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/anim_channels_defines.c92
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c58
-rw-r--r--source/blender/editors/animation/anim_deps.c2
-rw-r--r--source/blender/editors/animation/anim_draw.c106
-rw-r--r--source/blender/editors/animation/anim_filter.c54
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c46
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c10
-rw-r--r--source/blender/editors/animation/anim_ops.c29
-rw-r--r--source/blender/editors/animation/drivers.c19
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c56
-rw-r--r--source/blender/editors/animation/keyframes_draw.c31
-rw-r--r--source/blender/editors/animation/keyframes_edit.c4
-rw-r--r--source/blender/editors/animation/keyframes_general.c2
-rw-r--r--source/blender/editors/animation/keyframing.c29
-rw-r--r--source/blender/editors/animation/keyingsets.c4
-rw-r--r--source/blender/editors/animation/time_scrub_ui.c2
-rw-r--r--source/blender/editors/armature/armature_add.c571
-rw-r--r--source/blender/editors/armature/armature_edit.c222
-rw-r--r--source/blender/editors/armature/armature_intern.h52
-rw-r--r--source/blender/editors/armature/armature_naming.c66
-rw-r--r--source/blender/editors/armature/armature_ops.c3
-rw-r--r--source/blender/editors/armature/armature_relations.c24
-rw-r--r--source/blender/editors/armature/armature_select.c803
-rw-r--r--source/blender/editors/armature/armature_skinning.c4
-rw-r--r--source/blender/editors/armature/armature_utils.c35
-rw-r--r--source/blender/editors/armature/editarmature_undo.c3
-rw-r--r--source/blender/editors/armature/meshlaplacian.c6
-rw-r--r--source/blender/editors/armature/pose_edit.c13
-rw-r--r--source/blender/editors/armature/pose_group.c3
-rw-r--r--source/blender/editors/armature/pose_lib.c24
-rw-r--r--source/blender/editors/armature/pose_select.c84
-rw-r--r--source/blender/editors/armature/pose_slide.c182
-rw-r--r--source/blender/editors/armature/pose_transform.c23
-rw-r--r--source/blender/editors/armature/pose_utils.c2
-rw-r--r--source/blender/editors/curve/CMakeLists.txt1
-rw-r--r--source/blender/editors/curve/curve_intern.h19
-rw-r--r--source/blender/editors/curve/editcurve.c843
-rw-r--r--source/blender/editors/curve/editcurve_add.c4
-rw-r--r--source/blender/editors/curve/editcurve_paint.c20
-rw-r--r--source/blender/editors/curve/editcurve_query.c253
-rw-r--r--source/blender/editors/curve/editcurve_select.c18
-rw-r--r--source/blender/editors/curve/editcurve_undo.c18
-rw-r--r--source/blender/editors/curve/editfont.c2
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt3
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_draw_utils.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_geometry.h4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c15
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c38
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c57
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c52
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c52
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c21
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c560
-rw-r--r--source/blender/editors/gpencil/annotate_draw.c574
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c568
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c534
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c30
-rw-r--r--source/blender/editors/gpencil/gpencil_convert.c32
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c100
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c354
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c147
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h39
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c37
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c321
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c156
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c156
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c306
-rw-r--r--source/blender/editors/gpencil/gpencil_uv.c172
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_paint.c3
-rw-r--r--source/blender/editors/gpencil/gpencil_weight_paint.c3
-rw-r--r--source/blender/editors/include/ED_anim_api.h31
-rw-r--r--source/blender/editors/include/ED_armature.h14
-rw-r--r--source/blender/editors/include/ED_datafiles.h3
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h38
-rw-r--r--source/blender/editors/include/ED_gpencil.h46
-rw-r--r--source/blender/editors/include/ED_image.h14
-rw-r--r--source/blender/editors/include/ED_info.h6
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h8
-rw-r--r--source/blender/editors/include/ED_keyframing.h14
-rw-r--r--source/blender/editors/include/ED_mask.h19
-rw-r--r--source/blender/editors/include/ED_mesh.h29
-rw-r--r--source/blender/editors/include/ED_node.h15
-rw-r--r--source/blender/editors/include/ED_object.h47
-rw-r--r--source/blender/editors/include/ED_outliner.h4
-rw-r--r--source/blender/editors/include/ED_particle.h4
-rw-r--r--source/blender/editors/include/ED_render.h4
-rw-r--r--source/blender/editors/include/ED_screen.h65
-rw-r--r--source/blender/editors/include/ED_screen_types.h10
-rw-r--r--source/blender/editors/include/ED_sculpt.h5
-rw-r--r--source/blender/editors/include/ED_transform.h29
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h7
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/include/ED_util_imbuf.h52
-rw-r--r--source/blender/editors/include/ED_uvedit.h17
-rw-r--r--source/blender/editors/include/ED_view3d.h14
-rw-r--r--source/blender/editors/include/UI_icons.h2
-rw-r--r--source/blender/editors/include/UI_interface.h123
-rw-r--r--source/blender/editors/include/UI_resources.h8
-rw-r--r--source/blender/editors/include/UI_view2d.h25
-rw-r--r--source/blender/editors/interface/CMakeLists.txt3
-rw-r--r--source/blender/editors/interface/interface.c170
-rw-r--r--source/blender/editors/interface/interface_align.c10
-rw-r--r--source/blender/editors/interface/interface_anim.c58
-rw-r--r--source/blender/editors/interface/interface_context_menu.c10
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c65
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c31
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c21
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c5
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c3
-rw-r--r--source/blender/editors/interface/interface_handlers.c356
-rw-r--r--source/blender/editors/interface/interface_icons.c43
-rw-r--r--source/blender/editors/interface/interface_intern.h131
-rw-r--r--source/blender/editors/interface/interface_layout.c415
-rw-r--r--source/blender/editors/interface/interface_ops.c27
-rw-r--r--source/blender/editors/interface/interface_panel.c1148
-rw-r--r--source/blender/editors/interface/interface_query.c34
-rw-r--r--source/blender/editors/interface/interface_region_color_picker.c2
-rw-r--r--source/blender/editors/interface/interface_region_hud.c85
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c39
-rw-r--r--source/blender/editors/interface/interface_region_popover.c8
-rw-r--r--source/blender/editors/interface/interface_region_popup.c34
-rw-r--r--source/blender/editors/interface/interface_region_search.c152
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c20
-rw-r--r--source/blender/editors/interface/interface_regions.c10
-rw-r--r--source/blender/editors/interface/interface_regions_intern.h4
-rw-r--r--source/blender/editors/interface/interface_style.c12
-rw-r--r--source/blender/editors/interface/interface_template_search_menu.c1139
-rw-r--r--source/blender/editors/interface/interface_template_search_operator.c151
-rw-r--r--source/blender/editors/interface/interface_templates.c1314
-rw-r--r--source/blender/editors/interface/interface_undo.c139
-rw-r--r--source/blender/editors/interface/interface_utils.c80
-rw-r--r--source/blender/editors/interface/interface_widgets.c298
-rw-r--r--source/blender/editors/interface/resources.c2
-rw-r--r--source/blender/editors/interface/view2d.c115
-rw-r--r--source/blender/editors/interface/view2d_draw.c15
-rw-r--r--source/blender/editors/interface/view2d_ops.c26
-rw-r--r--source/blender/editors/io/io_alembic.c4
-rw-r--r--source/blender/editors/io/io_alembic.h2
-rw-r--r--source/blender/editors/io/io_cache.c2
-rw-r--r--source/blender/editors/io/io_cache.h2
-rw-r--r--source/blender/editors/io/io_usd.c2
-rw-r--r--source/blender/editors/io/io_usd.h2
-rw-r--r--source/blender/editors/mask/mask_add.c23
-rw-r--r--source/blender/editors/mask/mask_draw.c60
-rw-r--r--source/blender/editors/mask/mask_edit.c23
-rw-r--r--source/blender/editors/mask/mask_ops.c55
-rw-r--r--source/blender/editors/mask/mask_query.c110
-rw-r--r--source/blender/editors/mask/mask_relationships.c9
-rw-r--r--source/blender/editors/mask/mask_select.c81
-rw-r--r--source/blender/editors/mask/mask_shapekey.c16
-rw-r--r--source/blender/editors/mesh/editface.c12
-rw-r--r--source/blender/editors/mesh/editmesh_add.c113
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c10
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c68
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c3
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c12
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c10
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c10
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c26
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c6
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c6
-rw-r--r--source/blender/editors/mesh/editmesh_select.c26
-rw-r--r--source/blender/editors/mesh/editmesh_select_similar.c2
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c594
-rw-r--r--source/blender/editors/mesh/editmesh_undo.c10
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c64
-rw-r--r--source/blender/editors/mesh/mesh_intern.h2
-rw-r--r--source/blender/editors/mesh/mesh_mirror.c108
-rw-r--r--source/blender/editors/mesh/mesh_ops.c14
-rw-r--r--source/blender/editors/mesh/meshtools.c124
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/CMakeLists.txt2
-rw-r--r--source/blender/editors/object/object_add.c119
-rw-r--r--source/blender/editors/object/object_bake.c2
-rw-r--r--source/blender/editors/object/object_bake_api.c71
-rw-r--r--source/blender/editors/object/object_collection.c18
-rw-r--r--source/blender/editors/object/object_constraint.c37
-rw-r--r--source/blender/editors/object/object_data_transform.c4
-rw-r--r--source/blender/editors/object/object_edit.c321
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c16
-rw-r--r--source/blender/editors/object/object_hook.c8
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_modes.c94
-rw-r--r--source/blender/editors/object/object_modifier.c220
-rw-r--r--source/blender/editors/object/object_ops.c4
-rw-r--r--source/blender/editors/object/object_random.c4
-rw-r--r--source/blender/editors/object/object_relations.c45
-rw-r--r--source/blender/editors/object/object_remesh.c436
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_shader_fx.c8
-rw-r--r--source/blender/editors/object/object_shapekey.c4
-rw-r--r--source/blender/editors/object/object_transform.c69
-rw-r--r--source/blender/editors/object/object_utils.c5
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/object/object_volume.c18
-rw-r--r--source/blender/editors/physics/dynamicpaint_ops.c10
-rw-r--r--source/blender/editors/physics/particle_edit.c147
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c2
-rw-r--r--source/blender/editors/physics/particle_object.c6
-rw-r--r--source/blender/editors/physics/physics_fluid.c27
-rw-r--r--source/blender/editors/render/render_internal.c96
-rw-r--r--source/blender/editors/render/render_opengl.c38
-rw-r--r--source/blender/editors/render/render_preview.c56
-rw-r--r--source/blender/editors/render/render_shading.c17
-rw-r--r--source/blender/editors/render/render_update.c36
-rw-r--r--source/blender/editors/render/render_view.c122
-rw-r--r--source/blender/editors/scene/scene_edit.c4
-rw-r--r--source/blender/editors/screen/area.c609
-rw-r--r--source/blender/editors/screen/area_query.c14
-rw-r--r--source/blender/editors/screen/area_utils.c2
-rw-r--r--source/blender/editors/screen/glutil.c12
-rw-r--r--source/blender/editors/screen/screen_context.c72
-rw-r--r--source/blender/editors/screen/screen_draw.c178
-rw-r--r--source/blender/editors/screen/screen_edit.c658
-rw-r--r--source/blender/editors/screen/screen_geometry.c89
-rw-r--r--source/blender/editors/screen/screen_intern.h26
-rw-r--r--source/blender/editors/screen/screen_ops.c582
-rw-r--r--source/blender/editors/screen/screen_user_menu.c8
-rw-r--r--source/blender/editors/screen/screendump.c8
-rw-r--r--source/blender/editors/screen/workspace_edit.c21
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c12
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt9
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c84
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c234
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c109
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c95
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h5
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c28
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c36
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c37
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c110
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_ops.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c2
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c5166
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_automasking.c304
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_cloth.c375
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_detail.c428
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_dyntopo.c439
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_face_set.c980
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mask.c502
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_filter_mesh.c660
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h270
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_mask_expand.c526
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c16
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_pose.c587
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_smooth.c608
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_transform.c381
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c465
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c15
-rw-r--r--source/blender/editors/sound/sound_ops.c4
-rw-r--r--source/blender/editors/space_action/action_data.c54
-rw-r--r--source/blender/editors/space_action/action_draw.c23
-rw-r--r--source/blender/editors/space_action/action_edit.c10
-rw-r--r--source/blender/editors/space_action/action_select.c12
-rw-r--r--source/blender/editors/space_action/space_action.c96
-rw-r--r--source/blender/editors/space_api/spacetypes.c5
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c10
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c6
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c8
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c104
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_draw.c8
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_draw.c78
-rw-r--r--source/blender/editors/space_clip/clip_editor.c44
-rw-r--r--source/blender/editors/space_clip/clip_graph_draw.c49
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c2
-rw-r--r--source/blender/editors/space_clip/clip_intern.h2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c35
-rw-r--r--source/blender/editors/space_clip/clip_toolbar.c8
-rw-r--r--source/blender/editors/space_clip/clip_utils.c3
-rw-r--r--source/blender/editors/space_clip/space_clip.c242
-rw-r--r--source/blender/editors/space_clip/tracking_select.c25
-rw-r--r--source/blender/editors/space_console/console_draw.c15
-rw-r--r--source/blender/editors/space_console/console_ops.c8
-rw-r--r--source/blender/editors/space_console/space_console.c10
-rw-r--r--source/blender/editors/space_file/file_draw.c87
-rw-r--r--source/blender/editors/space_file/file_ops.c118
-rw-r--r--source/blender/editors/space_file/file_panels.c18
-rw-r--r--source/blender/editors/space_file/filelist.c179
-rw-r--r--source/blender/editors/space_file/filesel.c13
-rw-r--r--source/blender/editors/space_file/fsmenu.c7
-rw-r--r--source/blender/editors/space_file/space_file.c80
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c132
-rw-r--r--source/blender/editors/space_graph/graph_draw.c12
-rw-r--r--source/blender/editors/space_graph/graph_edit.c33
-rw-r--r--source/blender/editors/space_graph/graph_select.c8
-rw-r--r--source/blender/editors/space_graph/graph_utils.c50
-rw-r--r--source/blender/editors/space_graph/space_graph.c58
-rw-r--r--source/blender/editors/space_image/image_buttons.c6
-rw-r--r--source/blender/editors/space_image/image_draw.c11
-rw-r--r--source/blender/editors/space_image/image_edit.c11
-rw-r--r--source/blender/editors/space_image/image_ops.c425
-rw-r--r--source/blender/editors/space_image/image_sequence.c23
-rw-r--r--source/blender/editors/space_image/image_undo.c41
-rw-r--r--source/blender/editors/space_image/space_image.c97
-rw-r--r--source/blender/editors/space_info/info_draw.c1
-rw-r--r--source/blender/editors/space_info/info_report.c4
-rw-r--r--source/blender/editors/space_info/info_stats.c299
-rw-r--r--source/blender/editors/space_info/space_info.c10
-rw-r--r--source/blender/editors/space_info/textview.c38
-rw-r--r--source/blender/editors/space_info/textview.h2
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c69
-rw-r--r--source/blender/editors/space_nla/nla_channels.c7
-rw-r--r--source/blender/editors/space_nla/nla_draw.c14
-rw-r--r--source/blender/editors/space_nla/nla_edit.c36
-rw-r--r--source/blender/editors/space_nla/nla_select.c2
-rw-r--r--source/blender/editors/space_nla/space_nla.c41
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_node/drawnode.c954
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_buttons.c10
-rw-r--r--source/blender/editors/space_node/node_draw.c262
-rw-r--r--source/blender/editors/space_node/node_edit.c34
-rw-r--r--source/blender/editors/space_node/node_group.c19
-rw-r--r--source/blender/editors/space_node/node_intern.h16
-rw-r--r--source/blender/editors/space_node/node_relationships.c27
-rw-r--r--source/blender/editors/space_node/node_select.c89
-rw-r--r--source/blender/editors/space_node/node_templates.c118
-rw-r--r--source/blender/editors/space_node/node_view.c14
-rw-r--r--source/blender/editors/space_node/space_node.c112
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c77
-rw-r--r--source/blender/editors/space_outliner/outliner_dragdrop.c16
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c92
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c258
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h14
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c3
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c37
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c14
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c298
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c33
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c11
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c18
-rw-r--r--source/blender/editors/space_script/script_edit.c2
-rw-r--r--source/blender/editors/space_script/space_script.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c246
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c372
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c812
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h21
-rw-r--r--source/blender/editors/space_sequencer/sequencer_modifier.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_scopes.c159
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c167
-rw-r--r--source/blender/editors/space_sequencer/sequencer_view.c229
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c221
-rw-r--r--source/blender/editors/space_statusbar/space_statusbar.c6
-rw-r--r--source/blender/editors/space_text/space_text.c30
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c6
-rw-r--r--source/blender/editors/space_text/text_draw.c8
-rw-r--r--source/blender/editors/space_text/text_format.c2
-rw-r--r--source/blender/editors/space_text/text_header.c12
-rw-r--r--source/blender/editors/space_text/text_intern.h6
-rw-r--r--source/blender/editors/space_text/text_ops.c3
-rw-r--r--source/blender/editors/space_topbar/space_topbar.c8
-rw-r--r--source/blender/editors/space_userpref/space_userpref.c10
-rw-r--r--source/blender/editors/space_userpref/userpref_ops.c69
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c104
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c32
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c104
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c430
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c46
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h12
-rw-r--r--source/blender/editors/space_view3d/view3d_iterators.c21
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c5
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c1153
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c362
-rw-r--r--source/blender/editors/space_view3d/view3d_utils.c68
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c75
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c30
-rw-r--r--source/blender/editors/transform/transform.c503
-rw-r--r--source/blender/editors/transform/transform.h139
-rw-r--r--source/blender/editors/transform/transform_constraints.c287
-rw-r--r--source/blender/editors/transform/transform_constraints.h5
-rw-r--r--source/blender/editors/transform/transform_convert.c424
-rw-r--r--source/blender/editors/transform/transform_convert.h12
-rw-r--r--source/blender/editors/transform/transform_convert_action.c5
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c106
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c19
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c11
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c6
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c144
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c5
-rw-r--r--source/blender/editors/transform/transform_convert_node.c4
-rw-r--r--source/blender/editors/transform/transform_convert_object.c20
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c18
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c2
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c2
-rw-r--r--source/blender/editors/transform/transform_generics.c287
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c38
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c175
-rw-r--r--source/blender/editors/transform/transform_mode.c20
-rw-r--r--source/blender/editors/transform/transform_mode.h1
-rw-r--r--source/blender/editors/transform/transform_mode_align.c6
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c6
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c6
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c9
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c6
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c6
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c6
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c4
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c9
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c10
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c6
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c10
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c14
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c6
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c6
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c9
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c15
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c6
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c7
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c6
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c2
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c6
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c2
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c6
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c6
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c51
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c2
-rw-r--r--source/blender/editors/transform/transform_ops.c34
-rw-r--r--source/blender/editors/transform/transform_orientations.c258
-rw-r--r--source/blender/editors/transform/transform_snap.c131
-rw-r--r--source/blender/editors/transform/transform_snap_object.c401
-rw-r--r--source/blender/editors/undo/ed_undo.c53
-rw-r--r--source/blender/editors/undo/memfile_undo.c38
-rw-r--r--source/blender/editors/util/CMakeLists.txt3
-rw-r--r--source/blender/editors/util/ed_transverts.c2
-rw-r--r--source/blender/editors/util/ed_util.c17
-rw-r--r--source/blender/editors/util/ed_util_imbuf.c571
-rw-r--r--source/blender/editors/util/gizmo_utils.c4
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt1
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c25
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c72
-rw-r--r--source/blender/editors/uvedit/uvedit_intern.h31
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c3780
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c26
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.h4
-rw-r--r--source/blender/editors/uvedit/uvedit_select.c3371
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c47
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c10
468 files changed, 32388 insertions, 22802 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 67e899382bb..0947023e071 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -51,6 +51,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
@@ -58,6 +59,7 @@
#include "RNA_access.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -856,7 +858,7 @@ static void acf_group_color(bAnimContext *ac, bAnimListElem *ale, float r_color[
bool showGroupColors = acf_show_channel_colors(ac);
if (showGroupColors && agrp->customCol) {
- unsigned char cp[3];
+ uchar cp[3];
/* highlight only for active */
if (ale->flag & AGRP_ACTIVE) {
@@ -3032,6 +3034,83 @@ static bAnimChannelType ACF_DSVOLUME = {
acf_dsvolume_setting_ptr /* pointer for setting */
};
+/* Simulation Expander ----------------------------------------- */
+
+static int acf_dssimulation_icon(bAnimListElem *UNUSED(ale))
+{
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
+}
+
+static int acf_dssimulation_setting_flag(bAnimContext *UNUSED(ac),
+ eAnimChannel_Settings setting,
+ bool *neg)
+{
+ /* clear extra return data first */
+ *neg = false;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return SIM_DS_EXPAND;
+
+ case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */
+ return ADT_NLA_EVAL_OFF;
+
+ case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */
+ *neg = true;
+ return ADT_CURVES_NOT_VISIBLE;
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ return ADT_UI_SELECTED;
+
+ default: /* unsupported */
+ return 0;
+ }
+}
+
+static void *acf_dssimulation_setting_ptr(bAnimListElem *ale,
+ eAnimChannel_Settings setting,
+ short *type)
+{
+ Simulation *simulation = (Simulation *)ale->data;
+
+ /* clear extra return data first */
+ *type = 0;
+
+ switch (setting) {
+ case ACHANNEL_SETTING_EXPAND: /* expanded */
+ return GET_ACF_FLAG_PTR(simulation->flag, type);
+
+ case ACHANNEL_SETTING_SELECT: /* selected */
+ case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */
+ case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */
+ if (simulation->adt)
+ return GET_ACF_FLAG_PTR(simulation->adt->flag, type);
+ return NULL;
+
+ default: /* unsupported */
+ return NULL;
+ }
+}
+
+static bAnimChannelType ACF_DSSIMULATION = {
+ "Simulation Expander", /* type name */
+ ACHANNEL_ROLE_EXPANDER, /* role */
+
+ acf_generic_dataexpand_color, /* backdrop color */
+ acf_generic_dataexpand_backdrop, /* backdrop */
+ acf_generic_indention_1, /* indent level */
+ acf_generic_basic_offset, /* offset */
+
+ acf_generic_idblock_name, /* name */
+ acf_generic_idblock_name_prop, /* name prop */
+ acf_dssimulation_icon, /* icon */
+
+ acf_generic_dataexpand_setting_valid, /* has setting */
+ acf_dssimulation_setting_flag, /* flag for setting */
+ acf_dssimulation_setting_ptr /* pointer for setting */
+};
+
/* GPencil Expander ------------------------------------------- */
// TODO: just get this from RNA?
@@ -4048,6 +4127,7 @@ static void ANIM_init_channel_typeinfo_data(void)
animchannelTypeInfo[type++] = &ACF_DSHAIR; /* Hair Channel */
animchannelTypeInfo[type++] = &ACF_DSPOINTCLOUD; /* PointCloud Channel */
animchannelTypeInfo[type++] = &ACF_DSVOLUME; /* Volume Channel */
+ animchannelTypeInfo[type++] = &ACF_DSSIMULATION; /* Simulation Channel */
animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */
@@ -4395,7 +4475,7 @@ void ANIM_channel_draw(
if (acf->name && !achannel_is_being_renamed(ac, acf, channel_index)) {
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
- unsigned char col[4];
+ uchar col[4];
/* set text color */
/* XXX: if active, highlight differently? */
@@ -4818,7 +4898,7 @@ static void draw_setting_widget(bAnimContext *ac,
icon = ICON_HIDE_ON;
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- tooltip = TIP_("F-Curve is visible in Graph Editor for editing");
+ tooltip = TIP_("F-Curve visibility in Graph Editor");
}
else if (ale->type == ANIMTYPE_GPLAYER) {
tooltip = TIP_("Grease Pencil layer is visible in the viewport");
@@ -4835,7 +4915,7 @@ static void draw_setting_widget(bAnimContext *ac,
case ACHANNEL_SETTING_MOD_OFF: /* modifiers disabled */
icon = ICON_MODIFIER_OFF;
- tooltip = TIP_("F-Curve modifiers are disabled");
+ tooltip = TIP_("Enable F-Curve modifiers");
break;
case ACHANNEL_SETTING_EXPAND: /* expanded triangle */
@@ -4879,7 +4959,9 @@ static void draw_setting_widget(bAnimContext *ac,
"Temporarily disable NLA stack evaluation (i.e. only the active action is evaluated)");
}
else if (ale->type == ANIMTYPE_GPLAYER) {
- tooltip = TIP_("Lock current frame displayed by layer (i.e. disable animation playback)");
+ tooltip = TIP_(
+ "Shows all keyframes during animation playback and enabled all frames for editing "
+ "(uncheck to use only the current keyframe during animation playback and editing)");
}
else {
tooltip = TIP_("Do channels contribute to result (toggle channel muting)");
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index f47ed85f5bf..1ca3452e8d8 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -42,7 +42,7 @@
#include "RNA_define.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -138,7 +138,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
@@ -194,7 +195,8 @@ void ANIM_set_active_channel(bAnimContext *ac,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
ale->adt->flag |= ADT_UI_ACTIVE;
@@ -332,7 +334,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) {
sel = ACHANNEL_SETFLAG_CLEAR;
}
@@ -428,7 +431,8 @@ void ANIM_deselect_anim_channels(
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* need to verify that this data is valid for now */
if (ale->adt) {
ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
@@ -667,7 +671,7 @@ void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *f
}
/* free the F-Curve itself */
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* If the action has no F-Curves, unlink it from AnimData if it did not
@@ -695,15 +699,15 @@ bool ANIM_remove_empty_action_from_animdata(struct AnimData *adt)
/* poll callback for being in an Animation Editor channels list region */
static bool animedit_poll_channels_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
return 0;
}
@@ -713,21 +717,21 @@ static bool animedit_poll_channels_active(bContext *C)
/* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
static bool animedit_poll_channels_nla_tweakmode_off(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA) == 0) {
return 0;
}
/* NLA TweakMode test */
- if (sa->spacetype == SPACE_NLA) {
+ if (area->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) {
return 0;
}
@@ -1518,19 +1522,19 @@ static void ANIM_OT_channels_move(wmOperatorType *ot)
static bool animchannels_grouping_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceLink *sl;
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test - must be suitable modes only */
sl = CTX_wm_space_data(C);
- switch (sa->spacetype) {
+ switch (area->spacetype) {
/* supported... */
case SPACE_ACTION: {
SpaceAction *saction = (SpaceAction *)sl;
@@ -1802,7 +1806,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* remove from group and action, then free */
action_groups_remove_channel(adt->action, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
/* free the group itself */
@@ -1856,7 +1860,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
/* unlink and free the F-Curve */
BLI_remlink(&strip->fcurves, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
tag_update_animation_element(ale);
break;
}
@@ -2268,7 +2272,8 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
}
/* get animdata blocks */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
+ ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale = anim_data.first; ale; ale = ale->next) {
@@ -2353,16 +2358,16 @@ static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
static bool animchannels_enable_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
- if (ELEM(NULL, sa, CTX_wm_region(C))) {
+ if (ELEM(NULL, area, CTX_wm_region(C))) {
return 0;
}
/* animation editor test - Action/Dopesheet/etc. and Graph only */
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH) == 0) {
return 0;
}
@@ -2431,14 +2436,14 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
/* XXX: make this generic? */
static bool animchannels_find_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa == NULL) {
+ if (area == NULL) {
return 0;
}
/* animation editor with dopesheet */
- return ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
+ return ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA);
}
/* find_invoke() - Get initial channels */
@@ -2964,7 +2969,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
case ANIMTYPE_DSMCLIP:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 6f7770d97f1..4fb68b614ff 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -38,7 +38,7 @@
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index bcb9ddc5889..a2a1f7eb1d2 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -62,67 +62,6 @@
/* *************************************************** */
/* CURRENT FRAME DRAWING */
-/* Draw current frame number in a little green box beside the current frame indicator */
-void ANIM_draw_cfra_number(const bContext *C, View2D *v2d, short flag)
-{
- Scene *scene = CTX_data_scene(C);
- const float time = scene->r.cfra + scene->r.subframe;
- const float cfra = (float)(time * scene->r.framelen);
- const bool show_time = (flag & DRAWCFRA_UNIT_SECONDS) != 0;
-
- const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- unsigned char col[4];
- float color[4];
- float xscale, x, y;
- char numstr[32] = " t "; /* t is the character to start replacing from */
- float hlen;
- int slen;
-
- /* because the frame number text is subject to the same scaling as the contents of the view */
- UI_view2d_scale_get(v2d, &xscale, NULL);
- GPU_matrix_push();
- GPU_matrix_scale_2f(1.0f / xscale, 1.0f);
-
- /* get timecode string
- * - padding on str-buf passed so that it doesn't sit on the frame indicator
- */
- if (show_time) {
- BLI_timecode_string_from_time(
- &numstr[2], sizeof(numstr) - 2, 0, FRA2TIME(cfra), FPS, U.timecode_style);
- }
- else {
- BLI_timecode_string_from_time_seconds(&numstr[2], sizeof(numstr) - 2, 1, cfra);
- }
-
- slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
- hlen = slen * 0.5f;
-
- /* get starting coordinates for drawing */
- x = cfra * xscale;
- y = -0.1f * U.widget_unit;
-
- /* draw green box around/behind text */
- UI_GetThemeColor4fv(TH_CFRAME, color);
- color[3] = 3.0f;
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_aa(true,
- x - hlen - 0.1f * U.widget_unit,
- y + 3.0f,
- x + hlen + 0.1f * U.widget_unit,
- y - 3.0f + U.widget_unit,
- 0.1f * U.widget_unit,
- color);
-
- /* draw current frame number */
- UI_GetThemeColor4ubv(TH_TEXT_HI, col);
- UI_fontstyle_draw_simple(
- fstyle, x - hlen - 0.15f * U.widget_unit, y + 0.28f * U.widget_unit, numstr, col);
-
- /* restore view transform */
- GPU_matrix_pop();
-}
-
/* General call for drawing current frame indicator in animation editor */
void ANIM_draw_cfra(const bContext *C, View2D *v2d, short flag)
{
@@ -441,12 +380,45 @@ static float normalization_factor_get(Scene *scene, FCurve *fcu, short flag, flo
min_coord = min_ff(min_coord, prev_bezt->vec[1][1]);
}
else {
- float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
- for (int j = 0; j <= resol; j++) {
- float eval_time = prev_bezt->vec[1][0] + step_size * j;
- float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
- max_coord = max_ff(max_coord, eval_value);
- min_coord = min_ff(min_coord, eval_value);
+ if (!ELEM(prev_bezt->ipo, BEZT_IPO_BACK, BEZT_IPO_ELASTIC)) {
+ /* Calculate min/max using bezier forward differencing. */
+ float data[120];
+ float v1[2], v2[2], v3[2], v4[2];
+
+ v1[0] = prev_bezt->vec[1][0];
+ v1[1] = prev_bezt->vec[1][1];
+ v2[0] = prev_bezt->vec[2][0];
+ v2[1] = prev_bezt->vec[2][1];
+
+ v3[0] = bezt->vec[0][0];
+ v3[1] = bezt->vec[0][1];
+ v4[0] = bezt->vec[1][0];
+ v4[1] = bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ BKE_curve_forward_diff_bezier(
+ v1[0], v2[0], v3[0], v4[0], data, resol, sizeof(float) * 3);
+ BKE_curve_forward_diff_bezier(
+ v1[1], v2[1], v3[1], v4[1], data + 1, resol, sizeof(float) * 3);
+
+ for (int j = 0; j <= resol; ++j) {
+ const float *fp = &data[j * 3];
+ max_coord = max_ff(max_coord, fp[1]);
+ min_coord = min_ff(min_coord, fp[1]);
+ }
+ }
+ else {
+ /* Calculate min/max using full fcurve evaluation.
+ * [slower than bezier forward differencing but evaluates Back/Elastic interpolation
+ * as well].*/
+ float step_size = (bezt->vec[1][0] - prev_bezt->vec[1][0]) / resol;
+ for (int j = 0; j <= resol; j++) {
+ float eval_time = prev_bezt->vec[1][0] + step_size * j;
+ float eval_value = evaluate_fcurve_only_curve(fcu, eval_time);
+ max_coord = max_ff(max_coord, eval_value);
+ min_coord = min_ff(min_coord, eval_value);
+ }
}
}
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index a09db0380e6..bd83bdae31b 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -67,6 +67,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_speaker_types.h"
#include "DNA_userdef_types.h"
@@ -82,10 +83,11 @@
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_collection.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_layer.h"
@@ -399,7 +401,7 @@ bool ANIM_animdata_context_getdata(bAnimContext *ac)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
SpaceLink *sl = CTX_wm_space_data(C);
Scene *scene = CTX_data_scene(C);
@@ -418,10 +420,10 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
}
ac->view_layer = CTX_data_view_layer(C);
ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
- ac->sa = sa;
+ ac->area = area;
ac->region = region;
ac->sl = sl;
- ac->spacetype = (sa) ? sa->spacetype : 0;
+ ac->spacetype = (area) ? area->spacetype : 0;
ac->regiontype = (region) ? region->regiontype : 0;
/* initialise default y-scale factor */
@@ -826,6 +828,18 @@ static bAnimListElem *make_new_animlistelem(void *data,
ale->adt = BKE_animdata_from_id(data);
break;
}
+ case ANIMTYPE_DSSIMULATION: {
+ Simulation *simulation = (Simulation *)data;
+ AnimData *adt = simulation->adt;
+
+ ale->flag = FILTER_SIMULATION_OBJD(simulation);
+
+ ale->key_data = (adt) ? adt->action : NULL;
+ ale->datatype = ALE_ACT;
+
+ ale->adt = BKE_animdata_from_id(data);
+ break;
+ }
case ANIMTYPE_DSSKEY: {
Key *key = (Key *)data;
AnimData *adt = key->adt;
@@ -974,7 +988,7 @@ static bAnimListElem *make_new_animlistelem(void *data,
* then free the MEM_alloc'd string
*/
if (rna_path) {
- ale->key_data = (void *)list_find_fcurve(&act->curves, rna_path, 0);
+ ale->key_data = (void *)BKE_fcurve_find(&act->curves, rna_path, 0);
MEM_freeN(rna_path);
}
}
@@ -1840,15 +1854,18 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
bDopeSheet *ads = ac->ads;
size_t items = 0;
- Scene *scene = (Scene *)ads->source;
ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
Base *base;
- /* Active scene's GPencil block first - No parent item needed... */
- if (scene->gpd) {
- items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode);
+ /* Include all annotation datablocks. */
+ if (((ads->filterflag & ADS_FILTER_ONLYSEL) == 0) ||
+ (ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
+ LISTBASE_FOREACH (bGPdata *, gpd, &ac->bmain->gpencils) {
+ if (gpd->flag & GP_DATA_ANNOTATIONS) {
+ items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
+ }
+ }
}
-
/* Objects in the scene */
for (base = view_layer->object_bases.first; base; base = base->next) {
/* Only consider this object if it has got some GP data (saving on all the other tests) */
@@ -1877,13 +1894,12 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
}
}
- /* check selection and object type filters only for Object mode */
- if (ob->mode == OB_MODE_OBJECT) {
- if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
- /* only selected should be shown */
- continue;
- }
+ /* check selection and object type filters */
+ if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
+ /* only selected should be shown */
+ continue;
}
+
/* check if object belongs to the filtering group if option to filter
* objects by the grouped status is on
* - used to ease the process of doing multiple-character choreographies
@@ -2412,7 +2428,7 @@ static size_t animdata_filter_ds_modifiers(
afm.filter_mode = filter_mode;
/* 2) walk over dependencies */
- modifiers_foreachIDLink(ob, animfilter_modifier_idpoin_cb, &afm);
+ BKE_modifiers_foreach_ID_link(ob, animfilter_modifier_idpoin_cb, &afm);
/* 3) extract data from the context, merging it back into the standard list */
if (afm.items) {
@@ -3139,7 +3155,7 @@ static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads,
size_t num_bases = 0;
Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
sorted_bases[num_bases++] = base;
}
@@ -3233,7 +3249,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
*/
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
/* since we're still here, this object should be usable */
items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index f631d08f3e4..3613ca9eeda 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -203,7 +203,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
#define HSV_BANDWIDTH 0.3f
/* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */
-// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out)
+// void fcurve_rainbow(uint cur, uint tot, float *out)
void getcolor_fcurve_rainbow(int cur, int tot, float out[3])
{
float hsv[3], fac;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8b0e9b22ce8..46566feea91 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -74,12 +74,12 @@
/* ************* Marker API **************** */
/* helper function for getting the list of markers to work on */
-static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
+static ListBase *context_get_markers(Scene *scene, ScrArea *area)
{
/* local marker sets... */
- if (sa) {
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ if (area) {
+ if (area->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* local markers can only be shown when there's only a single active action to grab them from
* - flag only takes effect when there's an action, otherwise it can get too confusing?
@@ -108,7 +108,7 @@ ListBase *ED_context_get_markers(const bContext *C)
ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
{
if (ac) {
- return context_get_markers(ac->scene, ac->sa);
+ return context_get_markers(ac->scene, ac->area);
}
else {
return NULL;
@@ -234,35 +234,35 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *r_first, float *
*/
static bool ED_operator_markers_region_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return false;
}
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_ACTION: {
- SpaceAction *saction = sa->spacedata.first;
+ SpaceAction *saction = area->spacedata.first;
if (saction->flag & SACTION_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_GRAPH: {
- SpaceGraph *sipo = sa->spacedata.first;
+ SpaceGraph *sipo = area->spacedata.first;
if (sipo->mode != SIPO_MODE_DRIVERS && sipo->flag & SIPO_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_NLA: {
- SpaceNla *snla = sa->spacedata.first;
+ SpaceNla *snla = area->spacedata.first;
if (snla->flag & SNLA_SHOW_MARKERS) {
return true;
}
break;
}
case SPACE_SEQ: {
- SpaceSeq *seq = sa->spacedata.first;
+ SpaceSeq *seq = area->spacedata.first;
if (seq->flag & SEQ_SHOW_MARKERS) {
return true;
}
@@ -358,7 +358,7 @@ void ED_markers_deselect_all(ListBase *markers, int action)
action = ED_markers_get_first_selected(markers) ? SEL_DESELECT : SEL_SELECT;
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if (action == SEL_SELECT) {
marker->flag |= SELECT;
}
@@ -528,7 +528,7 @@ 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);
- unsigned char shade[4];
+ uchar shade[4];
UI_GetThemeColor4ubv(TH_TIME_SCRUB_BACKGROUND, shade);
immUniformColor4ubv(shade);
@@ -599,14 +599,14 @@ 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 */
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ 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);
}
}
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ 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);
@@ -906,7 +906,7 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve
static void ed_marker_move_apply(bContext *C, wmOperator *op)
{
#ifdef DURIAN_CAMERA_SWITCH
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Object *camera = scene->camera;
#endif
@@ -930,7 +930,7 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op)
BKE_scene_camera_switch_update(scene);
if (camera != scene->camera) {
- BKE_screen_view3d_scene_sync(sc, scene);
+ BKE_screen_view3d_scene_sync(screen, scene);
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
}
#endif
@@ -1156,7 +1156,7 @@ static void MARKER_OT_duplicate(wmOperatorType *ot)
static void deselect_markers(ListBase *markers)
{
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
marker->flag &= ~SELECT;
}
}
@@ -1373,7 +1373,7 @@ static int ed_marker_box_select_exec(bContext *C, wmOperator *op)
ED_markers_deselect_all(markers, SEL_DESELECT);
}
- for (TimeMarker *marker = markers->first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, markers) {
if (BLI_rctf_isect_x(&rect, marker->frame)) {
SET_FLAG_FROM_TEST(marker->flag, select, SELECT);
}
@@ -1621,7 +1621,7 @@ static void MARKER_OT_make_links_scene(wmOperatorType *ot)
static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ListBase *markers = ED_context_get_markers(C);
@@ -1646,7 +1646,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
BLI_addtail(markers, marker);
/* deselect all others, so that the user can then move it without problems */
- for (TimeMarker *m = markers->first; m; m = m->next) {
+ LISTBASE_FOREACH (TimeMarker *, m, markers) {
if (m != marker) {
m->flag &= ~SELECT;
}
@@ -1658,7 +1658,7 @@ static int ed_marker_camera_bind_exec(bContext *C, wmOperator *op)
/* camera may have changes */
BKE_scene_camera_switch_update(scene);
- BKE_screen_view3d_scene_sync(sc, scene);
+ BKE_screen_view3d_scene_sync(screen, scene);
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index 7e36799ff1b..4c10c66dfa6 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -31,7 +31,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -228,7 +228,7 @@ static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int
{
*r_sfra = INT_MAX;
*r_efra = INT_MIN;
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
*r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
*r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
}
@@ -348,7 +348,7 @@ static void motionpath_calculate_update_range(MPathTarget *mpt,
static void motionpath_free_free_tree_data(ListBase *targets)
{
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
BLI_dlrbTree_free(&mpt->keys);
}
}
@@ -412,7 +412,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
DEG_make_inactive(depsgraph);
}
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
mpt->ob_eval = DEG_get_evaluated_object(depsgraph, mpt->ob);
AnimData *adt = BKE_animdata_from_id(&mpt->ob_eval->id);
@@ -492,7 +492,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
}
/* clear recalc flags from targets */
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ LISTBASE_FOREACH (MPathTarget *, mpt, targets) {
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 6b0d11802f4..40cd368e02b 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -49,6 +49,7 @@
#include "ED_anim_api.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
+#include "ED_time_scrub_ui.h"
#include "ED_util.h"
#include "DEG_depsgraph.h"
@@ -61,7 +62,7 @@
/* Check if the operator can be run from the current context */
static bool change_frame_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* XXX temp? prevent changes during render */
if (G.is_rendering) {
@@ -71,16 +72,10 @@ static bool change_frame_poll(bContext *C)
/* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH)) {
return true;
}
- else if (sa->spacetype == SPACE_GRAPH) {
- /* NOTE: Graph Editor has special version which does some extra stuff.
- * No need to show the generic error message for that case though!
- */
- return false;
- }
}
CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active");
@@ -151,11 +146,13 @@ static float frame_from_event(bContext *C, const wmEvent *event)
static void change_frame_seq_preview_begin(bContext *C, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bScreen *screen = CTX_wm_screen(C);
- if (sa && sa->spacetype == SPACE_SEQ) {
- SpaceSeq *sseq = sa->spacedata.first;
- if (ED_space_sequencer_check_show_strip(sseq)) {
+ if (area && area->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = area->spacedata.first;
+ ARegion *region = CTX_wm_region(C);
+ if (ED_space_sequencer_check_show_strip(sseq) &&
+ !ED_time_scrub_event_in_region(region, event)) {
ED_sequencer_special_preview_set(C, event->mval);
}
}
@@ -282,7 +279,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot)
static bool anim_set_end_frames_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* XXX temp? prevent changes during render */
if (G.is_rendering) {
@@ -292,8 +289,8 @@ static bool anim_set_end_frames_poll(bContext *C)
/* although it's only included in keymaps for regions using ED_KEYMAP_ANIMATION,
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_ACTION, SPACE_GRAPH, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
}
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index ee0f403a155..328e435877c 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -36,9 +36,11 @@
#include "DNA_space_types.h"
#include "DNA_texture_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -90,7 +92,7 @@ FCurve *verify_driver_fcurve(ID *id,
* - add if not found and allowed to add one
* TODO: add auto-grouping support? how this works will need to be resolved
*/
- fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
+ fcu = BKE_fcurve_find(&adt->drivers, rna_path, array_index);
if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
@@ -108,7 +110,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[],
const int array_index,
eDriverFCurveCreationMode creation_mode)
{
- FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ FCurve *fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
fcu->auto_smoothing = U.auto_smoothing_new;
@@ -568,13 +570,13 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
/* step through all drivers, removing all of those with the same base path */
FCurve *fcu_iter = adt->drivers.first;
- while ((fcu = iter_step_fcurve(fcu_iter, rna_path)) != NULL) {
+ while ((fcu = BKE_fcurve_iter_step(fcu_iter, rna_path)) != NULL) {
/* store the next fcurve for looping */
fcu_iter = fcu->next;
/* remove F-Curve from driver stack, then free it */
BLI_remlink(&adt->drivers, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
/* done successfully */
success = true;
@@ -588,7 +590,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
success = true;
}
@@ -609,7 +611,7 @@ void ANIM_drivers_copybuf_free(void)
{
/* free the buffer F-Curve if it exists, as if it were just another F-Curve */
if (channeldriver_copypaste_buf) {
- free_fcurve(channeldriver_copypaste_buf);
+ BKE_fcurve_free(channeldriver_copypaste_buf);
}
channeldriver_copypaste_buf = NULL;
}
@@ -660,7 +662,7 @@ bool ANIM_copy_driver(
fcu->rna_path = NULL;
/* make a copy of the F-Curve with */
- channeldriver_copypaste_buf = copy_fcurve(fcu);
+ channeldriver_copypaste_buf = BKE_fcurve_copy(fcu);
/* restore the path */
fcu->rna_path = tmp_path;
@@ -979,7 +981,8 @@ static bool add_driver_button_poll(bContext *C)
}
/* Don't do anything if there is an fcurve for animation without a driver. */
- FCurve *fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ FCurve *fcu = BKE_fcurve_find_by_rna_context_ui(
+ C, &ptr, prop, index, NULL, NULL, &driven, &special);
return (fcu == NULL || fcu->driver);
}
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 9bdfd9cfe33..eadaa449b92 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -42,7 +42,6 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
@@ -178,7 +177,7 @@ static void draw_modifier__generator(uiLayout *layout,
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float *cp = NULL;
char xval[32];
- unsigned int i;
+ uint i;
int maxXWidth;
/* draw polynomial order selector */
@@ -317,7 +316,7 @@ static void draw_modifier__generator(uiLayout *layout,
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
{
float *cp = NULL;
- unsigned int i;
+ uint i;
/* draw polynomial order selector */
row = uiLayoutRow(layout, false);
@@ -718,28 +717,31 @@ static void draw_modifier__envelope(uiLayout *layout,
/* control points list */
for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
+ PointerRNA ctrl_ptr;
+ RNA_pointer_create(fcurve_owner_id, &RNA_FModifierEnvelopeControlPoint, fed, &ctrl_ptr);
+
/* get a new row to operate on */
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
UI_block_align_begin(block);
- but = uiDefButF(block,
- UI_BTYPE_NUM,
- B_FMODIFIER_REDRAW,
- IFACE_("Fra:"),
- 0,
- 0,
- 4.5 * UI_UNIT_X,
- UI_UNIT_Y,
- &fed->time,
- -MAXFRAMEF,
- MAXFRAMEF,
- 10,
- 1,
- TIP_("Frame that envelope point occurs"));
- UI_but_func_set(but, validate_fmodifier_cb, fcm, NULL);
-
- uiDefButF(block,
+ uiDefButR(block,
+ UI_BTYPE_NUM,
+ B_FMODIFIER_REDRAW,
+ IFACE_("Fra:"),
+ 0,
+ 0,
+ 4.5 * UI_UNIT_X,
+ UI_UNIT_Y,
+ &ctrl_ptr,
+ "frame",
+ -1,
+ -MAXFRAMEF,
+ MAXFRAMEF,
+ 10,
+ 1,
+ NULL);
+ uiDefButR(block,
UI_BTYPE_NUM,
B_FMODIFIER_REDRAW,
IFACE_("Min:"),
@@ -747,13 +749,15 @@ static void draw_modifier__envelope(uiLayout *layout,
0,
5 * UI_UNIT_X,
UI_UNIT_Y,
- &fed->min,
+ &ctrl_ptr,
+ "min",
+ -1,
-UI_FLT_MAX,
UI_FLT_MAX,
10,
2,
- TIP_("Minimum bound of envelope at this point"));
- uiDefButF(block,
+ NULL);
+ uiDefButR(block,
UI_BTYPE_NUM,
B_FMODIFIER_REDRAW,
IFACE_("Max:"),
@@ -761,12 +765,14 @@ static void draw_modifier__envelope(uiLayout *layout,
0,
5 * UI_UNIT_X,
UI_UNIT_Y,
- &fed->max,
+ &ctrl_ptr,
+ "max",
+ -1,
-UI_FLT_MAX,
UI_FLT_MAX,
10,
2,
- TIP_("Maximum bound of envelope at this point"));
+ NULL);
but = uiDefIconBut(block,
UI_BTYPE_BUT,
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 4b3b730d0fe..b921ba039be 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -31,6 +31,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_dlrbTree.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -505,14 +506,14 @@ static void update_keyblocks(DLRBT_Tree *keys, BezTriple *bezt, int bezt_len)
/* Find the curve count */
int max_curve = 0;
- for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
max_curve = MAX2(max_curve, col->totcurve);
}
/* Propagate blocks to inserted keys */
ActKeyColumn *prev_ready = NULL;
- for (ActKeyColumn *col = keys->first; col; col = col->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, keys) {
/* Pre-existing column. */
if (col->totcurve > 0) {
prev_ready = col;
@@ -558,11 +559,11 @@ void draw_keyframe_shape(float x,
short key_type,
short mode,
float alpha,
- unsigned int pos_id,
- unsigned int size_id,
- unsigned int color_id,
- unsigned int outline_color_id,
- unsigned int flags_id,
+ uint pos_id,
+ uint size_id,
+ uint color_id,
+ uint outline_color_id,
+ uint flags_id,
short handle_type,
short extreme_type)
{
@@ -595,9 +596,9 @@ void draw_keyframe_shape(float x,
size -= 0.8f * key_type;
}
- unsigned char fill_col[4];
- unsigned char outline_col[4];
- unsigned int flags = 0;
+ uchar fill_col[4];
+ uchar outline_col[4];
+ uint flags = 0;
/* draw! */
if (draw_fill) {
@@ -730,7 +731,7 @@ static void draw_keylist(View2D *v2d,
ipo_color_mix[3] *= 0.5f;
uint block_len = 0;
- for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
if (actkeyblock_get_valid_hold(ab)) {
block_len++;
}
@@ -746,7 +747,7 @@ static void draw_keylist(View2D *v2d,
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
immBegin(GPU_PRIM_TRIS, 6 * block_len);
- for (ActKeyColumn *ab = keys->first; ab; ab = ab->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ab, keys) {
int valid_hold = actkeyblock_get_valid_hold(ab);
if (valid_hold != 0) {
if ((valid_hold & ACTKEYBLOCK_FLAG_STATIC_HOLD) == 0) {
@@ -791,7 +792,7 @@ static void draw_keylist(View2D *v2d,
if (keys) {
/* count keys */
uint key_len = 0;
- for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
/* Optimization: if keyframe doesn't appear within 5 units (screenspace)
* in visible area, don't draw.
* This might give some improvements,
@@ -822,7 +823,7 @@ static void draw_keylist(View2D *v2d,
short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
- for (ActKeyColumn *ak = keys->first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
if (IN_RANGE_INCL(ak->cfra, v2d->cur.xmin, v2d->cur.xmax)) {
if (show_ipo) {
handle_type = ak->handle_type;
@@ -1153,7 +1154,7 @@ void cachefile_to_keylist(bDopeSheet *ads,
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* loop through each F-Curve, grabbing the keyframes */
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
fcurve_to_keylist(ale->adt, ale->data, keys, saction_flag);
}
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 61488e7f63a..2dae4e8b4c5 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -79,7 +79,7 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked,
{
BezTriple *bezt;
short ok = 0;
- unsigned int i;
+ uint i;
/* sanity check */
if (ELEM(NULL, fcu, fcu->bezt)) {
@@ -633,7 +633,7 @@ bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const
BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy);
if (BLI_lasso_is_point_inside(
- data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) {
+ data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) {
return true;
}
}
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index c526c185383..fc9ec870496 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -1189,7 +1189,7 @@ short paste_animedit_keys(bAnimContext *ac,
* one F-Curve has been pasted into.
*/
for (pass = 0; pass < 3; pass++) {
- unsigned int totmatch = 0;
+ uint totmatch = 0;
for (ale = anim_data->first; ale; ale = ale->next) {
/* Find buffer item to paste from:
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index e66ebb1928c..2aa8d468e2d 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -45,10 +45,12 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@@ -182,7 +184,7 @@ FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], const
if (ELEM(NULL, act, rna_path)) {
return NULL;
}
- return list_find_fcurve(&act->curves, rna_path, array_index);
+ return BKE_fcurve_find(&act->curves, rna_path, array_index);
}
/**
@@ -208,11 +210,11 @@ FCurve *ED_action_fcurve_ensure(struct Main *bmain,
* - add if not found and allowed to add one
* TODO: add auto-grouping support? how this works will need to be resolved
*/
- fcu = list_find_fcurve(&act->curves, rna_path, array_index);
+ fcu = BKE_fcurve_find(&act->curves, rna_path, array_index);
if (fcu == NULL) {
/* use default settings to make a F-Curve */
- fcu = MEM_callocN(sizeof(FCurve), "FCurve");
+ fcu = BKE_fcurve_create();
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
fcu->auto_smoothing = U.auto_smoothing_new;
@@ -494,7 +496,7 @@ int insert_vert_fcurve(
FCurve *fcu, float x, float y, eBezTriple_KeyframeType keyframe_type, eInsertKeyFlags flag)
{
BezTriple beztr = {{{0}}};
- unsigned int oldTot = fcu->totvert;
+ uint oldTot = fcu->totvert;
int a;
/* set all three points, for nicer start position
@@ -1118,7 +1120,7 @@ static bool insert_keyframe_value(ReportList *reports,
eInsertKeyFlags flag)
{
/* F-Curve not editable? */
- if (fcurve_is_keyframable(fcu) == 0) {
+ if (BKE_fcurve_is_keyframable(fcu) == 0) {
BKE_reportf(
reports,
RPT_ERROR,
@@ -1793,11 +1795,11 @@ enum {
*/
static bool modify_key_op_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
/* if no area or active scene */
- if (ELEM(NULL, sa, scene)) {
+ if (ELEM(NULL, area, scene)) {
return false;
}
@@ -1825,7 +1827,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
* updated since the last switching to the edit mode will be keyframed correctly
*/
if (obedit && ANIM_keyingset_find_id(ks, (ID *)obedit->data)) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_OBJECT);
ob_edit_mode = true;
}
@@ -1841,7 +1843,7 @@ static int insert_key_exec(bContext *C, wmOperator *op)
/* restore the edit mode if necessary */
if (ob_edit_mode) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_EDIT);
}
/* report failure or do updates? */
@@ -2398,7 +2400,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
* not have any effect.
*/
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), index);
if (fcu) {
changed = insert_keyframe_direct(
@@ -2415,7 +2417,7 @@ static int insert_key_button_exec(bContext *C, wmOperator *op)
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu && driven) {
changed = insert_keyframe_direct(
@@ -2558,7 +2560,7 @@ static int delete_key_button_exec(bContext *C, wmOperator *op)
*/
ID *id = ptr.owner_id;
NlaStrip *strip = ptr.data;
- FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, RNA_property_identifier(prop), 0);
if (fcu) {
if (BKE_fcurve_is_protected(fcu)) {
@@ -2999,7 +3001,8 @@ bool ED_autokeyframe_property(
bool special;
bool changed = false;
- fcu = rna_get_fcurve_context_ui(C, ptr, prop, rnaindex, NULL, &action, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(
+ C, ptr, prop, rnaindex, NULL, &action, &driven, &special);
if (fcu == NULL) {
return changed;
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index d30d03a1c73..89c7860982b 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -646,8 +646,8 @@ void ANIM_keyingset_infos_exit(void)
next = ksi->next;
/* free extra RNA data, and remove from list */
- if (ksi->ext.free) {
- ksi->ext.free(ksi->ext.data);
+ if (ksi->rna_ext.free) {
+ ksi->rna_ext.free(ksi->rna_ext.data);
}
BLI_freelinkN(&keyingset_type_infos, ksi);
}
diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c
index 25b8e78de92..7679995d9a4 100644
--- a/source/blender/editors/animation/time_scrub_ui.c
+++ b/source/blender/editors/animation/time_scrub_ui.c
@@ -95,7 +95,7 @@ static void draw_current_frame(const Scene *scene,
int current_frame)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- const unsigned char color[] = {255, 255, 255, 255};
+ const uchar color[] = {255, 255, 255, 255};
int frame_x = UI_view2d_view_to_region_x(v2d, current_frame);
char frame_str[64];
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index e87040279af..895b4953992 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -22,6 +22,7 @@
* \ingroup edarmature
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
@@ -38,8 +39,12 @@
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_deform.h"
+#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
+#include "BKE_lib_id.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -48,6 +53,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -217,6 +223,7 @@ static int armature_click_extrude_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -341,7 +348,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
GHash *name_map = BLI_ghash_str_new(__func__);
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (!ebone_dst) {
ebone_dst = ED_armature_ebone_get_mirrored(editbones, ebone_src);
@@ -351,7 +358,7 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
}
}
- for (EditBone *ebone_src = editbones->first; ebone_src; ebone_src = ebone_src->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_src, editbones) {
EditBone *ebone_dst = ebone_src->temp.ebone;
if (ebone_dst) {
bPoseChannel *pchan_src = BKE_pose_channel_find_name(ob->pose, ebone_src->name);
@@ -375,25 +382,20 @@ void postEditBoneDuplicate(struct ListBase *editbones, Object *ob)
BLI_ghash_free(name_map, NULL, NULL);
}
-/*
- * Note: When duplicating cross objects, editbones here is the list of bones
- * from the SOURCE object but ob is the DESTINATION object
- * */
-void updateDuplicateSubtargetObjects(EditBone *dupBone,
+static void updateDuplicateSubtarget(EditBone *dup_bone,
ListBase *editbones,
- Object *src_ob,
- Object *dst_ob)
+ Object *ob,
+ bool lookup_mirror_subtarget)
{
- /* If an edit bone has been duplicated, lets
- * update it's constraints if the subtarget
- * they point to has also been duplicated
+ /* If an edit bone has been duplicated, lets update it's constraints if the
+ * subtarget they point to has also been duplicated.
*/
EditBone *oldtarget, *newtarget;
bPoseChannel *pchan;
bConstraint *curcon;
ListBase *conlist;
- if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
+ if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name))) {
if ((conlist = &pchan->constraints)) {
for (curcon = conlist->first; curcon; curcon = curcon->next) {
/* does this constraint have a subtarget in
@@ -407,8 +409,7 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
cti->get_constraint_targets(curcon, &targets);
for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == src_ob) && (ct->subtarget[0])) {
- ct->tar = dst_ob; /* update target */
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
if (oldtarget) {
/* was the subtarget bone duplicated too? If
@@ -419,6 +420,17 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
newtarget = oldtarget->temp.ebone;
BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
}
+ else if (lookup_mirror_subtarget) {
+ /* The subtarget was not selected for duplication, try to see if a mirror bone of
+ * the current target exists */
+ char name_flip[MAXBONENAME];
+
+ BLI_string_flip_side_name(name_flip, oldtarget->name, false, sizeof(name_flip));
+ newtarget = get_named_editbone(editbones, name_flip);
+ if (newtarget) {
+ BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
+ }
+ }
}
}
}
@@ -432,32 +444,434 @@ void updateDuplicateSubtargetObjects(EditBone *dupBone,
}
}
-void updateDuplicateSubtarget(EditBone *dupBone, ListBase *editbones, Object *ob)
+static void updateDuplicateActionConstraintSettings(EditBone *dup_bone,
+ EditBone *orig_bone,
+ Object *ob,
+ bConstraint *curcon)
{
- updateDuplicateSubtargetObjects(dupBone, editbones, ob, ob);
+ bActionConstraint *act_con = (bActionConstraint *)curcon->data;
+ bAction *act = (bAction *)act_con->act;
+
+ float mat[4][4];
+
+ unit_m4(mat);
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, act_con->subtarget);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ float max_axis_val = 0;
+ int max_axis = 0;
+ /* Which axis represents X now. IE, which axis defines the mirror plane. */
+ for (int i = 0; i < 3; i++) {
+ float cur_val = fabsf(mat[0][i]);
+ if (cur_val > max_axis_val) {
+ max_axis = i;
+ max_axis_val = cur_val;
+ }
+ }
+
+ /* data->type is mapped as follows for backwards compatibility:
+ * 00,01,02 - rotation (it used to be like this)
+ * 10,11,12 - scaling
+ * 20,21,22 - location
+ */
+ /* Mirror the target range */
+ if (act_con->type < 10 && act_con->type != max_axis) {
+ /* Y or Z rotation */
+ act_con->min = -act_con->min;
+ act_con->max = -act_con->max;
+ }
+ else if (act_con->type == max_axis + 10) {
+ /* X scaling */
+ }
+ else if (act_con->type == max_axis + 20) {
+ /* X location */
+ float imat[4][4];
+
+ invert_m4_m4(imat, mat);
+
+ float min_vec[3], max_vec[3];
+
+ zero_v3(min_vec);
+ zero_v3(max_vec);
+
+ min_vec[0] = act_con->min;
+ max_vec[0] = act_con->max;
+
+ /* convert values into local object space */
+ mul_m4_v3(mat, min_vec);
+ mul_m4_v3(mat, max_vec);
+
+ min_vec[0] *= -1;
+ max_vec[0] *= -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ act_con->min = min_vec[0];
+ act_con->max = max_vec[0];
+ }
+
+ /* See if there is any channels that uses this bone */
+ ListBase ani_curves;
+ BLI_listbase_clear(&ani_curves);
+ if (BKE_fcurves_filter(&ani_curves, &act->curves, "pose.bones[", orig_bone->name)) {
+ /* Create a copy and mirror the animation */
+ for (LinkData *ld = ani_curves.first; ld; ld = ld->next) {
+ FCurve *old_curve = ld->data;
+ FCurve *new_curve = BKE_fcurve_copy(old_curve);
+ bActionGroup *agrp;
+
+ char *old_path = new_curve->rna_path;
+
+ new_curve->rna_path = BLI_str_replaceN(old_path, orig_bone->name, dup_bone->name);
+ MEM_freeN(old_path);
+
+ /* Flip the animation */
+ int i;
+ BezTriple *bezt;
+ for (i = 0, bezt = new_curve->bezt; i < new_curve->totvert; i++, bezt++) {
+ const size_t slength = strlen(new_curve->rna_path);
+ bool flip = false;
+ if (BLI_strn_endswith(new_curve->rna_path, "location", slength) &&
+ new_curve->array_index == 0) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_quaternion", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_euler", slength) &&
+ ELEM(new_curve->array_index, 1, 2)) {
+ flip = true;
+ }
+ else if (BLI_strn_endswith(new_curve->rna_path, "rotation_axis_angle", slength) &&
+ ELEM(new_curve->array_index, 2, 3)) {
+ flip = true;
+ }
+
+ if (flip) {
+ bezt->vec[0][1] *= -1;
+ bezt->vec[1][1] *= -1;
+ bezt->vec[2][1] *= -1;
+ }
+ }
+
+ /* Make sure that a action group name for the new bone exists */
+ agrp = BKE_action_group_find_name(act, dup_bone->name);
+
+ if (agrp == NULL) {
+ agrp = action_groups_add_new(act, dup_bone->name);
+ }
+ BLI_assert(agrp != NULL);
+ action_groups_add_channel(act, agrp, new_curve);
+ }
+ }
+ BLI_freelistN(&ani_curves);
+
+ /* Make deps graph aware of our changes */
+ DEG_id_tag_update(&act->id, ID_RECALC_ANIMATION_NO_FLUSH);
}
-EditBone *duplicateEditBoneObjects(
- EditBone *curBone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+static void updateDuplicateKinematicConstraintSettings(bConstraint *curcon)
{
- EditBone *eBone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+ /* IK constraint */
+ bKinematicConstraint *ik = (bKinematicConstraint *)curcon->data;
+ ik->poleangle = -M_PI - ik->poleangle;
+ /* Wrap the angle to the +/-180.0f range (default soft limit of the input boxes). */
+ ik->poleangle = angle_wrap_rad(ik->poleangle);
+}
- /* Copy data from old bone to new bone */
- memcpy(eBone, curBone, sizeof(EditBone));
+static void updateDuplicateLocRotConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ /* This code assumes that bRotLimitConstraint and bLocLimitConstraint have the same fields in
+ * the same memory locations. */
+ BLI_assert(sizeof(bLocLimitConstraint) == sizeof(bRotLimitConstraint));
- curBone->temp.ebone = eBone;
- eBone->temp.ebone = curBone;
+ bRotLimitConstraint *limit = (bRotLimitConstraint *)curcon->data;
+ float local_mat[4][4], imat[4][4];
- if (name != NULL) {
- BLI_strncpy(eBone->name, name, sizeof(eBone->name));
+ float min_vec[3], max_vec[3];
+
+ min_vec[0] = limit->xmin;
+ min_vec[1] = limit->ymin;
+ min_vec[2] = limit->zmin;
+
+ max_vec[0] = limit->xmax;
+ max_vec[1] = limit->ymax;
+ max_vec[2] = limit->zmax;
+
+ unit_m4(local_mat);
+
+ BKE_constraint_mat_convertspace(
+ ob, pchan, local_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ /* Zero out any location translation */
+ local_mat[3][0] = local_mat[3][1] = local_mat[3][2] = 0;
+ }
+
+ invert_m4_m4(imat, local_mat);
+ /* convert values into local object space */
+ mul_m4_v3(local_mat, min_vec);
+ mul_m4_v3(local_mat, max_vec);
+
+ if (curcon->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ float min_copy[3];
+
+ copy_v3_v3(min_copy, min_vec);
+
+ min_vec[1] = max_vec[1] * -1;
+ min_vec[2] = max_vec[2] * -1;
+
+ max_vec[1] = min_copy[1] * -1;
+ max_vec[2] = min_copy[2] * -1;
+ }
+ else {
+ float min_x_copy = min_vec[0];
+
+ min_vec[0] = max_vec[0] * -1;
+ max_vec[0] = min_x_copy * -1;
+ }
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, min_vec);
+ mul_m4_v3(imat, max_vec);
+
+ limit->xmin = min_vec[0];
+ limit->ymin = min_vec[1];
+ limit->zmin = min_vec[2];
+
+ limit->xmax = max_vec[0];
+ limit->ymax = max_vec[1];
+ limit->zmax = max_vec[2];
+}
+
+static void updateDuplicateTransformConstraintSettings(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *curcon)
+{
+ bTransformConstraint *trans = (bTransformConstraint *)curcon->data;
+
+ float target_mat[4][4], own_mat[4][4], imat[4][4];
+
+ unit_m4(own_mat);
+ BKE_constraint_mat_convertspace(
+ ob, pchan, own_mat, curcon->ownspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ /* ###Source map mirroring### */
+ float old_min, old_max;
+
+ /* Source location */
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min);
+ mul_m4_v3(own_mat, trans->from_max);
+
+ old_min = trans->from_min[0];
+ old_max = trans->from_max[0];
+
+ trans->from_min[0] = -old_max;
+ trans->from_max[0] = -old_min;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min);
+ mul_m4_v3(imat, trans->from_max);
+
+ /* Source rotation */
+
+ /* Zero out any location translation */
+ own_mat[3][0] = own_mat[3][1] = own_mat[3][2] = 0;
+
+ invert_m4_m4(imat, own_mat);
+
+ /* convert values into local object space */
+ mul_m4_v3(own_mat, trans->from_min_rot);
+ mul_m4_v3(own_mat, trans->from_max_rot);
+
+ old_min = trans->from_min_rot[1];
+ old_max = trans->from_max_rot[1];
+
+ trans->from_min_rot[1] = old_max * -1;
+ trans->from_max_rot[1] = old_min * -1;
+
+ old_min = trans->from_min_rot[2];
+ old_max = trans->from_max_rot[2];
+
+ trans->from_min_rot[2] = old_max * -1;
+ trans->from_max_rot[2] = old_min * -1;
+
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->from_min_rot);
+ mul_m4_v3(imat, trans->from_max_rot);
+
+ /* Source scale does not require any mirroring */
+
+ /* ###Destination map mirroring### */
+ float temp_vec[3];
+ float imat_rot[4][4];
+
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, trans->subtarget);
+ unit_m4(target_mat);
+ BKE_constraint_mat_convertspace(
+ ob, target_pchan, target_mat, curcon->tarspace, CONSTRAINT_SPACE_LOCAL, false);
+
+ invert_m4_m4(imat, target_mat);
+ /* convert values into local object space */
+ mul_m4_v3(target_mat, trans->to_min);
+ mul_m4_v3(target_mat, trans->to_max);
+ mul_m4_v3(target_mat, trans->to_min_scale);
+ mul_m4_v3(target_mat, trans->to_max_scale);
+
+ /* Zero out any location translation */
+ target_mat[3][0] = target_mat[3][1] = target_mat[3][2] = 0;
+ invert_m4_m4(imat_rot, target_mat);
+
+ mul_m4_v3(target_mat, trans->to_min_rot);
+ mul_m4_v3(target_mat, trans->to_max_rot);
+
+ /* TODO(sebpa): This does not support euler order, but doing so will make this way more complex.
+ * For now we have decided to not support all corner cases and advanced setups. */
+
+ /* Helper variables to denote the axis in trans->map */
+ const char X = 0;
+ const char Y = 1;
+ const char Z = 2;
+
+ switch (trans->to) {
+ case TRANS_SCALE:
+ copy_v3_v3(temp_vec, trans->to_max_scale);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Scale: Min/Max Flipped */
+ /* Y Rot to X/Y/Z Scale: Min/Max Flipped */
+ /* Z Rot to X/Y/Z Scale: Min/Max Flipped */
+ trans->to_max_scale[i] = trans->to_min_scale[i];
+ trans->to_min_scale[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_LOCATION:
+ /* Invert the X location */
+ trans->to_min[0] *= -1;
+ trans->to_max[0] *= -1;
+
+ copy_v3_v3(temp_vec, trans->to_max);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] != X)) {
+ /* X Loc to X/Y/Z Loc: Min/Max Flipped (and Inverted)
+ * Y Rot to X/Y/Z Loc: Min/Max Flipped
+ * Z Rot to X/Y/Z Loc: Min/Max Flipped */
+ trans->to_max[i] = trans->to_min[i];
+ trans->to_min[i] = temp_vec[i];
+ }
+ }
+ break;
+ case TRANS_ROTATION:
+ /* Invert the Z rotation */
+ trans->to_min_rot[2] *= -1;
+ trans->to_max_rot[2] *= -1;
+
+ if ((trans->from == TRANS_LOCATION && trans->map[1] != X) ||
+ (trans->from == TRANS_ROTATION && trans->map[1] != Y) || trans->from == TRANS_SCALE) {
+ /* Invert the Y rotation */
+ trans->to_min_rot[1] *= -1;
+ trans->to_max_rot[1] *= -1;
+ }
+
+ copy_v3_v3(temp_vec, trans->to_max_rot);
+
+ for (int i = 0; i < 3; i++) {
+ if ((trans->from == TRANS_LOCATION && trans->map[i] == X && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Y && i != 1) ||
+ (trans->from == TRANS_ROTATION && trans->map[i] == Z)) {
+ /* X Loc to X/Z Rot: Flipped
+ * Y Rot to X/Z Rot: Flipped
+ * Z Rot to X/Y/Z rot: Flipped */
+ trans->to_max_rot[i] = trans->to_min_rot[i];
+ trans->to_min_rot[i] = temp_vec[i];
+ }
+ }
+ break;
+ }
+ /* convert back to the settings space */
+ mul_m4_v3(imat, trans->to_min);
+ mul_m4_v3(imat, trans->to_max);
+ mul_m4_v3(imat_rot, trans->to_min_rot);
+ mul_m4_v3(imat_rot, trans->to_max_rot);
+ mul_m4_v3(imat, trans->to_min_scale);
+ mul_m4_v3(imat, trans->to_max_scale);
+}
+
+static void updateDuplicateConstraintSettings(EditBone *dup_bone, EditBone *orig_bone, Object *ob)
+{
+ /* If an edit bone has been duplicated, lets update it's constraints if the
+ * subtarget they point to has also been duplicated.
+ */
+ bPoseChannel *pchan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+ if ((pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name)) == NULL ||
+ (conlist = &pchan->constraints) == NULL) {
+ return;
}
- ED_armature_ebone_unique_name(editbones, eBone->name, NULL);
- BLI_addtail(editbones, eBone);
+ for (curcon = conlist->first; curcon; curcon = curcon->next) {
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_ACTION:
+ updateDuplicateActionConstraintSettings(dup_bone, orig_bone, ob, curcon);
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ updateDuplicateKinematicConstraintSettings(curcon);
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ updateDuplicateLocRotConstraintSettings(ob, pchan, curcon);
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ updateDuplicateTransformConstraintSettings(ob, pchan, curcon);
+ break;
+ }
+ }
+}
+static void updateDuplicateCustomBoneShapes(bContext *C, EditBone *dup_bone, Object *ob)
+{
+ if (ob->pose == NULL) {
+ return;
+ }
+ bPoseChannel *pchan;
+ pchan = BKE_pose_channel_verify(ob->pose, dup_bone->name);
+
+ if (pchan->custom != NULL) {
+ Main *bmain = CTX_data_main(C);
+ char name_flip[MAX_ID_NAME - 2];
+
+ /* Skip the first two chars in the object name as those are used to store object type */
+ BLI_string_flip_side_name(name_flip, pchan->custom->id.name + 2, false, sizeof(name_flip));
+ Object *shape_ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, name_flip);
+
+ if (shape_ob != NULL) {
+ /* A flipped shape object exists, use it! */
+ pchan->custom = shape_ob;
+ }
+ }
+}
+
+static void copy_pchan(EditBone *src_bone, EditBone *dst_bone, Object *src_ob, Object *dst_ob)
+{
/* copy the ID property */
- if (curBone->prop) {
- eBone->prop = IDP_CopyProperty(curBone->prop);
+ if (src_bone->prop) {
+ dst_bone->prop = IDP_CopyProperty(src_bone->prop);
}
/* Lets duplicate the list of constraints that the
@@ -466,25 +880,46 @@ EditBone *duplicateEditBoneObjects(
if (src_ob->pose) {
bPoseChannel *chanold, *channew;
- chanold = BKE_pose_channel_verify(src_ob->pose, curBone->name);
+ chanold = BKE_pose_channel_verify(src_ob->pose, src_bone->name);
if (chanold) {
/* WARNING: this creates a new posechannel, but there will not be an attached bone
* yet as the new bones created here are still 'EditBones' not 'Bones'.
*/
- channew = BKE_pose_channel_verify(dst_ob->pose, eBone->name);
+ channew = BKE_pose_channel_verify(dst_ob->pose, dst_bone->name);
if (channew) {
BKE_pose_channel_copy_data(channew, chanold);
}
}
}
+}
+
+EditBone *duplicateEditBoneObjects(
+ EditBone *cur_bone, const char *name, ListBase *editbones, Object *src_ob, Object *dst_ob)
+{
+ EditBone *e_bone = MEM_mallocN(sizeof(EditBone), "addup_editbone");
+
+ /* Copy data from old bone to new bone */
+ memcpy(e_bone, cur_bone, sizeof(EditBone));
+
+ cur_bone->temp.ebone = e_bone;
+ e_bone->temp.ebone = cur_bone;
+
+ if (name != NULL) {
+ BLI_strncpy(e_bone->name, name, sizeof(e_bone->name));
+ }
- return eBone;
+ ED_armature_ebone_unique_name(editbones, e_bone->name, NULL);
+ BLI_addtail(editbones, e_bone);
+
+ copy_pchan(cur_bone, e_bone, src_ob, dst_ob);
+
+ return e_bone;
}
-EditBone *duplicateEditBone(EditBone *curBone, const char *name, ListBase *editbones, Object *ob)
+EditBone *duplicateEditBone(EditBone *cur_bone, const char *name, ListBase *editbones, Object *ob)
{
- return duplicateEditBoneObjects(curBone, name, editbones, ob, ob);
+ return duplicateEditBoneObjects(cur_bone, name, editbones, ob, ob);
}
static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
@@ -538,8 +973,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
BLI_string_flip_side_name(
new_bone_name_buff, ebone_iter->name, false, sizeof(new_bone_name_buff));
- /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent namings
- * (different numbers), better keep default behavior in this case. */
+ /* Only use flipped name if not yet in use. Otherwise we'd get again inconsistent
+ * namings (different numbers), better keep default behavior in this case. */
if (ED_armature_ebone_find_name(arm->edbo, new_bone_name_buff) == NULL) {
new_bone_name = new_bone_name_buff;
}
@@ -567,13 +1002,13 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
else if (ebone_iter->parent->temp.ebone) {
/* If this bone has a parent that was duplicated,
- * Set the duplicate->parent to the curBone->parent->temp
+ * Set the duplicate->parent to the cur_bone->parent->temp
*/
ebone->parent = ebone_iter->parent->temp.ebone;
}
else {
/* If this bone has a parent that IS not selected,
- * Set the duplicate->parent to the curBone->parent
+ * Set the duplicate->parent to the cur_bone->parent
*/
ebone->parent = (EditBone *)ebone_iter->parent;
ebone->flag &= ~BONE_CONNECTED;
@@ -590,7 +1025,7 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, ob);
+ updateDuplicateSubtarget(ebone, arm->edbo, ob, false);
}
}
@@ -616,6 +1051,8 @@ static int armature_duplicate_selected_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -742,12 +1179,24 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Find the selected bones and duplicate them as needed, with mirrored name */
+ /* Find the selected bones and duplicate them as needed, with mirrored name. */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
ebone_iter = ebone_iter->next) {
- if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED) &&
- /* will be set if the mirror bone already exists (no need to make a new one) */
- (ebone_iter->temp.ebone == NULL)) {
+ if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) {
+ if (ebone_iter->temp.ebone != NULL) {
+ /* This will be set if the mirror bone already exists (no need to make a new one)
+ * but we do need to make sure that the 'pchan' settings (constraints etc)
+ * is synchronized. */
+ bPoseChannel *pchan;
+ /* Make sure we clean up the old data before overwriting it */
+ pchan = BKE_pose_channel_verify(obedit->pose, ebone_iter->temp.ebone->name);
+ BKE_pose_channel_free(pchan);
+ /* Sync pchan data */
+ copy_pchan(ebone_iter, ebone_iter->temp.ebone, obedit, obedit);
+ /* Sync scale mode */
+ ebone_iter->temp.ebone->inherit_scale_mode = ebone_iter->inherit_scale_mode;
+ continue;
+ }
char name_flip[MAXBONENAME];
BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip));
@@ -765,7 +1214,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
}
}
- /* Run through the list and fix the pointers */
+ /* Run through the list and fix the pointers. */
for (ebone_iter = arm->edbo->first; ebone_iter && ebone_iter != ebone_first_dupe;
ebone_iter = ebone_iter->next) {
if (ebone_iter->temp.ebone) {
@@ -793,7 +1242,12 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
* then we can assume the parent has no L/R but is a center bone.
* So just use the same parent for both.
*/
- ebone->flag &= ~BONE_CONNECTED;
+
+ if (ebone->head[axis] != 0.0f) {
+ /* The mirrored bone doesn't start on the mirror axis, so assume that this one should
+ * not be connected to the old parent */
+ ebone->flag &= ~BONE_CONNECTED;
+ }
}
ebone->parent = ebone_parent;
@@ -803,10 +1257,19 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op)
ebone->bbone_prev = get_symmetrized_bone(arm, ebone_iter->bbone_prev);
ebone->bbone_next = get_symmetrized_bone(arm, ebone_iter->bbone_next);
+ /* Sync bbone handle types */
+ ebone->bbone_prev_type = ebone_iter->bbone_prev_type;
+ ebone->bbone_next_type = ebone_iter->bbone_next_type;
+
/* Lets try to fix any constraint subtargets that might
* have been duplicated
*/
- updateDuplicateSubtarget(ebone, arm->edbo, obedit);
+ updateDuplicateSubtarget(ebone, arm->edbo, obedit, true);
+ /* Try to update constraint options so that they are mirrored as well
+ * (need to supply bone_iter as well in case we are working with existing bones) */
+ updateDuplicateConstraintSettings(ebone, ebone_iter, obedit);
+ /* Mirror bone shapes if possible */
+ updateDuplicateCustomBoneShapes(C, ebone, obedit);
}
}
@@ -1062,7 +1525,13 @@ static int armature_extrude_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (!changed_multi) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+
+ return OPERATOR_FINISHED;
}
void ARMATURE_OT_extrude(wmOperatorType *ot)
@@ -1116,7 +1585,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
ED_armature_edit_deselect_all(obedit);
- /* Create a bone */
+ /* Create a bone. */
bone = ED_armature_ebone_add(obedit->data, name);
copy_v3_v3(bone->head, curs);
@@ -1133,6 +1602,7 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1223,6 +1693,7 @@ static int armature_subdivide_exec(bContext *C, wmOperator *op)
/* note, notifier might evolve */
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&obedit->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -1232,7 +1703,7 @@ void ARMATURE_OT_subdivide(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Subdivide Multi";
+ ot->name = "Subdivide";
ot->idname = "ARMATURE_OT_subdivide";
ot->description = "Break selected bones into chains of smaller bones";
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index b8378c95a60..a7a705a6202 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -54,6 +54,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_view3d.h"
@@ -499,7 +500,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
/* Roll func is a callback which assumes that all is well. */
ebone->roll = roll;
@@ -508,7 +509,7 @@ static int armature_roll_clear_exec(bContext *C, wmOperator *op)
}
if (arm->flag & ARM_MIRROR_EDIT) {
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
EditBone *ebone_mirr = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
@@ -889,213 +890,6 @@ void ARMATURE_OT_fill(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Merge Operator
- * \{ */
-
-/* this function merges between two bones, removes them and those in-between,
- * and adjusts the parent relationships for those in-between
- */
-static void bones_merge(
- Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
-{
- bArmature *arm = obedit->data;
- EditBone *ebo, *ebone, *newbone;
- LinkData *chain;
- float head[3], tail[3];
-
- /* check if same bone */
- if (start == end) {
- if (G.debug & G_DEBUG) {
- printf("Error: same bone!\n");
- printf("\tstart = %s, end = %s\n", start->name, end->name);
- }
- }
-
- /* step 1: add a new bone
- * - head = head/tail of start (default head)
- * - tail = head/tail of end (default tail)
- * - parent = parent of start
- */
- if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(head, start->tail);
- }
- else {
- copy_v3_v3(head, start->head);
- }
- if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
- copy_v3_v3(tail, end->head);
- }
- else {
- copy_v3_v3(tail, end->tail);
- }
- newbone = add_points_bone(obedit, head, tail);
- newbone->parent = start->parent;
-
- /* TODO, copy more things to the new bone */
- newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_CYCLICOFFSET |
- BONE_NO_LOCAL_LOCATION | BONE_DONE);
-
- newbone->inherit_scale_mode = start->inherit_scale_mode;
-
- /* Step 2a: reparent any side chains which may be parented to any bone in the chain
- * of bones to merge - potentially several tips for side chains leading to some tree exist.
- */
- for (chain = chains->first; chain; chain = chain->next) {
- /* Traverse down chain until we hit the bottom or if we run into the tip of the chain of bones
- * we're merging (need to stop in this case to avoid corrupting this chain too!).
- */
- for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
- short found = 0;
-
- /* Check if this bone is parented to one in the merging chain
- * ! WATCHIT: must only go check until end of checking chain
- */
- for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
- /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
- if (ebone->parent == ebo) {
- ebone->parent = newbone;
- found = 1;
- break;
- }
- }
-
- /* carry on to the next tip now */
- if (found) {
- break;
- }
- }
- }
-
- /* step 2b: parent child of end to newbone (child from this chain) */
- if (endchild) {
- endchild->parent = newbone;
- }
-
- /* step 3: delete all bones between and including start and end */
- for (ebo = end; ebo; ebo = ebone) {
- ebone = (ebo == start) ? (NULL) : (ebo->parent);
- bone_free(arm, ebo);
- }
-
- newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
- ED_armature_edit_sync_selection(arm->edbo);
-}
-
-static int armature_merge_exec(bContext *C, wmOperator *op)
-{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const short type = RNA_enum_get(op->ptr, "type");
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- bArmature *arm = obedit->data;
-
- /* for now, there's only really one type of merging that's performed... */
- if (type == 1) {
- /* go down chains, merging bones */
- ListBase chains = {NULL, NULL};
- LinkData *chain, *nchain;
- EditBone *ebo;
-
- armature_tag_select_mirrored(arm);
-
- /* get chains (ends on chains) */
- chains_find_tips(arm->edbo, &chains);
- if (BLI_listbase_is_empty(&chains)) {
- continue;
- }
-
- /* each 'chain' is the last bone in the chain (with no children) */
- for (chain = chains.first; chain; chain = nchain) {
- EditBone *bstart = NULL, *bend = NULL;
- EditBone *bchild = NULL, *child = NULL;
-
- /* temporarily remove chain from list of chains */
- nchain = chain->next;
- BLI_remlink(&chains, chain);
-
- /* only consider bones that are visible and selected */
- for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
- /* check if visible + selected */
- if (EBONE_VISIBLE(arm, ebo) && ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
- (ebo->flag & BONE_SELECTED)) {
- /* set either end or start (end gets priority, unless it is already set) */
- if (bend == NULL) {
- bend = ebo;
- bchild = child;
- }
- else {
- bstart = ebo;
- }
- }
- else {
- /* chain is broken... merge any continuous segments then clear */
- if (bstart && bend) {
- bones_merge(obedit, bstart, bend, bchild, &chains);
- }
-
- bstart = NULL;
- bend = NULL;
- bchild = NULL;
- }
- }
-
- /* merge from bstart to bend if something not merged */
- if (bstart && bend) {
- bones_merge(obedit, bstart, bend, bchild, &chains);
- }
-
- /* put back link */
- BLI_insertlinkbefore(&chains, nchain, chain);
- }
-
- armature_tag_unselect(arm);
-
- BLI_freelistN(&chains);
- }
-
- /* updates */
- ED_armature_edit_sync_selection(arm->edbo);
- ED_armature_edit_refresh_layer_used(arm);
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-void ARMATURE_OT_merge(wmOperatorType *ot)
-{
- static const EnumPropertyItem merge_types[] = {
- {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
- {0, NULL, 0, NULL, NULL},
- };
-
- /* identifiers */
- ot->name = "Merge Bones";
- ot->idname = "ARMATURE_OT_merge";
- ot->description = "Merge continuous chains of selected bones";
-
- /* callbacks */
- ot->invoke = WM_menu_invoke;
- ot->exec = armature_merge_exec;
- ot->poll = ED_operator_editarmature;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Switch Direction Operator
*
* Currently, this does not use context loops, as context loops do not make it
@@ -1396,13 +1190,13 @@ static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
Object *ob = objects[ob_index];
bArmature *arm = ob->data;
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
bone->parent = NULL;
bone->flag &= ~BONE_CONNECTED;
}
}
- for (EditBone *bone = arm->edbo->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (EditBone *, bone, arm->edbo) {
ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
}
@@ -1490,6 +1284,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1665,6 +1460,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op))
ED_armature_edit_refresh_layer_used(arm);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
+ ED_outliner_select_sync_from_edit_bone_tag(C);
}
}
MEM_freeN(objects);
@@ -1715,7 +1511,7 @@ static int armature_hide_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if ((ebone->flag & BONE_SELECTED) != invert) {
ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
@@ -1774,7 +1570,7 @@ static int armature_reveal_exec(bContext *C, wmOperator *op)
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_HIDDEN_A) {
if (!(ebone->flag & BONE_UNSELECTABLE)) {
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index fa562ab0f44..08d82bf13c9 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -59,6 +59,7 @@ void ARMATURE_OT_select_mirror(struct wmOperatorType *ot);
void ARMATURE_OT_select_more(struct wmOperatorType *ot);
void ARMATURE_OT_select_less(struct wmOperatorType *ot);
void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
+void ARMATURE_OT_select_linked_pick(struct wmOperatorType *ot);
void ARMATURE_OT_select_linked(struct wmOperatorType *ot);
void ARMATURE_OT_select_similar(struct wmOperatorType *ot);
void ARMATURE_OT_shortest_path_pick(struct wmOperatorType *ot);
@@ -72,7 +73,6 @@ void ARMATURE_OT_hide(struct wmOperatorType *ot);
void ARMATURE_OT_reveal(struct wmOperatorType *ot);
void ARMATURE_OT_click_extrude(struct wmOperatorType *ot);
void ARMATURE_OT_fill(struct wmOperatorType *ot);
-void ARMATURE_OT_merge(struct wmOperatorType *ot);
void ARMATURE_OT_separate(struct wmOperatorType *ot);
void ARMATURE_OT_split(struct wmOperatorType *ot);
@@ -104,6 +104,7 @@ void POSE_OT_select_all(struct wmOperatorType *ot);
void POSE_OT_select_parent(struct wmOperatorType *ot);
void POSE_OT_select_hierarchy(struct wmOperatorType *ot);
void POSE_OT_select_linked(struct wmOperatorType *ot);
+void POSE_OT_select_linked_pick(struct wmOperatorType *ot);
void POSE_OT_select_constraint_target(struct wmOperatorType *ot);
void POSE_OT_select_grouped(struct wmOperatorType *ot);
void POSE_OT_select_mirror(struct wmOperatorType *ot);
@@ -232,9 +233,6 @@ struct EditBone *duplicateEditBone(struct EditBone *curBone,
const char *name,
struct ListBase *editbones,
struct Object *ob);
-void updateDuplicateSubtarget(struct EditBone *dupBone,
- struct ListBase *editbones,
- struct Object *ob);
/* duplicate method (cross objects) */
/* editbones is the target list */
@@ -244,12 +242,6 @@ struct EditBone *duplicateEditBoneObjects(struct EditBone *curBone,
struct Object *src_ob,
struct Object *dst_ob);
-/* editbones is the source list */
-void updateDuplicateSubtargetObjects(struct EditBone *dupBone,
- struct ListBase *editbones,
- struct Object *src_ob,
- struct Object *dst_ob);
-
EditBone *add_points_bone(struct Object *obedit, float head[3], float tail[3]);
void bone_free(struct bArmature *arm, struct EditBone *bone);
@@ -258,16 +250,40 @@ void armature_select_mirrored_ex(struct bArmature *arm, const int flag);
void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
-void *get_nearest_bone(struct bContext *C, const int xy[2], bool findunsel, struct Base **r_base);
-
-void *get_bone_from_selectbuffer(struct Base **bases,
- uint bases_len,
- bool is_editmode,
- const unsigned int *buffer,
- short hits,
+EditBone *ED_armature_pick_ebone(struct bContext *C,
+ const int xy[2],
bool findunsel,
- bool do_nearest,
struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone(struct bContext *C,
+ const int xy[2],
+ bool findunsel,
+ struct Base **r_base);
+
+struct EditBone *ED_armature_pick_ebone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
+struct Bone *ED_armature_pick_bone_from_selectbuffer(struct Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ struct Base **r_base);
int bone_looper(struct Object *ob,
struct Bone *bone,
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 13660244547..544d86d4c47 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -20,6 +20,8 @@
/** \file
* \ingroup edarmature
+ *
+ * This file contains functions/API's for renaming bones and/or working with them.
*/
#include <string.h>
@@ -63,12 +65,11 @@
#include "armature_intern.h"
-/* This file contains functions/API's for renaming bones and/or working with them */
-
-/* ************************************************** */
-/* EditBone Names */
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Edit Mode)
+ * \{ */
-/* note: there's a unique_bone_name() too! */
+/* note: there's a ed_armature_bone_unique_name() too! */
static bool editbone_unique_check(void *arg, const char *name)
{
struct {
@@ -92,20 +93,29 @@ void ED_armature_ebone_unique_name(ListBase *edbo, char *name, EditBone *bone)
BLI_uniquename_cb(editbone_unique_check, &data, DATA_("Bone"), '.', name, sizeof(bone->name));
}
-/* ************************************************** */
-/* Bone Renaming - API */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unique Bone Name Utility (Object Mode)
+ * \{ */
static bool bone_unique_check(void *arg, const char *name)
{
return BKE_armature_find_bone_name((bArmature *)arg, name) != NULL;
}
-static void unique_bone_name(bArmature *arm, char *name)
+static void ed_armature_bone_unique_name(bArmature *arm, char *name)
{
BLI_uniquename_cb(
bone_unique_check, (void *)arm, DATA_("Bone"), '.', name, sizeof(((Bone *)NULL)->name));
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Renaming (Object & Edit Mode API)
+ * \{ */
+
/* helper call for armature_bone_rename */
static void constraint_bone_name_fix(Object *ob,
ListBase *conlist,
@@ -180,7 +190,7 @@ void ED_armature_bone_rename(Main *bmain,
Bone *bone = BKE_armature_find_bone_name(arm, oldname);
if (bone) {
- unique_bone_name(arm, newname);
+ ed_armature_bone_unique_name(arm, newname);
if (arm->bonehash) {
BLI_assert(BLI_ghash_haskey(arm->bonehash, bone->name));
@@ -255,7 +265,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- if (modifiers_usesArmature(ob, arm)) {
+ if (BKE_modifiers_uses_armature(ob, arm)) {
bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname);
if (dg) {
BLI_strncpy(dg->name, newname, MAXBONENAME);
@@ -307,8 +317,7 @@ void ED_armature_bone_rename(Main *bmain,
}
}
- for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md;
- gp_md = gp_md->next) {
+ LISTBASE_FOREACH (GpencilModifierData *, gp_md, &ob->greasepencil_modifiers) {
switch (gp_md->type) {
case eGpencilModifierType_Armature: {
ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md;
@@ -352,11 +361,11 @@ void ED_armature_bone_rename(Main *bmain,
{
bScreen *screen;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- ScrArea *sa;
+ ScrArea *area;
/* add regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->ob_center && v3d->ob_center->data == arm) {
@@ -372,6 +381,12 @@ void ED_armature_bone_rename(Main *bmain,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Flipping (Object & Edit Mode API)
+ * \{ */
+
typedef struct BoneFlipNameData {
struct BoneFlipNameData *next, *prev;
char *name;
@@ -399,7 +414,7 @@ void ED_armature_bones_flip_names(Main *bmain,
/* First pass: generate flip names, and blindly rename.
* If rename did not yield expected result,
* store both bone's name and expected flipped one into temp list for second pass. */
- for (LinkData *link = bones_names->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, bones_names) {
char name_flip[MAXBONENAME];
char *name = link->data;
@@ -426,8 +441,11 @@ void ED_armature_bones_flip_names(Main *bmain,
}
}
-/* ************************************************** */
-/* Bone Renaming - EditMode */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flip Bone Names (Edit Mode Operator)
+ * \{ */
static int armature_flip_names_exec(bContext *C, wmOperator *op)
{
@@ -451,7 +469,7 @@ static int armature_flip_names_exec(bContext *C, wmOperator *op)
ListBase bones_names = {NULL};
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & BONE_SELECTED) {
BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name));
@@ -511,6 +529,12 @@ void ARMATURE_OT_flip_names(wmOperatorType *ot)
"(WARNING: may result in incoherent naming in some cases)");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Bone Auto Side Names (Edit Mode Operator)
+ * \{ */
+
static int armature_autoside_names_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -532,7 +556,7 @@ static int armature_autoside_names_exec(bContext *C, wmOperator *op)
continue;
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
/* We first need to do the flipped bone, then the original one.
@@ -599,3 +623,5 @@ void ARMATURE_OT_autoside_names(wmOperatorType *ot)
/* settings */
ot->prop = RNA_def_enum(ot->srna, "type", axis_items, 0, "Axis", "Axis tag names with");
}
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c
index a29d0f5f158..da1b29307b1 100644
--- a/source/blender/editors/armature/armature_ops.c
+++ b/source/blender/editors/armature/armature_ops.c
@@ -56,6 +56,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_select_less);
WM_operatortype_append(ARMATURE_OT_select_hierarchy);
WM_operatortype_append(ARMATURE_OT_select_linked);
+ WM_operatortype_append(ARMATURE_OT_select_linked_pick);
WM_operatortype_append(ARMATURE_OT_select_similar);
WM_operatortype_append(ARMATURE_OT_shortest_path_pick);
@@ -68,7 +69,6 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(ARMATURE_OT_reveal);
WM_operatortype_append(ARMATURE_OT_click_extrude);
WM_operatortype_append(ARMATURE_OT_fill);
- WM_operatortype_append(ARMATURE_OT_merge);
WM_operatortype_append(ARMATURE_OT_separate);
WM_operatortype_append(ARMATURE_OT_split);
@@ -100,6 +100,7 @@ void ED_operatortypes_armature(void)
WM_operatortype_append(POSE_OT_select_parent);
WM_operatortype_append(POSE_OT_select_hierarchy);
WM_operatortype_append(POSE_OT_select_linked);
+ WM_operatortype_append(POSE_OT_select_linked_pick);
WM_operatortype_append(POSE_OT_select_constraint_target);
WM_operatortype_append(POSE_OT_select_grouped);
WM_operatortype_append(POSE_OT_select_mirror);
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 2c2bf3cd283..d3d00fc44f2 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -37,11 +37,12 @@
#include "BLT_translation.h"
#include "BKE_action.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -57,6 +58,7 @@
#include "ED_armature.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -280,7 +282,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
float mat[4][4], oimat[4][4];
bool ok = false;
- /* Ensure we're not in editmode and that the active object is an armature*/
+ /* Ensure we're not in edit-mode and that the active object is an armature. */
if (!ob_active || ob_active->type != OB_ARMATURE) {
return OPERATOR_CANCELLED;
}
@@ -430,7 +432,6 @@ int join_armature_exec(bContext *C, wmOperator *op)
ED_armature_from_edit(bmain, arm);
ED_armature_edit_free(arm);
- BKE_armature_refresh_layer_used(arm);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
@@ -568,7 +569,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
if (is_select == (EBONE_VISIBLE(arm, curbone) && (curbone->flag & BONE_SELECTED))) {
/* clear the bone->parent var of any bone that had this as its parent */
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (ebo->parent == curbone) {
ebo->parent = NULL;
/* this is needed to prevent random crashes with in ED_armature_from_edit */
@@ -578,7 +579,7 @@ static void separate_armature_bones(Main *bmain, Object *ob, const bool is_selec
}
/* clear the pchan->parent var of any pchan that had this as its parent */
- for (bPoseChannel *pchn = ob->pose->chanbase.first; pchn; pchn = pchn->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchn, &ob->pose->chanbase) {
if (pchn->parent == pchan) {
pchn->parent = NULL;
}
@@ -629,7 +630,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
bArmature *arm_old = ob_old->data;
bool has_selected_bone = false;
bool has_selected_any = false;
- for (EditBone *ebone = arm_old->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm_old->edbo) {
if (EBONE_VISIBLE(arm_old, ebone)) {
if (ebone->flag & BONE_SELECTED) {
has_selected_bone = true;
@@ -687,9 +688,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
/* 5) restore original conditions */
ED_armature_to_edit(ob_old->data);
-
ED_armature_edit_refresh_layer_used(ob_old->data);
- BKE_armature_refresh_layer_used(ob_new->data);
/* parents tips remain selected when connected children are removed. */
ED_armature_edit_deselect_all(ob_old);
@@ -706,6 +705,7 @@ static int separate_armature_exec(bContext *C, wmOperator *op)
if (ok) {
BKE_report(op->reports, RPT_INFO, "Separated bones");
+ ED_outliner_select_sync_from_object_tag(C);
}
return OPERATOR_FINISHED;
@@ -835,7 +835,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
bool is_active_only_selected = false;
if (actbone->flag & BONE_SELECTED) {
is_active_only_selected = true;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
is_active_only_selected = false;
@@ -867,7 +867,7 @@ static int armature_parent_set_exec(bContext *C, wmOperator *op)
*/
/* Parent selected bones to the active one. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
bone_connect_to_new_parent(arm->edbo, ebone, actbone, val);
@@ -901,7 +901,7 @@ static int armature_parent_set_invoke(bContext *C,
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
EditBone *actbone = arm->act_edbone;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
if (ebone->parent != actbone) {
@@ -983,7 +983,7 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone)) {
changed = true;
break;
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 21eccd2ca1f..4b8bbe39a16 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rect.h"
#include "BLI_string_utils.h"
#include "BKE_action.h"
@@ -59,7 +60,9 @@
#define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
#define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
-/* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries for PoseMode & EditMode
+ * \{ */
Base *ED_armature_base_and_ebone_from_select_buffer(Base **bases,
uint bases_len,
@@ -109,14 +112,14 @@ Object *ED_armature_object_and_ebone_from_select_buffer(Object **objects,
return ob;
}
-Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
- uint bases_len,
- int hit,
- Bone **r_bone)
+Base *ED_armature_base_and_pchan_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ bPoseChannel **r_pchan)
{
const uint hit_object = hit & 0xFFFF;
Base *base = NULL;
- Bone *bone = NULL;
+ bPoseChannel *pchan = NULL;
/* TODO(campbell): 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) {
@@ -127,30 +130,53 @@ Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
if (base != NULL) {
if (base->object->pose != NULL) {
const uint hit_bone = (hit & ~BONESEL_ANY) >> 16;
- bPoseChannel *pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
- bone = pchan ? pchan->bone : NULL;
+ /* pchan may be NULL. */
+ pchan = BLI_findlink(&base->object->pose->chanbase, hit_bone);
}
}
- *r_bone = bone;
+ *r_pchan = pchan;
+ return base;
+}
+
+/* For callers that don't need the pose channel. */
+Base *ED_armature_base_and_bone_from_select_buffer(Base **bases,
+ uint bases_len,
+ int hit,
+ Bone **r_bone)
+{
+ bPoseChannel *pchan = NULL;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hit, &pchan);
+ *r_bone = pchan ? pchan->bone : NULL;
return base;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick from Select Buffer API
+ *
+ * Internal #ed_armature_pick_bone_from_selectbuffer_impl is exposed as:
+ * - #ED_armature_pick_ebone_from_selectbuffer
+ * - #ED_armature_pick_pchan_from_selectbuffer
+ * - #ED_armature_pick_bone_from_selectbuffer
+ * \{ */
+
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
-void *get_bone_from_selectbuffer(Base **bases,
- uint bases_len,
- bool is_editmode,
- const unsigned int *buffer,
- short hits,
- bool findunsel,
- bool do_nearest,
- Base **r_base)
+static void *ed_armature_pick_bone_from_selectbuffer_impl(const bool is_editmode,
+ Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
{
- Bone *bone;
+ bPoseChannel *pchan;
EditBone *ebone;
void *firstunSel = NULL, *firstSel = NULL, *data;
Base *firstunSel_base = NULL, *firstSel_base = NULL;
- unsigned int hitresult;
+ uint hitresult;
short i;
bool takeNext = false;
int minsel = 0xffffffff, minunsel = 0xffffffff;
@@ -158,77 +184,74 @@ void *get_bone_from_selectbuffer(Base **bases,
for (i = 0; i < hits; i++) {
hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
- Base *base = NULL;
- bool sel;
+ if (hitresult & BONESEL_ANY) { /* to avoid including objects in selection */
+ Base *base = NULL;
+ bool sel;
- hitresult &= ~(BONESEL_ANY);
- /* Determine what the current bone is */
- if (is_editmode == false) {
- base = ED_armature_base_and_bone_from_select_buffer(bases, bases_len, hitresult, &bone);
- if (bone != NULL) {
- if (findunsel) {
- sel = (bone->flag & BONE_SELECTED);
- }
- else {
- sel = !(bone->flag & BONE_SELECTED);
- }
-
- data = bone;
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (is_editmode == false) {
+ base = ED_armature_base_and_pchan_from_select_buffer(bases, bases_len, hitresult, &pchan);
+ if (pchan != NULL) {
+ if (findunsel) {
+ sel = (pchan->bone->flag & BONE_SELECTED);
}
else {
- data = NULL;
- sel = 0;
+ sel = !(pchan->bone->flag & BONE_SELECTED);
}
+
+ data = pchan;
}
else {
- base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, hitresult, &ebone);
- if (findunsel) {
- sel = (ebone->flag & BONE_SELECTED);
+ data = NULL;
+ sel = 0;
+ }
+ }
+ else {
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ if (findunsel) {
+ sel = (ebone->flag & BONE_SELECTED);
+ }
+ else {
+ sel = !(ebone->flag & BONE_SELECTED);
+ }
+
+ data = ebone;
+ }
+
+ if (data) {
+ if (sel) {
+ if (do_nearest) {
+ if (minsel > buffer[4 * i + 1]) {
+ firstSel = data;
+ firstSel_base = base;
+ minsel = buffer[4 * i + 1];
+ }
}
else {
- sel = !(ebone->flag & BONE_SELECTED);
+ if (!firstSel) {
+ firstSel = data;
+ firstSel_base = base;
+ }
+ takeNext = 1;
}
-
- data = ebone;
}
-
- if (data) {
- if (sel) {
- if (do_nearest) {
- if (minsel > buffer[4 * i + 1]) {
- firstSel = data;
- firstSel_base = base;
- minsel = buffer[4 * i + 1];
- }
- }
- else {
- if (!firstSel) {
- firstSel = data;
- firstSel_base = base;
- }
- takeNext = 1;
+ else {
+ if (do_nearest) {
+ if (minunsel > buffer[4 * i + 1]) {
+ firstunSel = data;
+ firstunSel_base = base;
+ minunsel = buffer[4 * i + 1];
}
}
else {
- if (do_nearest) {
- if (minunsel > buffer[4 * i + 1]) {
- firstunSel = data;
- firstunSel_base = base;
- minunsel = buffer[4 * i + 1];
- }
+ if (!firstunSel) {
+ firstunSel = data;
+ firstunSel_base = base;
}
- else {
- if (!firstunSel) {
- firstunSel = data;
- firstunSel_base = base;
- }
- if (takeNext) {
- *r_base = base;
- return data;
- }
+ if (takeNext) {
+ *r_base = base;
+ return data;
}
}
}
@@ -246,22 +269,74 @@ void *get_bone_from_selectbuffer(Base **bases,
}
}
-/* used by posemode as well editmode */
-/* only checks scene->basact! */
-/* x and y are mouse coords (area space) */
-void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+EditBone *ED_armature_pick_ebone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+bPoseChannel *ED_armature_pick_pchan_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+}
+
+Bone *ED_armature_pick_bone_from_selectbuffer(Base **bases,
+ uint bases_len,
+ const uint *buffer,
+ short hits,
+ bool findunsel,
+ bool do_nearest,
+ Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan_from_selectbuffer(
+ bases, bases_len, buffer, hits, findunsel, do_nearest, r_base);
+ return pchan ? pchan->bone : NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Pick API
+ *
+ * Internal #ed_armature_pick_bone_impl is exposed as:
+ * - #ED_armature_pick_ebone
+ * - #ED_armature_pick_pchan
+ * - #ED_armature_pick_bone
+ * \{ */
+
+/**
+ * \param xy: Cursor coordinates (area space).
+ * \return An #EditBone when is_editmode, otherwise a #bPoseChannel.
+ * \note Only checks objects in the current mode (edit-mode or pose-mode).
+ */
+static void *ed_armature_pick_bone_impl(
+ const bool is_editmode, bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
- unsigned int buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
short hits;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ BLI_assert((vc.obedit != NULL) == is_editmode);
- // rect.xmin = ... mouseco!
- rect.xmin = rect.xmax = xy[0];
- rect.ymin = rect.ymax = xy[1];
+ BLI_rcti_init_pt_radius(&rect, xy, 0);
hits = view3d_opengl_select(
&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST, VIEW3D_SELECT_FILTER_NOP);
@@ -284,123 +359,287 @@ void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel, Base **r_ba
bases = BKE_object_pose_base_array_get(vc.view_layer, vc.v3d, &bases_len);
}
- void *bone = get_bone_from_selectbuffer(
- bases, bases_len, vc.obedit != NULL, buffer, hits, findunsel, true, r_base);
+ void *bone = ed_armature_pick_bone_from_selectbuffer_impl(
+ is_editmode, bases, bases_len, buffer, hits, findunsel, true, r_base);
MEM_freeN(bases);
+
return bone;
}
return NULL;
}
-/* **************** EditMode stuff ********************** */
+EditBone *ED_armature_pick_ebone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ const bool is_editmode = true;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
-static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+bPoseChannel *ED_armature_pick_pchan(bContext *C, const int xy[2], bool findunsel, Base **r_base)
{
- bArmature *arm;
- EditBone *bone, *curBone, *next;
- const bool sel = !RNA_boolean_get(op->ptr, "deselect");
+ const bool is_editmode = false;
+ return ed_armature_pick_bone_impl(is_editmode, C, xy, findunsel, r_base);
+}
- view3d_operator_needs_opengl(C);
- BKE_object_update_select_id(CTX_data_main(C));
+Bone *ED_armature_pick_bone(bContext *C, const int xy[2], bool findunsel, Base **r_base)
+{
+ bPoseChannel *pchan = ED_armature_pick_pchan(C, xy, findunsel, r_base);
+ return pchan ? pchan->bone : NULL;
+}
- Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, true, &base);
+/** \} */
- if (!bone) {
- return OPERATOR_CANCELLED;
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Implementation
+ *
+ * Shared logic for select linked all/pick.
+ *
+ * Use #BONE_DONE flag to select linked.
+ * \{ */
+
+/**
+ * \param all_forks: Control how chains are stepped over.
+ * true: select all connected bones traveling up & down forks.
+ * false: select all parents and all children, but not the children of the root bone.
+ */
+static bool armature_select_linked_impl(Object *ob, const bool select, const bool all_forks)
+{
+ bool changed = false;
+ bArmature *arm = ob->data;
+
+ /* Implementation note, this flood-fills selected bones with the 'TOUCH' flag,
+ * even though this is a loop-within a loop, walking up the parent chain only touches new bones.
+ * Bones that have been touched are skipped, so the complexity is OK. */
+
+ enum {
+ /* Bone has been walked over, it's LINK value can be read. */
+ TOUCH = (1 << 0),
+ /* When TOUCH has been set, this flag can be checked to see if the bone is connected. */
+ LINK = (1 << 1),
+ };
+
+#define CHECK_PARENT(ebone) \
+ (((ebone)->flag & BONE_CONNECTED) && \
+ ((ebone)->parent ? EBONE_SELECTABLE(arm, (ebone)->parent) : false))
+
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->temp.i = 0;
}
- arm = base->object->data;
+ /* Select parents. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
+ }
+ if ((ebone_iter->flag & BONE_DONE) == 0) {
+ continue;
+ }
+
+ ebone_iter->temp.i |= TOUCH | LINK;
- /* Select parents */
- for (curBone = bone; curBone; curBone = next) {
- if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ /* We have an un-touched link. */
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
+
+ if (all_forks) {
+ ebone->temp.i |= (TOUCH | LINK);
}
else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ ebone->temp.i |= TOUCH;
+ }
+ /* Don't walk onto links (messes up 'all_forks' logic). */
+ if (ebone->parent && ebone->parent->temp.i & LINK) {
+ break;
}
}
+ }
- if (curBone->flag & BONE_CONNECTED) {
- next = curBone->parent;
+ /* Select children. */
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
+ /* No need to 'touch' this bone as it won't be walked over when scanning up the chain. */
+ if (!CHECK_PARENT(ebone_iter)) {
+ continue;
}
- else {
- next = NULL;
+ if (ebone_iter->temp.i & TOUCH) {
+ continue;
}
- }
- /* Select children */
- while (bone) {
- for (curBone = arm->edbo->first; curBone; curBone = next) {
- next = curBone->next;
- if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
- if (curBone->flag & BONE_CONNECTED) {
- if (sel) {
- curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- bone = curBone;
- break;
- }
- else {
- bone = NULL;
- break;
+ /* First check if we're marked. */
+ EditBone *ebone_touched_parent = NULL;
+ for (EditBone *ebone = ebone_iter; ebone; ebone = CHECK_PARENT(ebone) ? ebone->parent : NULL) {
+ if (ebone->temp.i & TOUCH) {
+ ebone_touched_parent = ebone;
+ break;
+ }
+ ebone->temp.i |= TOUCH;
+ }
+
+ if ((ebone_touched_parent != NULL) && (ebone_touched_parent->temp.i & LINK)) {
+ for (EditBone *ebone = ebone_iter; ebone != ebone_touched_parent; ebone = ebone->parent) {
+ if ((ebone->temp.i & LINK) == 0) {
+ ebone->temp.i |= LINK;
+ ED_armature_ebone_select_set(ebone, select);
+ changed = true;
}
}
}
- if (!curBone) {
- bone = NULL;
+ }
+
+#undef CHECK_PARENT
+
+ if (changed) {
+ ED_armature_edit_sync_selection(arm->edbo);
+ DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, ob);
+ }
+
+ return changed;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int armature_select_linked_exec(bContext *C, wmOperator *op)
+{
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ bool changed_multi = false;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ bArmature *arm = ob->data;
+
+ bool found = false;
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ if (EBONE_VISIBLE(arm, ebone) &&
+ (ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))) {
+ ebone->flag |= BONE_DONE;
+ found = true;
+ }
+ else {
+ ebone->flag &= ~BONE_DONE;
+ }
+ }
+
+ if (found) {
+ if (armature_select_linked_impl(ob, true, all_forks)) {
+ changed_multi = true;
+ }
}
}
+ MEM_freeN(objects);
- ED_outliner_select_sync_from_edit_bone_tag(C);
+ if (changed_multi) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
+ return OPERATOR_FINISHED;
+}
- ED_armature_edit_sync_selection(arm->edbo);
+void ARMATURE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked All";
+ ot->idname = "ARMATURE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
- WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, base->object);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
+ /* api callbacks */
+ ot->exec = armature_select_linked_exec;
+ ot->poll = ED_operator_editarmature;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int armature_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool select = !RNA_boolean_get(op->ptr, "deselect");
+ const bool all_forks = RNA_boolean_get(op->ptr, "all_forks");
+
+ view3d_operator_needs_opengl(C);
+ BKE_object_update_select_id(CTX_data_main(C));
+
+ Base *base = NULL;
+ EditBone *ebone_active = ED_armature_pick_ebone(C, event->mval, true, &base);
+
+ if (ebone_active == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ bArmature *arm = base->object->data;
+ if (!EBONE_SELECTABLE(arm, ebone_active)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Initialize flags. */
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
+ ebone->flag &= ~BONE_DONE;
+ }
+ ebone_active->flag |= BONE_DONE;
+
+ if (armature_select_linked_impl(base->object, select, all_forks)) {
+ ED_outliner_select_sync_from_edit_bone_tag(C);
+ }
return OPERATOR_FINISHED;
}
-static bool armature_select_linked_poll(bContext *C)
+static bool armature_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
-void ARMATURE_OT_select_linked(wmOperatorType *ot)
+void ARMATURE_OT_select_linked_pick(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Connected";
- ot->idname = "ARMATURE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ ot->name = "Select Linked";
+ ot->idname = "ARMATURE_OT_select_linked_pick";
+ ot->description = "(De)select bones linked by parent/child connections under the mouse cursor";
/* api callbacks */
/* leave 'exec' unset */
- ot->invoke = armature_select_linked_invoke;
- ot->poll = armature_select_linked_poll;
+ ot->invoke = armature_select_linked_pick_invoke;
+ ot->poll = armature_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ /* Leave disabled by default as this matches pose mode. */
+ RNA_def_boolean(ot->srna, "all_forks", 0, "All Forks", "Follow forks in the parents chain");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Buffer Queries EditMode
+ * \{ */
+
/* utility function for get_nearest_editbonepoint */
-static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
+static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12)
{
return hits12;
}
-static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
+static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5)
{
const int offs = 4 * hits12;
- memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint));
return hits5;
}
@@ -414,45 +653,28 @@ static EditBone *get_nearest_editbonepoint(
uint hitresult;
Base *base;
EditBone *ebone;
- } best = {
- .hitresult = BONESEL_NOSEL,
- .base = NULL,
- .ebone = NULL,
- };
+ } *result = NULL,
+
+ result_cycle = {.hitresult = -1, .base = NULL, .ebone = NULL},
+ result_bias = {.hitresult = -1, .base = NULL, .ebone = NULL};
/* find the bone after the current active bone, so as to bump up its chances in selection.
* this way overlapping bones will cycle selection state as with objects. */
- EditBone *ebone_next_act = ((bArmature *)vc->obedit->data)->act_edbone;
- {
- bArmature *arm = (bArmature *)vc->obedit->data;
- if (ebone_next_act && EBONE_VISIBLE(arm, ebone_next_act) &&
- ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
- ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
- }
- else {
- ebone_next_act = NULL;
- }
+ Object *obedit_orig = vc->obedit;
+ EditBone *ebone_active_orig = ((bArmature *)obedit_orig->data)->act_edbone;
+ if (ebone_active_orig == NULL) {
+ use_cycle = false;
}
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
if (use_cycle) {
static int last_mval[2] = {-100, -100};
-
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- if (len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) {
- do_nearest = false;
- }
+ if ((len_manhattan_v2v2_int(vc->mval, last_mval) <= WM_EVENT_CURSOR_MOTION_THRESHOLD) == 0) {
+ use_cycle = false;
}
copy_v2_v2_int(last_mval, vc->mval);
}
- else {
- if (!XRAY_ACTIVE(vc->v3d)) {
- do_nearest = true;
- }
- }
+
+ const bool do_nearest = !(XRAY_ACTIVE(vc->v3d) || use_cycle);
/* matching logic from 'mixed_bones_object_selectbuffer' */
int hits = 0;
@@ -506,87 +728,144 @@ cache_end:
/* See if there are any selected bones in this group */
if (hits > 0) {
if (hits == 1) {
- if (!(buffer[3] & BONESEL_NOSEL)) {
- best.hitresult = buffer[3];
- best.base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, best.hitresult, &best.ebone);
- }
+ result_bias.hitresult = buffer[3];
+ result_bias.base = ED_armature_base_and_ebone_from_select_buffer(
+ bases, bases_len, result_bias.hitresult, &result_bias.ebone);
}
else {
- int dep_min = 5;
+ int bias_max = INT_MIN;
+
+ /* Track Cycle Variables
+ * - Offset is always set to the active bone.
+ * - The object & bone indices subtracted by the 'offset.as_u32' value.
+ * Unsigned subtraction wrapping means we always select the next bone in the cycle.
+ */
+ struct {
+ union {
+ uint32_t as_u32;
+ struct {
+#ifdef __BIG_ENDIAN__
+ uint16_t ob;
+ uint16_t bone;
+#else
+ uint16_t bone;
+ uint16_t ob;
+#endif
+ };
+ } offset, test, best;
+ } cycle_order;
+
+ if (use_cycle) {
+ bArmature *arm = obedit_orig->data;
+ int ob_index = obedit_orig->runtime.select_id & 0xFFFF;
+ int bone_index = BLI_findindex(arm->edbo, ebone_active_orig);
+ /* Offset from the current active bone, so we cycle onto the next. */
+ cycle_order.offset.ob = ob_index;
+ cycle_order.offset.bone = bone_index;
+ /* The value of the active bone (with offset subtracted, a signal to always overwrite). */
+ cycle_order.best.as_u32 = 0;
+ }
+
for (int i = 0; i < hits; i++) {
const uint hitresult = buffer[3 + (i * 4)];
- if (!(hitresult & BONESEL_NOSEL)) {
- Base *base = NULL;
- EditBone *ebone;
- base = ED_armature_base_and_ebone_from_select_buffer(
- bases, bases_len, hitresult, &ebone);
- /* If this fails, selection code is setting the selection ID's incorrectly. */
- BLI_assert(base && ebone);
-
- int dep;
+
+ Base *base = NULL;
+ EditBone *ebone;
+ base = ED_armature_base_and_ebone_from_select_buffer(bases, bases_len, hitresult, &ebone);
+ /* If this fails, selection code is setting the selection ID's incorrectly. */
+ BLI_assert(base && ebone);
+
+ /* Prioritized selection. */
+ {
+ int bias;
/* clicks on bone points get advantage */
if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
/* but also the unselected one */
if (findunsel) {
if ((hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0) {
- dep = 1;
+ bias = 4;
}
else if ((hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0) {
- dep = 1;
+ bias = 4;
}
else {
- dep = 2;
+ bias = 3;
}
}
else {
- dep = 1;
+ bias = 4;
}
}
else {
/* bone found */
if (findunsel) {
if ((ebone->flag & BONE_SELECTED) == 0) {
- dep = 3;
+ bias = 2;
}
else {
- dep = 4;
+ bias = 1;
}
}
else {
- dep = 3;
+ bias = 2;
}
}
- if (ebone == ebone_next_act) {
- dep -= 1;
+ if (bias > bias_max) {
+ bias_max = bias;
+
+ result_bias.hitresult = hitresult;
+ result_bias.base = base;
+ result_bias.ebone = ebone;
}
+ }
- if (dep < dep_min) {
- dep_min = dep;
- best.hitresult = hitresult;
- best.base = base;
- best.ebone = ebone;
+ /* Cycle selected items (objects & bones). */
+ if (use_cycle) {
+ cycle_order.test.ob = hitresult & 0xFFFF;
+ cycle_order.test.bone = (hitresult & ~BONESEL_ANY) >> 16;
+ if (ebone == ebone_active_orig) {
+ BLI_assert(cycle_order.test.ob == cycle_order.offset.ob);
+ BLI_assert(cycle_order.test.bone == cycle_order.offset.bone);
+ }
+ /* Subtraction as a single value is needed to support cycling through bones
+ * from multiple objects. So once the last bone is selected,
+ * the bits for the bone index wrap into the object,
+ * causing the next object to be stepped onto. */
+ cycle_order.test.as_u32 -= cycle_order.offset.as_u32;
+
+ /* Even though this logic avoids stepping onto the active bone,
+ * always set the 'best' value for the first time.
+ * Otherwise ensure the value is the smallest it can be,
+ * relative to the active bone, as long as it's not the active bone. */
+ if ((cycle_order.best.as_u32 == 0) ||
+ (cycle_order.test.as_u32 && (cycle_order.test.as_u32 < cycle_order.best.as_u32))) {
+ cycle_order.best = cycle_order.test;
+ result_cycle.hitresult = hitresult;
+ result_cycle.base = base;
+ result_cycle.ebone = ebone;
}
}
}
}
- if (!(best.hitresult & BONESEL_NOSEL)) {
- *r_base = best.base;
+ result = (use_cycle && result_cycle.ebone) ? &result_cycle : &result_bias;
+
+ if (result->hitresult != -1) {
+ *r_base = result->base;
*r_selmask = 0;
- if (best.hitresult & BONESEL_ROOT) {
+ if (result->hitresult & BONESEL_ROOT) {
*r_selmask |= BONE_ROOTSEL;
}
- if (best.hitresult & BONESEL_TIP) {
+ if (result->hitresult & BONESEL_TIP) {
*r_selmask |= BONE_TIPSEL;
}
- if (best.hitresult & BONESEL_BONE) {
+ if (result->hitresult & BONESEL_BONE) {
*r_selmask |= BONE_SELECTED;
}
MEM_freeN(bases);
- return best.ebone;
+ return result->ebone;
}
}
*r_selmask = 0;
@@ -595,11 +874,17 @@ cache_end:
return NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Utility Functions
+ * \{ */
+
bool ED_armature_edit_deselect_all(Object *obedit)
{
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
changed = true;
@@ -612,7 +897,7 @@ bool ED_armature_edit_deselect_all_visible(Object *obedit)
{
bArmature *arm = obedit->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* first and foremost, bone must be visible and selected */
if (EBONE_VISIBLE(arm, ebone)) {
if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
@@ -661,17 +946,11 @@ bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
return changed_multi;
}
-/* accounts for connected parents */
-static int ebone_select_flag(EditBone *ebone)
-{
- if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
- return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) |
- (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
- }
- else {
- return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
- }
-}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Cursor Pick API
+ * \{ */
/* context: editmode armature in view3d */
bool ED_armature_edit_select_pick(
@@ -784,7 +1063,7 @@ bool ED_armature_edit_select_pick(
ED_armature_edit_sync_selection(arm->edbo);
/* then now check for active status */
- if (ebone_select_flag(nearBone)) {
+ if (ED_armature_ebone_selectflag_get(nearBone)) {
arm->act_edbone = nearBone;
}
@@ -800,6 +1079,8 @@ bool ED_armature_edit_select_pick(
return false;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Select Op From Tagged
*
@@ -893,7 +1174,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/* Initialize flags. */
{
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* Flush the parent flag to this bone
* so we don't need to check the parent when adjusting the selection. */
@@ -915,7 +1196,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
/* Apply selection from bone selection flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->temp.i != 0) {
int is_ignore_flag = ((ebone->temp.i << 16) & (BONESEL_ROOT | BONESEL_TIP));
int is_inside_flag = (ebone->temp.i & (BONESEL_ROOT | BONESEL_TIP | BONESEL_BONE));
@@ -935,7 +1216,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
if (changed) {
/* Cleanup flags. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
SWAP(int, ebone->temp.i, ebone->flag);
ebone->flag |= BONE_DONE;
@@ -948,7 +1229,7 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
}
}
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->flag & BONE_DONE) {
if ((ebone->flag & BONE_CONNECTED) && ebone->parent) {
bool is_parent_tip_changed = (ebone->parent->flag & BONE_TIPSEL) !=
@@ -984,7 +1265,9 @@ bool ED_armature_edit_select_op_from_tagged(bArmature *arm, const int sel_op)
/** \} */
-/* **************** Selections ******************/
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
static int armature_de_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1003,7 +1286,7 @@ static int armature_de_select_all_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
}
- /* Set the flags */
+ /* Set the flags. */
CTX_DATA_BEGIN (C, EditBone *, ebone, visible_bones) {
/* ignore bone if selection can't change */
switch (action) {
@@ -1063,7 +1346,11 @@ void ARMATURE_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/**************** Select more/less **************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Implementation
+ * \{ */
static void armature_select_more(bArmature *arm, EditBone *ebone)
{
@@ -1150,6 +1437,12 @@ static void armature_select_more_less(Object *ob, bool more)
ED_armature_edit_sync_selection(arm->edbo);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More Operator
+ * \{ */
+
static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1183,6 +1476,12 @@ void ARMATURE_OT_select_more(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Less Operator
+ * \{ */
+
static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1216,6 +1515,12 @@ void ARMATURE_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Similar
+ * \{ */
+
enum {
SIMEDBONE_CHILDREN = 1,
SIMEDBONE_CHILDREN_IMMEDIATE,
@@ -1270,7 +1575,7 @@ static void select_similar_length(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
const float len_iter = bone_length_squared_worldspace_get(ob, ebone);
if ((len_iter > len_min) && (len_iter < len_max)) {
@@ -1318,7 +1623,7 @@ static void select_similar_direction(bContext *C, const float thresh)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
float dir[3];
bone_direction_worldspace_get(ob, ebone, dir);
@@ -1352,7 +1657,7 @@ static void select_similar_layer(bContext *C)
bArmature *arm = ob->data;
bool changed = false;
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
if (ebone->layer & ebone_act->layer) {
ED_armature_ebone_select_set(ebone, true);
@@ -1392,7 +1697,7 @@ static void select_similar_prefix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char prefix_other[MAXBONENAME];
BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
@@ -1434,7 +1739,7 @@ static void select_similar_suffix(bContext *C)
bool changed = false;
/* Find matches */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
char suffix_other[MAXBONENAME];
BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
@@ -1469,7 +1774,7 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons
}
const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset);
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_SELECTABLE(arm, ebone)) {
const bPoseChannel *pchan = BKE_pose_channel_find_name(obedit->pose, ebone->name);
if (pchan) {
@@ -1504,11 +1809,11 @@ static void select_similar_children(bContext *C)
bArmature *arm = obedit->data;
EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
ebone_iter->temp.ebone = ebone_iter->parent;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
is_ancestor(ebone_iter, ebone_act);
if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
@@ -1526,7 +1831,7 @@ static void select_similar_children_immediate(bContext *C)
bArmature *arm = obedit->data;
EditBone *ebone_act = CTX_data_active_bone(C);
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1546,7 +1851,7 @@ static void select_similar_siblings(bContext *C)
return;
}
- for (EditBone *ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
+ LISTBASE_FOREACH (EditBone *, ebone_iter, arm->edbo) {
if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
ED_armature_ebone_select_set(ebone_iter, true);
}
@@ -1631,7 +1936,11 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
}
-/* ********************* select hierarchy operator ************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Hierarchy Operator
+ * \{ */
/* No need to convert to multi-objects. Just like we keep the non-active bones
* selected we then keep the non-active objects untouched (selected/unselected). */
@@ -1737,7 +2046,11 @@ void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Mirror Select ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Mirror Operator
+ * \{ */
/**
* \note clone of #pose_select_mirror_exec keep in sync
@@ -1822,7 +2135,11 @@ void ARMATURE_OT_select_mirror(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
-/****************** Select Path ****************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Path Operator
+ * \{ */
static bool armature_shortest_path_select(
bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child, bool use_parent, bool is_test)
@@ -1866,7 +2183,7 @@ static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const
BKE_object_update_select_id(CTX_data_main(C));
ebone_src = arm->act_edbone;
- ebone_dst = get_nearest_bone(C, event->mval, false, &base_dst);
+ ebone_dst = ED_armature_pick_ebone(C, event->mval, false, &base_dst);
/* fallback to object selection */
if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
@@ -1948,3 +2265,5 @@ void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index 87f980db7b9..61d8856afbc 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -418,7 +418,7 @@ static void add_verts_to_dgroups(ReportList *reports,
BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert);
vertsfilled = 1;
}
- else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ else if (BKE_modifiers_findby_type(ob, eModifierType_Subsurf)) {
/* is subsurf on? Lets use the verts on the limit surface then.
* = same amount of vertices as mesh, but vertices moved to the
* subsurfed position, like for 'optimal'. */
@@ -459,7 +459,7 @@ static void add_verts_to_dgroups(ReportList *reports,
}
/* only generated in some cases but can call anyway */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
/* free the memory allocated */
MEM_freeN(bonelist);
diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c
index 76361f6785b..cf7f6699e5e 100644
--- a/source/blender/editors/armature/armature_utils.c
+++ b/source/blender/editors/armature/armature_utils.c
@@ -92,7 +92,7 @@ void ED_armature_edit_validate_active(struct bArmature *arm)
void ED_armature_edit_refresh_layer_used(bArmature *arm)
{
arm->layer_used = 0;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
arm->layer_used |= ebo->layer;
}
}
@@ -142,7 +142,7 @@ void bone_free(bArmature *arm, EditBone *bone)
}
/* Clear references from other edit bones. */
- for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (ebone->bbone_next == bone) {
ebone->bbone_next = NULL;
}
@@ -196,13 +196,12 @@ bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebon
* \param ebone_child_tot: Size of the ebone_child array
* \return The shared parent or NULL.
*/
-EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[],
- const unsigned int ebone_child_tot)
+EditBone *ED_armature_ebone_find_shared_parent(EditBone *ebone_child[], const uint ebone_child_tot)
{
- unsigned int i;
+ uint i;
EditBone *ebone_iter;
-#define EBONE_TEMP_UINT(ebone) (*((unsigned int *)(&((ebone)->temp))))
+#define EBONE_TEMP_UINT(ebone) (*((uint *)(&((ebone)->temp))))
/* clear all */
for (i = 0; i < ebone_child_tot; i++) {
@@ -473,7 +472,7 @@ void ED_armature_ebone_transform_mirror_update(bArmature *arm, EditBone *ebo, bo
void ED_armature_edit_transform_mirror_update(Object *obedit)
{
bArmature *arm = obedit->data;
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
ED_armature_ebone_transform_mirror_update(arm, ebo, true);
}
}
@@ -482,10 +481,10 @@ void ED_armature_edit_transform_mirror_update(Object *obedit)
/* Armature EditMode Conversions */
/* converts Bones to EditBone list, used for tools as well */
-static EditBone *make_boneList_rec(ListBase *edbo,
- ListBase *bones,
- EditBone *parent,
- Bone *actBone)
+static EditBone *make_boneList_recursive(ListBase *edbo,
+ ListBase *bones,
+ EditBone *parent,
+ Bone *actBone)
{
EditBone *eBone;
EditBone *eBoneAct = NULL;
@@ -562,9 +561,9 @@ static EditBone *make_boneList_rec(ListBase *edbo,
BLI_addtail(edbo, eBone);
- /* Add children if necessary */
+ /* Add children if necessary. */
if (curBone->childbase.first) {
- eBoneTest = make_boneList_rec(edbo, &curBone->childbase, eBone, actBone);
+ eBoneTest = make_boneList_recursive(edbo, &curBone->childbase, eBone, actBone);
if (eBoneTest) {
eBoneAct = eBoneTest;
}
@@ -581,7 +580,7 @@ static EditBone *make_boneList_rec(ListBase *edbo,
static EditBone *find_ebone_link(ListBase *edbo, Bone *link)
{
if (link != NULL) {
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
if (ebone->temp.bone == link) {
return ebone;
}
@@ -595,9 +594,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, struct Bone *actBone)
{
BLI_assert(!edbo->first && !edbo->last);
- EditBone *active = make_boneList_rec(edbo, bones, NULL, actBone);
+ EditBone *active = make_boneList_recursive(edbo, bones, NULL, actBone);
- for (EditBone *ebone = edbo->first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, edbo) {
Bone *bone = ebone->temp.bone;
/* Convert custom B-Bone handle links. */
@@ -721,7 +720,7 @@ void ED_armature_from_edit(Main *bmain, bArmature *arm)
}
}
- /* Copy the bones from the editData into the armature */
+ /* Copy the bones from the edit-data into the armature. */
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
newBone = MEM_callocN(sizeof(Bone), "bone");
eBone->temp.bone = newBone; /* Associate the real Bones with the EditBones */
@@ -819,7 +818,7 @@ void ED_armature_edit_free(struct bArmature *arm)
{
EditBone *eBone;
- /* Clear the editbones list */
+ /* Clear the edit-bones list. */
if (arm->edbo) {
if (arm->edbo->first) {
for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c
index c73f8f69fdd..a3a73f8d509 100644
--- a/source/blender/editors/armature/editarmature_undo.c
+++ b/source/blender/editors/armature/editarmature_undo.c
@@ -29,6 +29,7 @@
#include "DNA_object_types.h"
#include "BLI_array_utils.h"
+#include "BLI_listbase.h"
#include "BKE_context.h"
#include "BKE_layer.h"
@@ -94,7 +95,7 @@ static void *undoarm_from_editarm(UndoArmature *uarm, bArmature *arm)
ED_armature_ebone_listbase_temp_clear(&uarm->lb);
- for (EditBone *ebone = uarm->lb.first; ebone; ebone = ebone->next) {
+ LISTBASE_FOREACH (EditBone *, ebone, &uarm->lb) {
uarm->undo_size += sizeof(EditBone);
}
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 6028ddb216f..d8a6a22a7df 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -1549,7 +1549,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind
}
}
else {
- modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)");
+ BKE_modifier_set_error(&mmd->modifier, "Failed to find bind solution (increase precision?)");
error("Mesh Deform: failed to find bind solution.");
break;
}
@@ -1753,7 +1753,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
int totvert,
float cagemat[4][4])
{
- MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifier_get_original(
+ MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)BKE_modifier_get_original(
&mmd->modifier);
MeshDeformBind mdb;
MVert *mvert;
@@ -1799,7 +1799,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd,
MEM_freeN(mdb.vertexcos);
/* compact weights */
- modifier_mdef_compact_influences((ModifierData *)mmd_orig);
+ BKE_modifier_mdef_compact_influences((ModifierData *)mmd_orig);
end_progress_bar();
waitcursor(0);
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 09b6cd9c8cc..0cd3afc9cf9 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -33,7 +33,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_deform.h"
@@ -75,12 +75,12 @@
/* matches logic with ED_operator_posemode_context() */
Object *ED_pose_object_from_context(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob;
/* Since this call may also be used from the buttons window,
* we need to check for where to get the object. */
- if (sa && sa->spacetype == SPACE_PROPERTIES) {
+ if (area && area->spacetype == SPACE_PROPERTIES) {
ob = ED_object_context(C);
}
else {
@@ -665,6 +665,11 @@ static int pose_bone_rotmode_exec(bContext *C, wmOperator *op)
/* set rotation mode of selected bones */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, selected_pose_bones, Object *, ob) {
+ /* use API Method for conversions... */
+ BKE_rotMode_change_values(
+ pchan->quat, pchan->eul, pchan->rotAxis, &pchan->rotAngle, pchan->rotmode, (short)mode);
+
+ /* finally, set the new rotation type */
pchan->rotmode = mode;
if (prev_ob != ob) {
@@ -901,8 +906,6 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op)
RNA_boolean_set_array(&ptr, "layers", layers);
if (prev_ob != ob) {
- BKE_armature_refresh_layer_used(ob->data);
-
/* Note, notifier might evolve. */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE);
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 9cd87f476d4..c10e204e3a4 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -44,6 +44,7 @@
#include "WM_types.h"
#include "ED_armature.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "UI_interface.h"
@@ -484,6 +485,7 @@ static int pose_group_select_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
@@ -518,6 +520,7 @@ static int pose_group_deselect_exec(bContext *C, wmOperator *UNUSED(op))
bArmature *arm = ob->data;
DEG_id_tag_update(&arm->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ ED_outliner_select_sync_from_pose_bone_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index f759808d08e..aa57fb5844d 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -161,16 +161,16 @@ static TimeMarker *poselib_get_active_pose(bAction *act)
/* XXX C can be zero */
static Object *get_poselib_object(bContext *C)
{
- ScrArea *sa;
+ ScrArea *area;
/* sanity check */
if (C == NULL) {
return NULL;
}
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_PROPERTIES)) {
+ if (area && (area->spacetype == SPACE_PROPERTIES)) {
return ED_object_context(C);
}
else {
@@ -626,7 +626,7 @@ static int poselib_remove_exec(bContext *C, wmOperator *op)
/* remove relevant keyframes */
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
BezTriple *bezt;
- unsigned int i;
+ uint i;
if (fcu->bezt) {
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
@@ -870,7 +870,7 @@ typedef struct tPoseLib_PreviewData {
/** active scene. */
Scene *scene;
/** active area. */
- ScrArea *sa;
+ ScrArea *area;
/** RNA-Pointer to Object 'ob' .*/
PointerRNA rna_ptr;
@@ -1171,7 +1171,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
/* do header print - if interactively previewing */
if (pld->state == PL_PREVIEW_RUNNING) {
if (pld->flag & PL_PREVIEW_SHOWORIGINAL) {
- ED_area_status_text(pld->sa, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
+ ED_area_status_text(pld->area, TIP_("PoseLib Previewing Pose: [Showing Original Pose]"));
ED_workspace_status_text(C, TIP_("Use Tab to start previewing poses again"));
}
else if (pld->searchstr[0]) {
@@ -1200,7 +1200,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
"Current Pose - \"%s\""),
tempstr,
markern);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, TIP_("Use ScrollWheel or PageUp/Down to change pose"));
}
else {
@@ -1208,7 +1208,7 @@ static void poselib_preview_apply(bContext *C, wmOperator *op)
sizeof(pld->headerstr),
TIP_("PoseLib Previewing Pose: \"%s\""),
pld->marker->name);
- ED_area_status_text(pld->sa, pld->headerstr);
+ ED_area_status_text(pld->area, pld->headerstr);
ED_workspace_status_text(C, NULL);
}
}
@@ -1323,9 +1323,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
}
/* specially handle events for searching */
-static void poselib_preview_handle_search(tPoseLib_PreviewData *pld,
- unsigned short event,
- char ascii)
+static void poselib_preview_handle_search(tPoseLib_PreviewData *pld, ushort event, char ascii)
{
/* try doing some form of string manipulation first */
switch (event) {
@@ -1633,7 +1631,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op)
pld->act = (ob) ? (ob->poselib) : NULL;
pld->scene = CTX_data_scene(C);
- pld->sa = CTX_wm_area(C);
+ pld->area = CTX_wm_area(C);
/* get starting pose based on RNA-props for this operator */
if (pose_index == -1) {
@@ -1704,7 +1702,7 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
TimeMarker *marker = pld->marker;
/* redraw the header so that it doesn't show any of our stuff anymore */
- ED_area_status_text(pld->sa, NULL);
+ ED_area_status_text(pld->area, NULL);
ED_workspace_status_text(C, NULL);
/* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 07be2baf1ae..9525fcf2154 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -141,7 +141,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
View3D *v3d,
Base *base,
- const unsigned int *buffer,
+ const uint *buffer,
short hits,
bool extend,
bool deselect,
@@ -156,12 +156,12 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer,
}
Object *ob_act = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL);
/* Callers happen to already get the active base */
Base *base_dummy = NULL;
- nearBone = get_bone_from_selectbuffer(
- &base, 1, obedit != NULL, buffer, hits, 1, do_nearest, &base_dummy);
+ nearBone = ED_armature_pick_bone_from_selectbuffer(
+ &base, 1, buffer, hits, 1, do_nearest, &base_dummy);
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
@@ -263,7 +263,7 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se
Object *ob_active = OBACT(view_layer);
BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT));
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob_active, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -323,7 +323,7 @@ bool ED_pose_deselect_all(Object *ob, int select_mode, const bool ignore_visibil
static bool ed_pose_is_any_selected(Object *ob, bool ignore_visibility)
{
bArmature *arm = ob->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
return true;
@@ -413,7 +413,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
view3d_operator_needs_opengl(C);
Base *base = NULL;
- bone = get_nearest_bone(C, event->mval, !extend, &base);
+ bone = ED_armature_pick_bone(C, event->mval, !extend, &base);
if (!bone) {
return OPERATOR_CANCELLED;
@@ -443,7 +443,7 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
}
/* Select children */
- for (curBone = bone->childbase.first; curBone; curBone = next) {
+ for (curBone = bone->childbase.first; curBone; curBone = curBone->next) {
selectconnected_posebonechildren(base->object, curBone, extend);
}
@@ -454,22 +454,22 @@ static int pose_select_connected_invoke(bContext *C, wmOperator *op, const wmEve
return OPERATOR_FINISHED;
}
-static bool pose_select_linked_poll(bContext *C)
+static bool pose_select_linked_pick_poll(bContext *C)
{
return (ED_operator_view3d_active(C) && ED_operator_posemode(C));
}
-void POSE_OT_select_linked(wmOperatorType *ot)
+void POSE_OT_select_linked_pick(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Connected";
- ot->idname = "POSE_OT_select_linked";
- ot->description = "Select bones related to selected ones by parent/child relationships";
+ ot->idname = "POSE_OT_select_linked_pick";
+ ot->description = "Select bones linked by parent/child connections under the mouse cursor";
/* callbacks */
/* leave 'exec' unset */
ot->invoke = pose_select_connected_invoke;
- ot->poll = pose_select_linked_poll;
+ ot->poll = pose_select_linked_pick_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -482,6 +482,62 @@ void POSE_OT_select_linked(wmOperatorType *ot)
"Extend selection instead of deselecting everything first");
}
+static int pose_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Bone *curBone, *next = NULL;
+
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
+ if ((pchan->bone->flag & BONE_SELECTED) == 0) {
+ continue;
+ }
+
+ bArmature *arm = ob->data;
+
+ /* Select parents */
+ for (curBone = pchan->bone; curBone; curBone = next) {
+ if (PBONE_SELECTABLE(arm, curBone)) {
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED) {
+ next = curBone->parent;
+ }
+ else {
+ next = NULL;
+ }
+ }
+ else {
+ next = NULL;
+ }
+ }
+
+ /* Select children */
+ for (curBone = pchan->bone->childbase.first; curBone; curBone = curBone->next) {
+ selectconnected_posebonechildren(ob, curBone, false);
+ }
+ ED_pose_bone_select_tag_update(ob);
+ }
+ CTX_DATA_END;
+
+ ED_outliner_select_sync_from_pose_bone_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void POSE_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Connected";
+ ot->idname = "POSE_OT_select_linked";
+ ot->description = "Select all bones linked by parent/child connections to the current selection";
+
+ /* callbacks */
+ ot->exec = pose_select_linked_exec;
+ ot->poll = ED_operator_posemode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/* -------------------------------------- */
static int pose_de_select_all_exec(bContext *C, wmOperator *op)
@@ -497,7 +553,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
Object *ob_prev = NULL;
- /* Set the flags */
+ /* Set the flags. */
CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, pchan, visible_pose_bones, Object *, ob) {
bArmature *arm = ob->data;
pose_do_bone_select(pchan, action);
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 336d09f71b5..d9621dba730 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -86,7 +86,7 @@ typedef struct tPoseSlideOp {
/** current scene */
Scene *scene;
/** area that we're operating in (needed for modal()) */
- ScrArea *sa;
+ ScrArea *area;
/** region that we're operating in (needed for modal()) */
ARegion *region;
/** len of the PoseSlideObject array. */
@@ -197,7 +197,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, ePoseSlide_Modes mode)
/* get info from context */
pso->scene = CTX_data_scene(C);
- pso->sa = CTX_wm_area(C); /* only really needed when doing modal() */
+ pso->area = CTX_wm_area(C); /* only really needed when doing modal() */
pso->region = CTX_wm_region(C); /* only really needed when doing modal() */
pso->cframe = pso->scene->r.cfra;
@@ -544,71 +544,56 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl)
/* only if all channels exist, proceed */
if (fcu_w && fcu_x && fcu_y && fcu_z) {
- float quat_prev[4], quat_prev_orig[4];
- float quat_next[4], quat_next_orig[4];
- float quat_curr[4], quat_curr_orig[4];
float quat_final[4];
- copy_qt_qt(quat_curr_orig, pchan->quat);
-
- /* get 2 quats */
- quat_prev_orig[0] = evaluate_fcurve(fcu_w, prevFrameF);
- quat_prev_orig[1] = evaluate_fcurve(fcu_x, prevFrameF);
- quat_prev_orig[2] = evaluate_fcurve(fcu_y, prevFrameF);
- quat_prev_orig[3] = evaluate_fcurve(fcu_z, prevFrameF);
-
- quat_next_orig[0] = evaluate_fcurve(fcu_w, nextFrameF);
- quat_next_orig[1] = evaluate_fcurve(fcu_x, nextFrameF);
- quat_next_orig[2] = evaluate_fcurve(fcu_y, nextFrameF);
- quat_next_orig[3] = evaluate_fcurve(fcu_z, nextFrameF);
-
- normalize_qt_qt(quat_prev, quat_prev_orig);
- normalize_qt_qt(quat_next, quat_next_orig);
- normalize_qt_qt(quat_curr, quat_curr_orig);
-
/* perform blending */
if (pso->mode == POSESLIDE_BREAKDOWN) {
/* Just perform the interpolation between quat_prev and
* quat_next using pso->percentage as a guide. */
- interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
- }
- else if (pso->mode == POSESLIDE_PUSH) {
- float quat_diff[4];
+ float quat_prev[4];
+ float quat_next[4];
+
+ quat_prev[0] = evaluate_fcurve(fcu_w, prevFrameF);
+ quat_prev[1] = evaluate_fcurve(fcu_x, prevFrameF);
+ quat_prev[2] = evaluate_fcurve(fcu_y, prevFrameF);
+ quat_prev[3] = evaluate_fcurve(fcu_z, prevFrameF);
- /* calculate the delta transform from the previous to the current */
- /* TODO: investigate ways to favor one transform more? */
- sub_qt_qtqt(quat_diff, quat_curr, quat_prev);
+ quat_next[0] = evaluate_fcurve(fcu_w, nextFrameF);
+ quat_next[1] = evaluate_fcurve(fcu_x, nextFrameF);
+ quat_next[2] = evaluate_fcurve(fcu_y, nextFrameF);
+ quat_next[3] = evaluate_fcurve(fcu_z, nextFrameF);
- /* increase the original by the delta transform, by an amount determined by percentage */
- add_qt_qtqt(quat_final, quat_curr, quat_diff, pso->percentage);
+ normalize_qt(quat_prev);
+ normalize_qt(quat_next);
- normalize_qt(quat_final);
+ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage);
}
else {
- BLI_assert(pso->mode == POSESLIDE_RELAX);
- float quat_interp[4], quat_final_prev[4];
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
+ /* POSESLIDE_PUSH and POSESLIDE_RELAX. */
+ float quat_breakdown[4];
+ float quat_curr[4];
- copy_qt_qt(quat_final, quat_curr);
+ copy_qt_qt(quat_curr, pchan->quat);
- /* perform this blending several times until a satisfactory result is reached */
- while (iters-- > 0) {
- /* calculate the interpolation between the endpoints */
- interp_qt_qtqt(quat_interp,
- quat_prev,
- quat_next,
- (cframe - pso->prevFrame) / (pso->nextFrame - pso->prevFrame));
+ quat_breakdown[0] = evaluate_fcurve(fcu_w, cframe);
+ quat_breakdown[1] = evaluate_fcurve(fcu_x, cframe);
+ quat_breakdown[2] = evaluate_fcurve(fcu_y, cframe);
+ quat_breakdown[3] = evaluate_fcurve(fcu_z, cframe);
- normalize_qt_qt(quat_final_prev, quat_final);
+ normalize_qt(quat_breakdown);
+ normalize_qt(quat_curr);
- /* tricky interpolations - blending between original and new */
- interp_qt_qtqt(quat_final, quat_final_prev, quat_interp, 1.0f / 6.0f);
+ if (pso->mode == POSESLIDE_PUSH) {
+ interp_qt_qtqt(quat_final, quat_breakdown, quat_curr, 1.0f + pso->percentage);
+ }
+ else {
+ BLI_assert(pso->mode == POSESLIDE_RELAX);
+ interp_qt_qtqt(quat_final, quat_curr, quat_breakdown, pso->percentage);
}
}
/* Apply final to the pose bone, keeping compatible for similar keyframe positions. */
- quat_to_compatible_quat(pchan->quat, quat_final, quat_curr_orig);
+ quat_to_compatible_quat(pchan->quat, quat_final, pchan->quat);
}
/* free the path now */
@@ -904,7 +889,7 @@ static void pose_slide_draw_status(tPoseSlideOp *pso)
limits_str);
}
- ED_area_status_text(pso->sa, status_str);
+ ED_area_status_text(pso->area, status_str);
}
/* common code for invoke() methods */
@@ -1071,7 +1056,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case EVT_PADENTER: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* insert keyframes as required... */
@@ -1088,7 +1073,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
case RIGHTMOUSE: {
if (event->val == KM_PRESS) {
/* return to normal cursor and header status */
- ED_area_status_text(pso->sa, NULL);
+ ED_area_status_text(pso->area, NULL);
WM_cursor_modal_restore(win);
/* reset transforms back to original state */
@@ -1254,51 +1239,60 @@ static int pose_slide_exec_common(bContext *C, wmOperator *op, tPoseSlideOp *pso
return OPERATOR_FINISHED;
}
-/* common code for defining RNA properties */
-/* TODO: Skip save on these? */
+/**
+ * Common code for defining RNA properties.
+ */
static void pose_slide_opdef_properties(wmOperatorType *ot)
{
- RNA_def_float_percentage(ot->srna,
- "percentage",
- 0.5f,
- 0.0f,
- 1.0f,
- "Percentage",
- "Weighting factor for which keyframe is favored more",
- 0.0,
- 1.0);
-
- RNA_def_int(ot->srna,
- "prev_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Previous Keyframe",
- "Frame number of keyframe immediately before the current frame",
- 0,
- 50);
- RNA_def_int(ot->srna,
- "next_frame",
- 0,
- MINAFRAME,
- MAXFRAME,
- "Next Keyframe",
- "Frame number of keyframe immediately after the current frame",
- 0,
- 50);
-
- RNA_def_enum(ot->srna,
- "channels",
- prop_channels_types,
- PS_TFM_ALL,
- "Channels",
- "Set of properties that are affected");
- RNA_def_enum(ot->srna,
- "axis_lock",
- prop_axis_lock_types,
- 0,
- "Axis Lock",
- "Transform axis to restrict effects to");
+ PropertyRNA *prop;
+
+ prop = RNA_def_float_percentage(ot->srna,
+ "percentage",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Percentage",
+ "Weighting factor for which keyframe is favored more",
+ 0.0,
+ 1.0);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "prev_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Previous Keyframe",
+ "Frame number of keyframe immediately before the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_int(ot->srna,
+ "next_frame",
+ 0,
+ MINAFRAME,
+ MAXFRAME,
+ "Next Keyframe",
+ "Frame number of keyframe immediately after the current frame",
+ 0,
+ 50);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna,
+ "channels",
+ prop_channels_types,
+ PS_TFM_ALL,
+ "Channels",
+ "Set of properties that are affected");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna,
+ "axis_lock",
+ prop_axis_lock_types,
+ 0,
+ "Axis Lock",
+ "Transform axis to restrict effects to");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ------------------------------------ */
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index fe79894a351..1d2bf152777 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -207,12 +207,12 @@ typedef struct ApplyArmature_ParentState {
} ApplyArmature_ParentState;
/* Recursive walk for Apply To Selected mode; pstate NULL unless child of an applied bone. */
-static void applyarmature_process_selected_rec(bArmature *arm,
- bPose *pose,
- bPose *pose_eval,
- Bone *bone,
- ListBase *selected,
- ApplyArmature_ParentState *pstate)
+static void applyarmature_process_selected_recursive(bArmature *arm,
+ bPose *pose,
+ bPose *pose_eval,
+ Bone *bone,
+ ListBase *selected,
+ ApplyArmature_ParentState *pstate)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(pose, bone->name);
const bPoseChannel *pchan_eval = BKE_pose_channel_find_name(pose_eval, bone->name);
@@ -333,8 +333,8 @@ static void applyarmature_process_selected_rec(bArmature *arm,
pstate = &new_pstate;
}
- for (Bone *child = bone->childbase.first; child; child = child->next) {
- applyarmature_process_selected_rec(arm, pose, pose_eval, child, selected, pstate);
+ LISTBASE_FOREACH (Bone *, child, &bone->childbase) {
+ applyarmature_process_selected_recursive(arm, pose, pose_eval, child, selected, pstate);
}
}
@@ -389,8 +389,9 @@ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op)
if (use_selected) {
/* The selected only mode requires a recursive walk to handle parent-child relations. */
- for (Bone *bone = arm->bonebase.first; bone; bone = bone->next) {
- applyarmature_process_selected_rec(arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
+ LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) {
+ applyarmature_process_selected_recursive(
+ arm, pose, ob_eval->pose, bone, &selected_bones, NULL);
}
BLI_freelistN(&selected_bones);
@@ -1239,7 +1240,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op)
workob.adt = ob->adt;
workob.pose = dummyPose;
- BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata(&workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false);
/* copy back values, but on selected bones only */
for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) {
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index efb568178d9..e2038bdd2a3 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -32,7 +32,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt
index 8c9309055c8..ff80c47baa8 100644
--- a/source/blender/editors/curve/CMakeLists.txt
+++ b/source/blender/editors/curve/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
editcurve.c
editcurve_add.c
editcurve_paint.c
+ editcurve_query.c
editcurve_select.c
editcurve_undo.c
editfont.c
diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h
index 201ba2560dc..7d0a2e5edbc 100644
--- a/source/blender/editors/curve/curve_intern.h
+++ b/source/blender/editors/curve/curve_intern.h
@@ -142,14 +142,6 @@ void CURVE_OT_match_texture_space(struct wmOperatorType *ot);
struct GHash *ED_curve_keyindex_hash_duplicate(struct GHash *keyindex);
void ED_curve_keyindex_update_nurb(struct EditNurb *editnurb, struct Nurb *nu, struct Nurb *newnu);
-bool ED_curve_pick_vert(struct ViewContext *vc,
- short sel,
- struct Nurb **r_nurb,
- struct BezTriple **r_bezt,
- struct BPoint **r_bp,
- short *r_handle,
- struct Base **r_base);
-
/* helper functions */
void ed_editnurb_translate_flag(struct ListBase *editnurb, short flag, const float vec[3]);
bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const short flag);
@@ -189,6 +181,17 @@ void SURFACE_OT_primitive_nurbs_surface_cylinder_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_sphere_add(struct wmOperatorType *ot);
void SURFACE_OT_primitive_nurbs_surface_torus_add(struct wmOperatorType *ot);
+/* editcurve_query.c */
+bool ED_curve_pick_vert(struct ViewContext *vc,
+ short sel,
+ struct Nurb **r_nurb,
+ struct BezTriple **r_bezt,
+ struct BPoint **r_bp,
+ short *r_handle,
+ struct Base **r_base);
+void ED_curve_nurb_vert_selected_find(
+ Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp);
+
/* editcurve_paint.c */
void CURVE_OT_draw(struct wmOperatorType *ot);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 2911611c516..4e1c07af001 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -36,7 +36,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -58,6 +58,7 @@
#include "ED_curve.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
@@ -81,6 +82,10 @@ static void adduplicateflagNurb(
static bool curve_delete_segments(Object *obedit, View3D *v3d, const bool split);
static bool curve_delete_vertices(Object *obedit, View3D *v3d);
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
+
ListBase *object_editcurve_get(Object *ob)
{
if (ob && ELEM(ob->type, OB_CURVE, OB_SURF)) {
@@ -90,7 +95,11 @@ ListBase *object_editcurve_get(Object *ob)
return NULL;
}
-/* ******************* PRINTS ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Debug Printing
+ * \{ */
#if 0
void printknots(Object *obedit)
@@ -118,7 +127,11 @@ void printknots(Object *obedit)
}
#endif
-/* ********************* Shape keys *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shape keys
+ * \{ */
static CVKeyIndex *init_cvKeyIndex(
void *cv, int key_index, int nu_index, int pt_index, int vertex_index)
@@ -897,7 +910,11 @@ static void calc_shapeKeys(Object *obedit, ListBase *newnurbs)
}
}
-/* ********************* Amimation data *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Data
+ * \{ */
static bool curve_is_animated(Curve *cu)
{
@@ -919,13 +936,13 @@ static void fcurve_path_rename(AnimData *adt,
nextfcu = fcu->next;
if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
char *spath, *suffix = fcu->rna_path + len;
- nfcu = copy_fcurve(fcu);
+ nfcu = BKE_fcurve_copy(fcu);
spath = nfcu->rna_path;
nfcu->rna_path = BLI_sprintfN("%s%s", rna_path, suffix);
- /* copy_fcurve() sets nfcu->grp to NULL. To maintain the groups, we need to keep the pointer.
- * As a result, the group's 'channels' pointers will be wrong, which is fixed by calling
- * `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
+ /* BKE_fcurve_copy() sets nfcu->grp to NULL. To maintain the groups, we need to keep the
+ * pointer. As a result, the group's 'channels' pointers will be wrong, which is fixed by
+ * calling `action_groups_reconstruct(action)` later, after all fcurves have been renamed. */
nfcu->grp = fcu->grp;
BLI_addtail(curves, nfcu);
@@ -939,7 +956,7 @@ static void fcurve_path_rename(AnimData *adt,
BLI_remlink(&adt->drivers, fcu);
}
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
MEM_freeN(spath);
}
@@ -955,7 +972,7 @@ static void fcurve_remove(AnimData *adt, ListBase *orig_curves, FCurve *fcu)
action_groups_remove_channel(adt->action, fcu);
}
- free_fcurve(fcu);
+ BKE_fcurve_free(fcu);
}
static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
@@ -1114,7 +1131,11 @@ int ED_curve_updateAnimPaths(Main *bmain, Curve *cu)
return 1;
}
-/* ********************* LOAD and MAKE *************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Edit Mode Conversion (Make & Load)
+ * \{ */
static int *initialize_index_map(Object *obedit, int *r_old_totvert)
{
@@ -1354,7 +1375,11 @@ void ED_curve_editnurb_free(Object *obedit)
BKE_curve_editNurb_free(cu);
}
-/******************** separate operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Separate Operator
+ * \{ */
static int separate_exec(bContext *C, wmOperator *op)
{
@@ -1476,6 +1501,8 @@ static int separate_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
@@ -1495,7 +1522,11 @@ void CURVE_OT_separate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** split operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Split Operator
+ * \{ */
static int curve_split_exec(bContext *C, wmOperator *op)
{
@@ -1563,7 +1594,11 @@ void CURVE_OT_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* FLAGS ********************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Flag Utility Functions
+ * \{ */
static bool isNurbselUV(const Nurb *nu, int flag, int *r_u, int *r_v)
{
@@ -2532,7 +2567,11 @@ static void adduplicateflagNurb(
}
}
-/**************** switch direction operator ***************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Switch Direction Operator
+ * \{ */
static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2591,7 +2630,11 @@ void CURVE_OT_switch_direction(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/****************** set weight operator *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Weight Operator
+ * \{ */
static int set_goal_weight_exec(bContext *C, wmOperator *op)
{
@@ -2654,7 +2697,11 @@ void CURVE_OT_spline_weight_set(wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "weight", 1.0f, 0.0f, 1.0f, "Weight", "", 0.0f, 1.0f);
}
-/******************* set radius operator ******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Radius Operator
+ * \{ */
static int set_radius_exec(bContext *C, wmOperator *op)
{
@@ -2718,7 +2765,11 @@ void CURVE_OT_radius_set(wmOperatorType *ot)
ot->srna, "radius", 1.0f, 0.0f, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.0001f, 10.0f);
}
-/********************* smooth operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Vertices Operator
+ * \{ */
static void smooth_single_bezt(BezTriple *bezt,
const BezTriple *bezt_orig_prev,
@@ -2875,12 +2926,15 @@ void CURVE_OT_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/* Smooth radius/weight/tilt
+/** \name Smooth Operator (Radius/Weight/Tilt) Utilities
*
- * TODO: make smoothing distance based
- * TODO: support cyclic curves
- */
+ * To do:
+ * - Make smoothing distance based.
+ * - Support cyclic curves.
+ * \{ */
static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, const int bp_offset)
{
@@ -3059,6 +3113,12 @@ static void curve_smooth_value(ListBase *editnurb, const int bezt_offsetof, cons
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Weight Operator
+ * \{ */
+
static int curve_smooth_weight_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3096,6 +3156,12 @@ void CURVE_OT_smooth_weight(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Radius Operator
+ * \{ */
+
static int curve_smooth_radius_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3133,6 +3199,12 @@ void CURVE_OT_smooth_radius(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Tilt Operator
+ * \{ */
+
static int curve_smooth_tilt_exec(bContext *C, wmOperator *UNUSED(op))
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -3170,7 +3242,11 @@ void CURVE_OT_smooth_tilt(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** hide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static int hide_exec(bContext *C, wmOperator *op)
{
@@ -3269,7 +3345,11 @@ void CURVE_OT_hide(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
-/********************** reveal operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reveal Operator
+ * \{ */
static int reveal_exec(bContext *C, wmOperator *op)
{
@@ -3345,7 +3425,11 @@ void CURVE_OT_reveal(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
-/********************** subdivide operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Subdivide Operator
+ * \{ */
/**
* Divide the line segments associated with the currently selected
@@ -3508,6 +3592,7 @@ static void subdividenurb(Object *obedit, View3D *v3d, int number_cuts)
memcpy(bpn, nextbp, sizeof(BPoint));
interp_v4_v4v4(bpn->vec, bp->vec, nextbp->vec, factor);
+ bpn->radius = interpf(bp->radius, nextbp->radius, factor);
bpn++;
}
}
@@ -3800,179 +3885,11 @@ void CURVE_OT_subdivide(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** find nearest ************************/
+/** \} */
-static void ED_curve_pick_vert__doClosest(
- void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2])
-{
- struct {
- BPoint *bp;
- BezTriple *bezt;
- Nurb *nurb;
- float dist;
- int hpoint, select;
- float mval_fl[2];
- bool is_changed;
- } *data = userData;
-
- short flag;
- float dist_test;
-
- if (bp) {
- flag = bp->f1;
- }
- else {
- if (beztindex == 0) {
- flag = bezt->f1;
- }
- else if (beztindex == 1) {
- flag = bezt->f2;
- }
- else {
- flag = bezt->f3;
- }
- }
-
- dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
- if ((flag & SELECT) == data->select) {
- dist_test += 5.0f;
- }
- if (bezt && beztindex == 1) {
- dist_test += 3.0f; /* middle points get a small disadvantage */
- }
-
- if (dist_test < data->dist) {
- data->dist = dist_test;
-
- data->bp = bp;
- data->bezt = bezt;
- data->nurb = nu;
- data->hpoint = bezt ? beztindex : 0;
- data->is_changed = true;
- }
-}
-
-bool ED_curve_pick_vert(ViewContext *vc,
- short sel,
- Nurb **r_nurb,
- BezTriple **r_bezt,
- BPoint **r_bp,
- short *r_handle,
- Base **r_base)
-{
- /* (sel == 1): selected gets a disadvantage */
- /* in nurb and bezt or bp the nearest is written */
- /* return 0 1 2: handlepunt */
- struct {
- BPoint *bp;
- BezTriple *bezt;
- Nurb *nurb;
- float dist;
- int hpoint, select;
- float mval_fl[2];
- bool is_changed;
- } data = {NULL};
-
- data.dist = ED_view3d_select_dist_px();
- data.hpoint = 0;
- data.select = sel;
- data.mval_fl[0] = vc->mval[0];
- data.mval_fl[1] = vc->mval[1];
-
- uint bases_len;
- Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
- vc->view_layer, vc->v3d, &bases_len);
- for (uint base_index = 0; base_index < bases_len; base_index++) {
- Base *base = bases[base_index];
- data.is_changed = false;
-
- ED_view3d_viewcontext_init_object(vc, base->object);
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- nurbs_foreachScreenVert(vc, ED_curve_pick_vert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
-
- if (r_base && data.is_changed) {
- *r_base = base;
- }
- }
- MEM_freeN(bases);
-
- *r_nurb = data.nurb;
- *r_bezt = data.bezt;
- *r_bp = data.bp;
-
- if (r_handle) {
- *r_handle = data.hpoint;
- }
-
- return (data.bezt || data.bp);
-}
-
-static void findselectedNurbvert(
- Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
-{
- /* in nu and (bezt or bp) selected are written if there's 1 sel. */
- /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
- ListBase *editnurb = &cu->editnurb->nurbs;
- Nurb *nu1;
- BezTriple *bezt1;
- BPoint *bp1;
- int a;
-
- *r_nu = NULL;
- *r_bezt = NULL;
- *r_bp = NULL;
-
- for (nu1 = editnurb->first; nu1; nu1 = nu1->next) {
- if (nu1->type == CU_BEZIER) {
- bezt1 = nu1->bezt;
- a = nu1->pntsu;
- while (a--) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1)) {
- if (*r_nu != NULL && *r_nu != nu1) {
- *r_nu = NULL;
- *r_bp = NULL;
- *r_bezt = NULL;
- return;
- }
- else if (*r_bezt || *r_bp) {
- *r_bp = NULL;
- *r_bezt = NULL;
- }
- else {
- *r_bezt = bezt1;
- *r_nu = nu1;
- }
- }
- bezt1++;
- }
- }
- else {
- bp1 = nu1->bp;
- a = nu1->pntsu * nu1->pntsv;
- while (a--) {
- if (bp1->f1 & SELECT) {
- if (*r_nu != NULL && *r_nu != nu1) {
- *r_bp = NULL;
- *r_bezt = NULL;
- *r_nu = NULL;
- return;
- }
- else if (*r_bezt || *r_bp) {
- *r_bp = NULL;
- *r_bezt = NULL;
- }
- else {
- *r_bp = bp1;
- *r_nu = nu1;
- }
- }
- bp1++;
- }
- }
- }
-}
-
-/***************** set spline type operator *******************/
+/* -------------------------------------------------------------------- */
+/** \name Set Spline Type Operator
+ * \{ */
static int set_spline_type_exec(bContext *C, wmOperator *op)
{
@@ -4069,7 +3986,11 @@ void CURVE_OT_spline_type_set(wmOperatorType *ot)
"Use handles when converting bezier curves into polygons");
}
-/***************** set handle type operator *******************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Handle Type Operator
+ * \{ */
static int set_handle_type_exec(bContext *C, wmOperator *op)
{
@@ -4127,7 +4048,11 @@ void CURVE_OT_handle_type_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
}
-/***************** recalculate handles operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Recalculate Handles Operator
+ * \{ */
static int curve_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
@@ -4175,9 +4100,13 @@ void CURVE_OT_normals_make_consistent(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "calc_length", false, "Length", "Recalculate handle length");
}
-/***************** make segment operator **********************/
+/** \} */
-/* ******************** SKINNING LOFTING!!! ******************** */
+/* -------------------------------------------------------------------- */
+/** \name Make Segment Operator
+ *
+ * Also handles skinning & lofting.
+ * \{ */
static void switchdirection_knots(float *base, int tot)
{
@@ -4271,10 +4200,7 @@ typedef struct NurbSort {
float vec[3];
} NurbSort;
-static ListBase nsortbase = {NULL, NULL};
-/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
-
-static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
+static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb, ListBase *nsortbase)
{
ListBase nbase = {NULL, NULL};
NurbSort *nus, *nustest, *headdo, *taildo;
@@ -4303,7 +4229,7 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
/* just add the first one */
nus = nbase.first;
BLI_remlink(&nbase, nus);
- BLI_addtail(&nsortbase, nus);
+ BLI_addtail(nsortbase, nus);
/* now add, either at head or tail, the closest one */
while (nbase.first) {
@@ -4313,13 +4239,13 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
nustest = nbase.first;
while (nustest) {
- dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
+ dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->first)->vec);
if (dist < headdist) {
headdist = dist;
headdo = nustest;
}
- dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
+ dist = len_v3v3(nustest->vec, ((NurbSort *)nsortbase->last)->vec);
if (dist < taildist) {
taildist = dist;
@@ -4330,11 +4256,11 @@ static void make_selection_list_nurb(View3D *v3d, ListBase *editnurb)
if (headdist < taildist) {
BLI_remlink(&nbase, headdo);
- BLI_addhead(&nsortbase, headdo);
+ BLI_addhead(nsortbase, headdo);
}
else {
BLI_remlink(&nbase, taildo);
- BLI_addtail(&nsortbase, taildo);
+ BLI_addtail(nsortbase, taildo);
}
}
}
@@ -4511,8 +4437,9 @@ static int merge_nurb(View3D *v3d, Object *obedit)
ListBase *editnurb = object_editcurve_get(obedit);
NurbSort *nus1, *nus2;
bool ok = true;
+ ListBase nsortbase = {NULL, NULL};
- make_selection_list_nurb(v3d, editnurb);
+ make_selection_list_nurb(v3d, editnurb, &nsortbase);
if (nsortbase.first == nsortbase.last) {
BLI_freelistN(&nsortbase);
@@ -4877,7 +4804,11 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/***************** pick select from 3d view **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pick Select from 3D View
+ * \{ */
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
@@ -4992,7 +4923,7 @@ bool ED_curve_editnurb_select_pick(
}
}
else {
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
if (bezt) {
@@ -5033,7 +4964,11 @@ bool ED_curve_editnurb_select_pick(
return false;
}
-/******************** spin operator ***********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Spin Operator
+ * \{ */
/* 'cent' is in object space and 'dvec' in worldspace.
*/
@@ -5213,13 +5148,14 @@ void CURVE_OT_spin(wmOperatorType *ot)
ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
-/***************** extrude vertex operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Vertex Operator
+ * \{ */
static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
{
- Nurb *nu = NULL;
- Nurb *nu_last = NULL;
-
bool changed = false;
Nurb *cu_actnu;
@@ -5234,216 +5170,238 @@ static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb, View3D *v3d)
}
BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
- BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
-
- /* first pass (endpoints) */
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
-
- if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
- continue;
- }
+ int act_offset = 0;
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
+ BLI_assert(nu->pntsu > 0);
+ int i;
+ int pnt_len = nu->pntsu;
+ int new_points = 0;
+ int offset = 0;
+ bool is_prev_selected = false;
+ bool duplic_first = false;
+ bool duplic_last = false;
if (nu->type == CU_BEZIER) {
-
- /* Check to see if the first bezier point is selected */
- if (nu->pntsu > 0 && nu->bezt != NULL) {
- BezTriple *nu_bezt_old = nu->bezt;
- BezTriple *bezt = nu->bezt;
-
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- BezTriple *bezt_new;
- BEZT_DESEL_ALL(bezt);
-
- bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
- ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
- *bezt_new = *bezt;
-
- MEM_freeN(nu->bezt);
- nu->bezt = bezt_new;
-
- nu->pntsu += 1;
-
- if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
- cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
- bezt_new :
- &nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
- }
-
- BEZT_SEL_ALL(bezt_new);
- changed = true;
- }
+ BezTriple *bezt, *bezt_prev = NULL;
+ BezTriple bezt_stack;
+ bool is_cyclic = false;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Keep `is_prev_selected` false to force extrude. */
+ bezt_prev = &nu->bezt[0];
+ }
+ else if (nu->flagu & CU_NURB_CYCLIC) {
+ is_cyclic = true;
+ bezt_prev = &nu->bezt[pnt_len - 1];
+ is_prev_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev);
}
+ else {
+ duplic_first = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[0]) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[1]);
- /* Check to see if the last bezier point is selected */
- if (nu->pntsu > 1) {
- BezTriple *nu_bezt_old = nu->bezt;
- BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
-
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- BezTriple *bezt_new;
- BEZT_DESEL_ALL(bezt);
-
- bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
- ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu);
- bezt_new[nu->pntsu] = *bezt;
-
- MEM_freeN(nu->bezt);
- nu->bezt = bezt_new;
-
- bezt_new += nu->pntsu;
- nu->pntsu += 1;
-
- if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
- cu_actvert.bezt = (cu_actvert.bezt == bezt) ? bezt_new :
- &nu->bezt[cu_actvert.bezt - nu_bezt_old];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
- }
+ duplic_last = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 2]) &&
+ BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, &nu->bezt[pnt_len - 1]);
- BEZT_SEL_ALL(bezt_new);
- changed = true;
+ if (duplic_first) {
+ bezt_stack = nu->bezt[0];
+ BEZT_DESEL_ALL(&bezt_stack);
+ bezt_prev = &bezt_stack;
+ }
+ if (duplic_last) {
+ new_points++;
}
}
- }
- else {
-
- /* Check to see if the first bpoint is selected */
- if (nu->pntsu > 0 && nu->bp != NULL) {
- BPoint *nu_bp_old = nu->bp;
- BPoint *bp = nu->bp;
-
- if (bp->f1 & SELECT) {
- BPoint *bp_new;
- bp->f1 &= ~SELECT;
-
- bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
- ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu);
- *bp_new = *bp;
-
- MEM_freeN(nu->bp);
- nu->bp = bp_new;
-
- nu->pntsu += 1;
- BKE_nurb_knot_calc_u(nu);
-
- if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
- cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new :
- &nu->bp[(cu_actvert.bp - nu_bp_old) + 1];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
- }
-
- bp_new->f1 |= SELECT;
- changed = true;
+ i = pnt_len;
+ for (bezt = &nu->bezt[0]; i--; bezt++) {
+ bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
+ if (bezt_prev && is_prev_selected != is_selected) {
+ new_points++;
}
+ if (bezt == cu_actvert.bezt) {
+ act_offset = new_points;
+ }
+ bezt_prev = bezt;
+ is_prev_selected = is_selected;
}
- /* Check to see if the last bpoint is selected */
- if (nu->pntsu > 1) {
- BPoint *nu_bp_old = nu->bp;
- BPoint *bp = &nu->bp[nu->pntsu - 1];
-
- if (bp->f1 & SELECT) {
- BPoint *bp_new;
- bp->f1 &= ~SELECT;
-
- bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
- ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu);
- bp_new[nu->pntsu] = *bp;
-
- MEM_freeN(nu->bp);
- nu->bp = bp_new;
+ if (new_points) {
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Set `is_prev_selected` as false to force extrude. */
+ BLI_assert(bezt_prev == &nu->bezt[0]);
+ is_prev_selected = false;
+ }
+ else if (is_cyclic) {
+ BLI_assert(bezt_prev == &nu->bezt[pnt_len - 1]);
+ BLI_assert(is_prev_selected == BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt_prev));
+ }
+ else if (duplic_first) {
+ bezt_prev = &bezt_stack;
+ is_prev_selected = false;
+ }
+ else {
+ bezt_prev = NULL;
+ }
+ BezTriple *bezt_src, *bezt_dst, *bezt_src_iter, *bezt_dst_iter;
+ const int new_len = pnt_len + new_points;
- bp_new += nu->pntsu;
- nu->pntsu += 1;
+ bezt_src = nu->bezt;
+ bezt_dst = MEM_mallocN(new_len * sizeof(BezTriple), __func__);
+ bezt_src_iter = &bezt_src[0];
+ bezt_dst_iter = &bezt_dst[0];
+ i = 0;
+ for (bezt = &nu->bezt[0]; i < pnt_len; i++, bezt++) {
+ bool is_selected = BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt);
+ /* While this gets de-selected, selecting here ensures newly created verts are selected.
+ * without this, the vertices are copied but only the handles are transformed.
+ * which seems buggy from a user perspective. */
+ if (is_selected) {
+ bezt->f2 |= SELECT;
+ }
+ if (bezt_prev && is_prev_selected != is_selected) {
+ int count = i - offset + 1;
+ if (is_prev_selected) {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count - 1);
+ ED_curve_beztcpy(editnurb, &bezt_dst_iter[count - 1], bezt_prev, 1);
+ }
+ else {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, count);
+ }
+ ED_curve_beztcpy(editnurb, &bezt_dst_iter[count], bezt, 1);
+ BEZT_DESEL_ALL(&bezt_dst_iter[count - 1]);
- if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
- cu_actvert.bp = (cu_actvert.bp == bp) ? bp_new : &nu->bp[cu_actvert.bp - nu_bp_old];
- BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ bezt_dst_iter += count + 1;
+ bezt_src_iter += count;
+ offset = i + 1;
}
+ bezt_prev = bezt;
+ is_prev_selected = is_selected;
+ }
- BKE_nurb_knot_calc_u(nu);
-
- bp_new->f1 |= SELECT;
- changed = true;
+ int remain = pnt_len - offset;
+ if (remain) {
+ ED_curve_beztcpy(editnurb, bezt_dst_iter, bezt_src_iter, remain);
}
- }
- }
- }
- /* second pass (interior points) */
- nu_last = editnurb->nurbs.last;
- for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) {
- int i, i_end;
+ if (duplic_last) {
+ ED_curve_beztcpy(editnurb, &bezt_dst[new_len - 1], &bezt_src[pnt_len - 1], 1);
+ BEZT_DESEL_ALL(&bezt_dst[new_len - 1]);
+ }
- if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
- /* all points are interior */
- i = 0;
- i_end = nu->pntsu;
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_dst;
+ nu->pntsu += new_points;
+ changed = true;
+ }
}
else {
- /* skip endpoints */
- i = 1;
- i_end = nu->pntsu - 1;
- }
+ BPoint *bp, *bp_prev = NULL;
+ BPoint bp_stack;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Reference a `prev_bp` to force extrude. */
+ bp_prev = &nu->bp[0];
+ }
+ else {
+ duplic_first = (nu->bp[0].f1 & SELECT) && (nu->bp[1].f1 & SELECT);
+ duplic_last = (nu->bp[pnt_len - 2].f1 & SELECT) && (nu->bp[pnt_len - 1].f1 & SELECT);
+ if (duplic_first) {
+ bp_stack = nu->bp[0];
+ bp_stack.f1 &= ~SELECT;
+ bp_prev = &bp_stack;
+ }
+ if (duplic_last) {
+ new_points++;
+ }
+ }
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt;
+ i = pnt_len;
+ for (bp = &nu->bp[0]; i--; bp++) {
+ bool is_selected = (bp->f1 & SELECT) != 0;
+ if (bp_prev && is_prev_selected != is_selected) {
+ new_points++;
+ }
+ if (bp == cu_actvert.bp) {
+ act_offset = new_points;
+ }
+ bp_prev = bp;
+ is_prev_selected = is_selected;
+ }
- for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
- if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt)) {
- Nurb *nurb_new;
- BezTriple *bezt_new;
+ if (new_points) {
+ BPoint *bp_src, *bp_dst, *bp_src_iter, *bp_dst_iter;
+ const int new_len = pnt_len + new_points;
- BEZT_DESEL_ALL(bezt);
- nurb_new = BKE_nurb_copy(nu, 1, 1);
- nurb_new->flagu &= ~CU_NURB_CYCLIC;
- BLI_addtail(&editnurb->nurbs, nurb_new);
- bezt_new = nurb_new->bezt;
- ED_curve_beztcpy(editnurb, bezt_new, bezt, 1);
- BEZT_SEL_ALL(bezt_new);
+ is_prev_selected = false;
+ if (pnt_len == 1) {
+ /* Single point extrusion.
+ * Keep `is_prev_selected` false to force extrude. */
+ BLI_assert(bp_prev == &nu->bp[0]);
+ }
+ else if (duplic_first) {
+ bp_prev = &bp_stack;
+ is_prev_selected = false;
+ }
+ else {
+ bp_prev = NULL;
+ }
+ bp_src = nu->bp;
+ bp_dst = MEM_mallocN(new_len * sizeof(BPoint), __func__);
+ bp_src_iter = &bp_src[0];
+ bp_dst_iter = &bp_dst[0];
+ i = 0;
+ for (bp = &nu->bp[0]; i < pnt_len; i++, bp++) {
+ bool is_selected = (bp->f1 & SELECT) != 0;
+ if (bp_prev && is_prev_selected != is_selected) {
+ int count = i - offset + 1;
+ if (is_prev_selected) {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count - 1);
+ ED_curve_bpcpy(editnurb, &bp_dst_iter[count - 1], bp_prev, 1);
+ }
+ else {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, count);
+ }
+ ED_curve_bpcpy(editnurb, &bp_dst_iter[count], bp, 1);
+ bp_dst_iter[count - 1].f1 &= ~SELECT;
- if (cu_actvert.bezt == bezt || cu_actnu == NULL) {
- BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new);
+ bp_dst_iter += count + 1;
+ bp_src_iter += count;
+ offset = i + 1;
}
-
- changed = true;
+ bp_prev = bp;
+ is_prev_selected = is_selected;
}
- }
- }
- else {
- BPoint *bp;
- for (bp = &nu->bp[i]; i < i_end; i++, bp++) {
- if (bp->f1 & SELECT) {
- Nurb *nurb_new;
- BPoint *bp_new;
+ int remain = pnt_len - offset;
+ if (remain) {
+ ED_curve_bpcpy(editnurb, bp_dst_iter, bp_src_iter, remain);
+ }
- bp->f1 &= ~SELECT;
- nurb_new = BKE_nurb_copy(nu, 1, 1);
- nurb_new->flagu &= ~CU_NURB_CYCLIC;
- BLI_addtail(&editnurb->nurbs, nurb_new);
- bp_new = nurb_new->bp;
- ED_curve_bpcpy(editnurb, bp_new, bp, 1);
- bp_new->f1 |= SELECT;
+ if (duplic_last) {
+ ED_curve_bpcpy(editnurb, &bp_dst[new_len - 1], &bp_src[pnt_len - 1], 1);
+ bp_dst[new_len - 1].f1 &= ~SELECT;
+ }
- if (cu_actvert.bp == bp || cu_actnu == NULL) {
- BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new);
- }
+ MEM_freeN(nu->bp);
+ nu->bp = bp_dst;
+ nu->pntsu += new_points;
- changed = true;
- }
+ BKE_nurb_knot_calc_u(nu);
+ changed = true;
}
}
}
- if (changed == false) {
- BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p);
- }
+ cu->actvert += act_offset;
return changed;
}
-/***************** add vertex operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Vertex Operator
+ * \{ */
static int ed_editcurve_addvert(Curve *cu,
EditNurb *editnurb,
@@ -5659,7 +5617,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cu = vc.obedit->data;
- findselectedNurbvert(cu, vc.v3d, &nu, &bezt, &bp);
+ ED_curve_nurb_vert_selected_find(cu, vc.v3d, &nu, &bezt, &bp);
if (bezt) {
mul_v3_m4v3(location, vc.obedit->obmat, bezt->vec[1]);
@@ -5677,7 +5635,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const float mval[2] = {UNPACK2(event->mval)};
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- vc.bmain, vc.scene, 0, vc.region, vc.v3d);
+ vc.scene, 0, vc.region, vc.v3d);
ED_transform_snap_object_project_view3d(
snap_context,
@@ -5760,7 +5718,11 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
1.0e4f);
}
-/***************** extrude operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Operator
+ * \{ */
static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -5831,7 +5793,11 @@ void CURVE_OT_extrude(wmOperatorType *ot)
RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
}
-/***************** make cyclic operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Make Cyclic Operator
+ * \{ */
static bool curve_toggle_cyclic(View3D *v3d, ListBase *editnurb, int direction)
{
@@ -5997,7 +5963,11 @@ void CURVE_OT_cyclic_toggle(wmOperatorType *ot)
"Direction to make surface cyclic in");
}
-/********************** add duplicate operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Duplicate Operator
+ * \{ */
static int duplicate_exec(bContext *C, wmOperator *op)
{
@@ -6053,7 +6023,11 @@ void CURVE_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** delete operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
static bool curve_delete_vertices(Object *obedit, View3D *v3d)
{
@@ -6599,6 +6573,12 @@ void CURVE_OT_delete(wmOperatorType *ot)
ot->prop = prop;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Vertices
+ * \{ */
+
static bool test_bezt_is_sel_any(const void *bezt_v, void *user_data)
{
View3D *v3d = user_data;
@@ -6628,8 +6608,8 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
for (nu = editnurb->first; nu; nu = nu->next) {
if ((nu->type == CU_BEZIER) && (nu->pntsu > 2)) {
- unsigned int span_step[2] = {nu->pntsu, nu->pntsu};
- unsigned int span_len;
+ uint span_step[2] = {nu->pntsu, nu->pntsu};
+ uint span_len;
while (BLI_array_iter_span(nu->bezt,
nu->pntsu,
@@ -6643,9 +6623,9 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BezTriple *bezt_next = &nu->bezt[mod_i(span_step[1] + 1, nu->pntsu)];
int i_span_edge_len = span_len + 1;
- const unsigned int dims = 3;
+ const uint dims = 3;
- const unsigned int points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
+ const uint points_len = ((cu->resolu - 1) * i_span_edge_len) + 1;
float *points = MEM_mallocN(points_len * dims * sizeof(float), __func__);
float *points_stride = points;
const int points_stride_len = (cu->resolu - 1);
@@ -6670,7 +6650,7 @@ static int curve_dissolve_exec(bContext *C, wmOperator *UNUSED(op))
BLI_assert(points_stride + dims == points + (points_len * dims));
float tan_l[3], tan_r[3], error_sq_dummy;
- unsigned int error_index_dummy;
+ uint error_index_dummy;
sub_v3_v3v3(tan_l, bezt_prev->vec[1], bezt_prev->vec[2]);
normalize_v3(tan_l);
@@ -6731,6 +6711,12 @@ void CURVE_OT_dissolve_verts(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Decimate Operator
+ * \{ */
+
static bool nurb_bezt_flag_any(const Nurb *nu, const char flag_test)
{
BezTriple *bezt = nu->bezt;
@@ -6824,7 +6810,11 @@ void CURVE_OT_decimate(wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f);
}
-/********************** shade smooth/flat operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Shade Smooth/Flat Operator
+ * \{ */
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
@@ -6844,7 +6834,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
continue;
}
- for (Nurb *nu = editnurb->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, editnurb) {
if (ED_curve_nurb_select_check(v3d, nu)) {
if (!clear) {
nu->flag |= CU_SMOOTH;
@@ -6895,8 +6885,16 @@ void CURVE_OT_shade_flat(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/************** join operator, to be used externally? ****************/
-/* TODO: shape keys - as with meshes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Join Operator
+ * \{ */
+
+/**
+ * This is used externally, by #OBJECT_OT_join.
+ * TODO: shape keys - as with meshes.
+ */
int join_curve_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -6996,7 +6994,11 @@ int join_curve_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/***************** clear tilt operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Tilt Operator
+ * \{ */
static int clear_tilt_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -7077,28 +7079,11 @@ void ED_curve_bpcpy(EditNurb *editnurb, BPoint *dst, BPoint *src, int count)
keyIndex_updateBP(editnurb, src, dst, count);
}
-bool ED_curve_active_center(Curve *cu, float center[3])
-{
- Nurb *nu = NULL;
- void *vert = NULL;
-
- if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
- return false;
- }
-
- if (nu->type == CU_BEZIER) {
- BezTriple *bezt = (BezTriple *)vert;
- copy_v3_v3(center, bezt->vec[1]);
- }
- else {
- BPoint *bp = (BPoint *)vert;
- copy_v3_v3(center, bp->vec);
- }
-
- return true;
-}
+/** \} */
-/******************** Match texture space operator ***********************/
+/* -------------------------------------------------------------------- */
+/** \name Match Texture Space Operator
+ * \{ */
static bool match_texture_space_poll(bContext *C)
{
@@ -7168,3 +7153,5 @@ void CURVE_OT_match_texture_space(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 91d5ea58361..bacdd5b69b5 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -138,7 +138,7 @@ Nurb *ED_curve_add_nurbs_primitive(
copy_v3_v3(zvec, rv3d->viewinv[2]);
}
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
/* these types call this function to return a Nurb */
if (stype != CU_PRIM_TUBE && stype != CU_PRIM_DONUT) {
@@ -521,7 +521,7 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index d028a88e322..748bf040fbb 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -205,7 +205,7 @@ static bool stroke_elem_project(const struct CurveDrawData *cdd,
}
else {
const ViewDepths *depths = rv3d->depths;
- if (depths && ((unsigned int)mval_i[0] < depths->w) && ((unsigned int)mval_i[1] < depths->h)) {
+ if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
if (ED_view3d_depth_unproject(region, mval_i, depth, r_location_world)) {
@@ -798,7 +798,7 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
float *cubic_spline = NULL;
- unsigned int cubic_spline_len = 0;
+ uint cubic_spline_len = 0;
/* error in object local space */
const int fit_method = RNA_enum_get(op->ptr, "fit_method");
@@ -827,14 +827,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
}
}
- unsigned int *corners = NULL;
- unsigned int corners_len = 0;
+ uint *corners = NULL;
+ uint corners_len = 0;
if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
/* this could be configurable... */
const float corner_radius_min = error_threshold / 8;
const float corner_radius_max = error_threshold * 2;
- const unsigned int samples_max = 16;
+ const uint samples_max = 16;
curve_fit_corners_detect_fl(coords,
stroke_len,
@@ -847,9 +847,9 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
&corners_len);
}
- unsigned int *corners_index = NULL;
- unsigned int corners_index_len = 0;
- unsigned int calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
+ uint *corners_index = NULL;
+ uint corners_index_len = 0;
+ uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
if ((stroke_len > 2) && use_cyclic) {
calc_flag |= CURVE_FIT_CALC_CYCLIC;
@@ -919,14 +919,14 @@ static int curve_draw_exec(bContext *C, wmOperator *op)
if (corners_index) {
/* ignore the first and last */
- unsigned int i_start = 0, i_end = corners_index_len;
+ uint i_start = 0, i_end = corners_index_len;
if ((corners_index_len >= 2) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
i_start += 1;
i_end -= 1;
}
- for (unsigned int i = i_start; i < i_end; i++) {
+ for (uint i = i_start; i < i_end; i++) {
bezt = &nu->bezt[corners_index[i]];
bezt->h1 = bezt->h2 = HD_FREE;
}
diff --git a/source/blender/editors/curve/editcurve_query.c b/source/blender/editors/curve/editcurve_query.c
new file mode 100644
index 00000000000..132f7e58e71
--- /dev/null
+++ b/source/blender/editors/curve/editcurve_query.c
@@ -0,0 +1,253 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edcurve
+ */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "BKE_curve.h"
+#include "BKE_fcurve.h"
+#include "BKE_layer.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "ED_curve.h"
+#include "ED_view3d.h"
+
+#include "curve_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Picking API
+ * \{ */
+
+static void ED_curve_pick_vert__do_closest(void *userData,
+ Nurb *nu,
+ BPoint *bp,
+ BezTriple *bezt,
+ int beztindex,
+ bool handles_visible,
+ const float screen_co[2])
+{
+ struct {
+ BPoint *bp;
+ BezTriple *bezt;
+ Nurb *nurb;
+ float dist;
+ int hpoint, select;
+ float mval_fl[2];
+ bool is_changed;
+ } *data = userData;
+
+ short flag;
+ float dist_test;
+
+ if (bp) {
+ flag = bp->f1;
+ }
+ else {
+ BLI_assert(handles_visible || beztindex == 1);
+
+ if (beztindex == 0) {
+ flag = bezt->f1;
+ }
+ else if (beztindex == 1) {
+ flag = bezt->f2;
+ }
+ else {
+ flag = bezt->f3;
+ }
+ }
+
+ dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
+ if ((flag & SELECT) == data->select) {
+ dist_test += 5.0f;
+ }
+ if (bezt && beztindex == 1) {
+ dist_test += 3.0f; /* middle points get a small disadvantage */
+ }
+
+ if (dist_test < data->dist) {
+ data->dist = dist_test;
+
+ data->bp = bp;
+ data->bezt = bezt;
+ data->nurb = nu;
+ data->hpoint = bezt ? beztindex : 0;
+ data->is_changed = true;
+ }
+
+ UNUSED_VARS_NDEBUG(handles_visible);
+}
+
+bool ED_curve_pick_vert(ViewContext *vc,
+ short sel,
+ Nurb **r_nurb,
+ BezTriple **r_bezt,
+ BPoint **r_bp,
+ short *r_handle,
+ Base **r_base)
+{
+ /* (sel == 1): selected gets a disadvantage */
+ /* in nurb and bezt or bp the nearest is written */
+ /* return 0 1 2: handlepunt */
+ struct {
+ BPoint *bp;
+ BezTriple *bezt;
+ Nurb *nurb;
+ float dist;
+ int hpoint, select;
+ float mval_fl[2];
+ bool is_changed;
+ } data = {NULL};
+
+ data.dist = ED_view3d_select_dist_px();
+ data.hpoint = 0;
+ data.select = sel;
+ data.mval_fl[0] = vc->mval[0];
+ data.mval_fl[1] = vc->mval[1];
+
+ uint bases_len;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ vc->view_layer, vc->v3d, &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Base *base = bases[base_index];
+ data.is_changed = false;
+
+ ED_view3d_viewcontext_init_object(vc, base->object);
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ nurbs_foreachScreenVert(vc, ED_curve_pick_vert__do_closest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ if (r_base && data.is_changed) {
+ *r_base = base;
+ }
+ }
+ MEM_freeN(bases);
+
+ *r_nurb = data.nurb;
+ *r_bezt = data.bezt;
+ *r_bp = data.bp;
+
+ if (r_handle) {
+ *r_handle = data.hpoint;
+ }
+
+ return (data.bezt || data.bp);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Queries
+ * \{ */
+
+void ED_curve_nurb_vert_selected_find(
+ Curve *cu, View3D *v3d, Nurb **r_nu, BezTriple **r_bezt, BPoint **r_bp)
+{
+ /* in nu and (bezt or bp) selected are written if there's 1 sel. */
+ /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
+ ListBase *editnurb = &cu->editnurb->nurbs;
+ Nurb *nu1;
+ BezTriple *bezt1;
+ BPoint *bp1;
+ int a;
+
+ *r_nu = NULL;
+ *r_bezt = NULL;
+ *r_bp = NULL;
+
+ for (nu1 = editnurb->first; nu1; nu1 = nu1->next) {
+ if (nu1->type == CU_BEZIER) {
+ bezt1 = nu1->bezt;
+ a = nu1->pntsu;
+ while (a--) {
+ if (BEZT_ISSEL_ANY_HIDDENHANDLES(v3d, bezt1)) {
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_nu = NULL;
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ return;
+ }
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ }
+ else {
+ *r_bezt = bezt1;
+ *r_nu = nu1;
+ }
+ }
+ bezt1++;
+ }
+ }
+ else {
+ bp1 = nu1->bp;
+ a = nu1->pntsu * nu1->pntsv;
+ while (a--) {
+ if (bp1->f1 & SELECT) {
+ if (*r_nu != NULL && *r_nu != nu1) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ *r_nu = NULL;
+ return;
+ }
+ else if (*r_bezt || *r_bp) {
+ *r_bp = NULL;
+ *r_bezt = NULL;
+ }
+ else {
+ *r_bp = bp1;
+ *r_nu = nu1;
+ }
+ }
+ bp1++;
+ }
+ }
+ }
+}
+
+bool ED_curve_active_center(Curve *cu, float center[3])
+{
+ Nurb *nu = NULL;
+ void *vert = NULL;
+
+ if (!BKE_curve_nurb_vert_active_get(cu, &nu, &vert)) {
+ return false;
+ }
+
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt = (BezTriple *)vert;
+ copy_v3_v3(center, bezt->vec[1]);
+ }
+ else {
+ BPoint *bp = (BPoint *)vert;
+ copy_v3_v3(center, bp->vec);
+ }
+
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index 51bb1eafdb9..9294bc6e91b 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -29,6 +29,7 @@
#include "BLI_bitmap.h"
#include "BLI_heap_simple.h"
#include "BLI_kdtree.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rand.h"
@@ -198,7 +199,7 @@ bool ED_curve_nurb_select_all(const Nurb *nu)
bool ED_curve_select_all(EditNurb *editnurb)
{
bool changed = false;
- for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
changed |= ED_curve_nurb_select_all(nu);
}
return changed;
@@ -257,7 +258,7 @@ bool ED_curve_select_check(View3D *v3d, struct EditNurb *editnurb)
bool ED_curve_deselect_all(EditNurb *editnurb)
{
bool changed = false;
- for (Nurb *nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, &editnurb->nurbs) {
changed |= ED_curve_nurb_deselect_all(nu);
}
return changed;
@@ -589,8 +590,8 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
changed = ED_curve_deselect_all(cu->editnurb);
break;
case SEL_INVERT:
- changed = ED_curve_select_swap(
- cu->editnurb, (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0);
+ changed = ED_curve_select_swap(cu->editnurb,
+ v3d->overlay.handle_display == CURVE_HANDLE_NONE);
break;
}
@@ -771,7 +772,7 @@ static int select_row_exec(bContext *C, wmOperator *UNUSED(op))
if (last == bp) {
direction = 1 - direction;
- BKE_nurbList_flag_set(editnurb, 0);
+ BKE_nurbList_flag_set(editnurb, SELECT, false);
}
last = bp;
@@ -825,8 +826,10 @@ static int select_next_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, 1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -860,8 +863,10 @@ static int select_previous_exec(bContext *C, wmOperator *UNUSED(op))
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
+
ListBase *editnurb = object_editcurve_get(obedit);
select_adjacent_cp(editnurb, -1, 0, SELECT);
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -1391,6 +1396,7 @@ static int select_nth_exec(bContext *C, wmOperator *op)
if (ed_curve_select_nth(obedit->data, &op_params) == true) {
changed = true;
+
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
@@ -1825,7 +1831,7 @@ static float curve_calc_dist_span(Nurb *nu, int vert_src, int vert_dst)
int i_prev, i;
float dist = 0.0f;
- BLI_assert(nu->pntsv == 1);
+ BLI_assert(nu->pntsv <= 1);
i_prev = vert_src;
i = (i_prev + 1) % u;
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 94a0ef7a460..1fd1e217649 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -30,7 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
@@ -88,12 +88,12 @@ static void undocurve_to_editcurve(Main *bmain, UndoCurve *ucu, Curve *cu, short
if (ad) {
if (ad->action) {
- free_fcurves(&ad->action->curves);
- copy_fcurves(&ad->action->curves, &ucu->fcurves);
+ BKE_fcurves_free(&ad->action->curves);
+ BKE_fcurves_copy(&ad->action->curves, &ucu->fcurves);
}
- free_fcurves(&ad->drivers);
- copy_fcurves(&ad->drivers, &ucu->drivers);
+ BKE_fcurves_free(&ad->drivers);
+ BKE_fcurves_copy(&ad->drivers, &ucu->drivers);
}
/* copy */
@@ -132,10 +132,10 @@ static void undocurve_from_editcurve(UndoCurve *ucu, Curve *cu, const short shap
if (ad) {
if (ad->action) {
- copy_fcurves(&ucu->fcurves, &ad->action->curves);
+ BKE_fcurves_copy(&ucu->fcurves, &ad->action->curves);
}
- copy_fcurves(&ucu->drivers, &ad->drivers);
+ BKE_fcurves_copy(&ucu->drivers, &ad->drivers);
}
/* copy */
@@ -167,8 +167,8 @@ static void undocurve_free_data(UndoCurve *uc)
BKE_curve_editNurb_keyIndex_free(&uc->undoIndex);
- free_fcurves(&uc->fcurves);
- free_fcurves(&uc->drivers);
+ BKE_fcurves_free(&uc->fcurves);
+ BKE_fcurves_free(&uc->drivers);
}
static Object *editcurve_object_from_context(bContext *C)
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 297af4cb72d..dc5dc71106f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -76,7 +76,7 @@ static int kill_selection(Object *obedit, int ins);
/** \name Internal Utilities
* \{ */
-static wchar_t findaccent(wchar_t char1, unsigned int code)
+static wchar_t findaccent(wchar_t char1, uint code)
{
wchar_t new = 0;
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index af591e0c7c5..ef9bb7e0c88 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -359,7 +359,7 @@ static void font_undosys_step_decode(
struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final))
{
/* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set(C, OB_MODE_EDIT);
+ ED_object_mode_set_ex(C, OB_MODE_EDIT, false, NULL);
BLI_assert(font_undosys_poll(C));
FontUndoStep *us = (FontUndoStep *)us_p;
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 1bc0465424d..1a5b3d6ac45 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -336,7 +336,7 @@ set(ICON_NAMES
force_boid
force_turbulence
force_drag
- force_smokeflow
+ force_fluidflow
image_plane
image_background
image_reference
@@ -779,7 +779,6 @@ if(WITH_BLENDER)
# images
data_to_c_simple(../../../../release/datafiles/splash.png SRC)
- data_to_c_simple(../../../../release/datafiles/splash_2x.png SRC)
data_to_c_simple(../../../../release/datafiles/alert_icons.png SRC)
# XXX These are handy, but give nasty "false changes" in svn :/
# svg_to_png(../../../../release/datafiles/blender_icons.svg
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index 68a204c04a7..1f3edf31b19 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -53,6 +53,7 @@ set(SRC
gizmo_types/dial3d_gizmo.c
gizmo_types/move3d_gizmo.c
gizmo_types/primitive3d_gizmo.c
+ gizmo_types/snap3d_gizmo.c
)
set(LIB
diff --git a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
index 90196988d94..668b59ac191 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_arrow_gizmo.c
@@ -55,7 +55,7 @@ static float normals[][3] = {
{0.000000, 0.000000, 1.000000},
};
-static unsigned short indices[] = {
+static ushort indices[] = {
1, 3, 2, 3, 5, 4, 5, 7, 6, 7, 9, 8, 9, 11, 10, 11, 13, 12, 5, 18, 19, 15, 1,
0, 13, 15, 14, 6, 10, 14, 11, 21, 22, 7, 19, 20, 13, 22, 23, 3, 17, 18, 9, 20, 21, 15,
23, 16, 1, 16, 17, 23, 22, 24, 21, 20, 24, 19, 18, 24, 17, 16, 24, 16, 23, 24, 22, 21, 24,
diff --git a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
index ea1a3147148..51618e353f4 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_cube_gizmo.c
@@ -45,7 +45,7 @@ static const float normals[][3] = {
{-0.577349, 0.577349, 0.577349},
};
-static const unsigned short indices[] = {
+static const ushort indices[] = {
1, 2, 3, 7, 6, 5, 4, 5, 1, 5, 6, 2, 2, 6, 7, 0, 3, 7,
0, 1, 3, 4, 7, 5, 0, 4, 1, 1, 5, 2, 3, 2, 7, 4, 0, 7,
};
diff --git a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
index 273f957e9b6..7e37c233c2a 100644
--- a/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
+++ b/source/blender/editors/gizmo_library/geometry/geom_dial_gizmo.c
@@ -221,7 +221,7 @@ static const float normals[][3] = {
{-0.466689, 0.092807, -0.879513}, {0.512650, -0.101962, -0.852504},
};
-static const unsigned short indices[] = {
+static const ushort indices[] = {
6, 7, 1, 7, 8, 2, 8, 9, 3, 9, 10, 4, 10, 11, 5, 5, 11, 6, 12,
13, 7, 13, 14, 8, 14, 15, 9, 15, 16, 10, 16, 17, 11, 11, 17, 12, 18, 19,
13, 13, 19, 20, 20, 21, 15, 15, 21, 22, 22, 23, 17, 17, 23, 18, 24, 25, 19,
diff --git a/source/blender/editors/gizmo_library/gizmo_draw_utils.c b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
index cffafc56693..01e5a7eacfd 100644
--- a/source/blender/editors/gizmo_library/gizmo_draw_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_draw_utils.c
@@ -66,7 +66,7 @@ void wm_gizmo_geometryinfo_draw(const GizmoGeomInfo *info,
/* Elements */
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, info->ntris, info->nverts);
for (int i = 0; i < info->ntris; i++) {
- const unsigned short *idx = &info->indices[i * 3];
+ const ushort *idx = &info->indices[i * 3];
GPU_indexbuf_add_tri_verts(&elb, idx[0], idx[1], idx[2]);
}
el = GPU_indexbuf_build(&elb);
diff --git a/source/blender/editors/gizmo_library/gizmo_geometry.h b/source/blender/editors/gizmo_library/gizmo_geometry.h
index ae8ba3c411b..a5f61158f66 100644
--- a/source/blender/editors/gizmo_library/gizmo_geometry.h
+++ b/source/blender/editors/gizmo_library/gizmo_geometry.h
@@ -30,12 +30,14 @@
#ifndef __GIZMO_GEOMETRY_H__
#define __GIZMO_GEOMETRY_H__
+#include "BLI_sys_types.h"
+
typedef struct GizmoGeomInfo {
int nverts;
int ntris;
const float (*verts)[3];
const float (*normals)[3];
- const unsigned short *indices;
+ const ushort *indices;
} GizmoGeomInfo;
/* arrow gizmo */
diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
index da6365d724d..e6333d7d3e0 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c
@@ -88,9 +88,14 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
const int draw_style = RNA_enum_get(arrow->gizmo.ptr, "draw_style");
const int draw_options = RNA_enum_get(arrow->gizmo.ptr, "draw_options");
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
if (draw_style == ED_GIZMO_ARROW_STYLE_CROSS) {
+ immUniform1f("lineWidth", U.pixelsize);
immUniformColor4fv(color);
immBegin(GPU_PRIM_LINES, 4);
@@ -112,7 +117,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
{-unitx, unity, 0},
};
- GPU_line_width(arrow->gizmo.line_width);
+ immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_LOOP);
}
else {
@@ -127,7 +132,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
};
if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) {
- GPU_line_width(arrow->gizmo.line_width);
+ immUniform1f("lineWidth", arrow->gizmo.line_width * U.pixelsize);
wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP);
}
else {
@@ -160,6 +165,10 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, const bool select, const
/* translate to line end */
GPU_matrix_translate_3f(0.0f, 0.0f, arrow_length);
+ immUnbindProgram();
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformColor4fv(color);
+
imm_draw_circle_fill_3d(pos, 0.0, 0.0, width, 8);
imm_draw_cylinder_fill_3d(pos, width, 0.0, len, 8, 1);
}
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 11253f01bf2..04b93f35681 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -76,7 +76,8 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
const float fill_alpha,
const bool select)
{
- GPU_line_width(gz->line_width);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -85,10 +86,14 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
if (color[3] == 1.0 && fill_alpha == 1.0 && select == false) {
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
immUniformColor4fv(color);
- GPU_polygon_smooth(0);
imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
+ immUniformColor4fv(color);
imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
- GPU_polygon_smooth(1);
immUnbindProgram();
}
else {
@@ -103,9 +108,10 @@ static void button2d_geom_draw_backdrop(const wmGizmo *gz,
/* Draw outline. */
if ((fill_alpha != 1.0f) && (select == false)) {
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
- GPU_line_width(gz->line_width);
imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, CIRCLE_RESOLUTION);
immUnbindProgram();
}
@@ -120,6 +126,8 @@ static void button2d_draw_intern(const bContext *C,
const bool highlight)
{
ButtonGizmo2D *button = (ButtonGizmo2D *)gz;
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
if (button->is_init == false) {
@@ -155,9 +163,9 @@ static void button2d_draw_intern(const bContext *C,
float matrix_final_no_offset[4][4];
WM_gizmo_calc_matrix_final_no_offset(gz, matrix_final_no_offset);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformColor4fv(color);
- GPU_line_width(gz->line_width);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
immBegin(GPU_PRIM_LINE_STRIP, 2);
immVertex3fv(pos, matrix_final[3]);
@@ -197,11 +205,19 @@ static void button2d_draw_intern(const bContext *C,
if (button->shape_batch[0] != NULL) {
GPU_line_smooth(true);
GPU_polygon_smooth(false);
- GPU_line_width(1.0f);
for (uint i = 0; i < ARRAY_SIZE(button->shape_batch) && button->shape_batch[i]; i++) {
- /* Invert line color for wire. */
- GPU_batch_program_set_builtin(button->shape_batch[i], GPU_SHADER_2D_UNIFORM_COLOR);
+ const bool do_wires = (i == 1);
+ if (do_wires) {
+ GPU_batch_program_set_builtin(button->shape_batch[i],
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ GPU_batch_uniform_2fv(button->shape_batch[i], "viewportSize", &viewport[2]);
+ 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);
+ }
+ /* Invert line color for wire. */
if (draw_options & ED_GIZMO_BUTTON_SHOW_BACKDROP) {
/* If we have a backdrop already,
* draw a contrasting shape over it instead of drawing it the same color.
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 1b43479eedb..fd24149e9ea 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -162,13 +162,22 @@ static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[2], bool r_con
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
* \{ */
-static void cage2d_draw_box_corners(const rctf *r, const float margin[2], const float color[3])
+static void cage2d_draw_box_corners(const rctf *r,
+ const float margin[2],
+ const float color[3],
+ const float line_width)
{
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_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
immBegin(GPU_PRIM_LINES, 16);
immVertex2f(pos, r->xmin, r->ymin + margin[1]);
@@ -445,7 +454,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(GPU_SHADER_2D_FLAT_COLOR);
+ immBindBuiltinProgram(is_solid ? GPU_SHADER_2D_FLAT_COLOR : GPU_SHADER_3D_POLYLINE_FLAT_COLOR);
{
if (is_solid) {
@@ -459,7 +468,12 @@ static void cage2d_draw_box_interaction(const float color[4],
}
else {
BLI_assert(ELEM(prim_type, GPU_PRIM_LINE_STRIP, GPU_PRIM_LINES));
- GPU_line_width(line_width + 3.0f);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+
+ immUniform1f("lineWidth", (line_width * 3.0f) * U.pixelsize);
immBegin(prim_type, verts_len);
immAttr3f(attr_id.col, 0.0f, 0.0f, 0.0f);
@@ -468,7 +482,7 @@ static void cage2d_draw_box_interaction(const float color[4],
}
immEnd();
- GPU_line_width(line_width);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
immBegin(prim_type, verts_len);
immAttr3fv(attr_id.col, color);
@@ -505,13 +519,19 @@ static void cage2d_draw_circle_wire(const rctf *r,
const float margin[2],
const float color[3],
const int transform_flag,
- const int draw_options)
+ const int draw_options,
+ const float line_width)
{
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_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
immBegin(GPU_PRIM_LINE_LOOP, 4);
immVertex2f(pos, r->xmin, r->ymin);
immVertex2f(pos, r->xmax, r->ymin);
@@ -662,15 +682,14 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
.ymax = size_real[1],
};
if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ float color[4], black[3] = {0, 0, 0};
+ gizmo_color_get(gz, highlight, color);
+
/* corner gizmos */
- GPU_line_width(gz->line_width + 3.0f);
- cage2d_draw_box_corners(&r, margin, (const float[3]){0, 0, 0});
+ cage2d_draw_box_corners(&r, margin, black, gz->line_width + 3.0f);
/* corner gizmos */
- float color[4];
- gizmo_color_get(gz, highlight, color);
- GPU_line_width(gz->line_width);
- cage2d_draw_box_corners(&r, margin, color);
+ cage2d_draw_box_corners(&r, margin, color, gz->line_width);
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE2D_PART_TRANSLATE) {
@@ -700,30 +719,26 @@ static void gizmo_cage2d_draw_intern(wmGizmo *gz,
}
}
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
- float color[4];
+ float color[4], black[3] = {0, 0, 0};
gizmo_color_get(gz, highlight, color);
- GPU_line_smooth(true);
GPU_blend(true);
- GPU_line_width(gz->line_width + 3.0f);
- cage2d_draw_circle_wire(&r, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
- GPU_line_width(gz->line_width);
- cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options);
+ float outline_line_width = gz->line_width + 3.0f;
+ cage2d_draw_circle_wire(&r, margin, black, transform_flag, draw_options, outline_line_width);
+ cage2d_draw_circle_wire(&r, margin, color, transform_flag, draw_options, gz->line_width);
/* corner gizmos */
cage2d_draw_circle_handles(&r, margin, color, transform_flag, true);
cage2d_draw_circle_handles(&r, margin, (const float[3]){0, 0, 0}, transform_flag, false);
GPU_blend(false);
- GPU_line_smooth(false);
}
else {
BLI_assert(0);
}
}
- GPU_line_width(1.0);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
index 6855268610e..b0af8641767 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -130,14 +130,22 @@ static void gizmo_rect_pivot_from_scale_part(int part, float r_pt[3], bool r_con
* Useful for 3D views, see: #ED_GIZMO_CAGE2D_STYLE_BOX
* \{ */
-static void cage3d_draw_box_corners(const float r[3], const float margin[3], const float color[3])
+static void cage3d_draw_box_corners(const float r[3],
+ const float margin[3],
+ const float color[3],
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
UNUSED_VARS(margin);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
immUnbindProgram();
@@ -199,13 +207,19 @@ static void cage3d_draw_circle_wire(const float r[3],
const float margin[3],
const float color[3],
const int transform_flag,
- const int draw_options)
+ const int draw_options,
+ const float line_width)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
immUniformColor3fv(color);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
imm_draw_cube_wire_3d(pos, (float[3]){0}, r);
#if 0
@@ -339,15 +353,14 @@ static void gizmo_cage3d_draw_intern(
};
#endif
if (draw_style == ED_GIZMO_CAGE2D_STYLE_BOX) {
+ float color[4], black[3] = {0, 0, 0};
+ gizmo_color_get(gz, highlight, color);
+
/* corner gizmos */
- GPU_line_width(gz->line_width + 3.0f);
- cage3d_draw_box_corners(size_real, margin, (const float[3]){0, 0, 0});
+ cage3d_draw_box_corners(size_real, margin, black, gz->line_width + 3.0f);
/* corner gizmos */
- float color[4];
- gizmo_color_get(gz, highlight, color);
- GPU_line_width(gz->line_width);
- cage3d_draw_box_corners(size_real, margin, color);
+ cage3d_draw_box_corners(size_real, margin, color, gz->line_width);
bool show = false;
if (gz->highlight_part == ED_GIZMO_CAGE3D_PART_TRANSLATE) {
@@ -366,34 +379,29 @@ static void gizmo_cage3d_draw_intern(
}
}
else if (draw_style == ED_GIZMO_CAGE2D_STYLE_CIRCLE) {
- float color[4];
+ float color[4], black[3] = {0, 0, 0};
gizmo_color_get(gz, highlight, color);
- GPU_line_smooth(true);
- GPU_polygon_smooth(true);
GPU_blend(true);
- GPU_line_width(gz->line_width + 3.0f);
cage3d_draw_circle_wire(
- size_real, margin, (const float[3]){0, 0, 0}, transform_flag, draw_options);
- GPU_line_width(gz->line_width);
- cage3d_draw_circle_wire(size_real, margin, color, transform_flag, draw_options);
+ size_real, margin, black, transform_flag, draw_options, gz->line_width + 3.0f);
+ cage3d_draw_circle_wire(
+ size_real, margin, color, transform_flag, draw_options, gz->line_width);
/* corner gizmos */
- cage3d_draw_circle_handles(
- rv3d, matrix_final, size_real, margin, (const float[3]){0, 0, 0}, true, 60);
+ GPU_polygon_smooth(true);
+ cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, black, true, 60);
cage3d_draw_circle_handles(rv3d, matrix_final, size_real, margin, color, true, 40);
+ GPU_polygon_smooth(false);
GPU_blend(false);
- GPU_polygon_smooth(false);
- GPU_line_smooth(false);
}
else {
BLI_assert(0);
}
}
- GPU_line_width(1.0);
GPU_matrix_pop();
}
diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
index 6b308308664..262f4b78b95 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c
@@ -111,19 +111,18 @@ static void dial_geom_draw(const float color[4],
ED_GIZMO_DIAL_DRAW_FLAG_FILL_SELECT) :
ED_GIZMO_DIAL_DRAW_FLAG_FILL)));
- GPU_line_width(line_width);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (clip_plane) {
- immBindBuiltinProgram(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR);
immUniform4fv("ClipPlane", clip_plane);
immUniformMatrix4fv("ModelMatrix", axis_modal_mat);
- glEnable(GL_CLIP_DISTANCE0);
}
else {
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
}
immUniformColor4fv(color);
@@ -151,6 +150,11 @@ static void dial_geom_draw(const float color[4],
}
}
else {
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
+
if (arc_partial_angle == 0.0f) {
imm_draw_circle_wire_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION);
if (arc_inner_factor != 0.0f) {
@@ -171,10 +175,6 @@ static void dial_geom_draw(const float color[4],
immUnbindProgram();
- if (clip_plane) {
- glDisable(GL_CLIP_DISTANCE0);
- }
-
UNUSED_VARS(select);
#endif
}
@@ -184,14 +184,20 @@ static void dial_geom_draw(const float color[4],
*/
static void dial_ghostarc_draw_helpline(const float angle,
const float co_outer[3],
- const float color[4])
+ const float color[4],
+ const float line_width)
{
GPU_matrix_push();
GPU_matrix_rotate_3f(RAD2DEGF(angle), 0.0f, 0.0f, -1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", line_width * U.pixelsize);
immUniformColor4fv(color);
@@ -211,11 +217,17 @@ static void dial_ghostarc_draw_helpline(const float angle,
static void dial_ghostarc_draw_incremental_angle(const float incremental_angle, const float offset)
{
const int tot_incr = (2 * M_PI) / incremental_angle;
- GPU_line_width(1.0f);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
immUniformColor3f(1.0f, 1.0f, 1.0f);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", U.pixelsize);
+
immBegin(GPU_PRIM_LINES, tot_incr * 2);
float v[3] = {0};
@@ -369,14 +381,12 @@ static void dial_ghostarc_draw_with_helplines(const float angle_ofs,
{
/* Coordinate at which the arc drawing will be started. */
const float co_outer[4] = {0.0f, DIAL_WIDTH, 0.0f};
- dial_ghostarc_draw(
- angle_ofs, angle_delta, arc_inner_factor, (const float[4]){0.8f, 0.8f, 0.8f, 0.4f});
- GPU_line_width(1.0f);
- dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline);
- if (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) {
- GPU_line_width(3.0f);
- }
- dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline);
+ const float color_arc_inner[4] = {0.8f, 0.8f, 0.8f, 0.2f};
+ dial_ghostarc_draw(angle_ofs, angle_delta, arc_inner_factor, color_arc_inner);
+
+ float line_width = (draw_options & ED_GIZMO_DIAL_DRAW_FLAG_ANGLE_VALUE) ? 3.0f : 1.0f;
+ dial_ghostarc_draw_helpline(angle_ofs, co_outer, color_helpline, 1.0f);
+ dial_ghostarc_draw_helpline(angle_ofs + angle_delta, co_outer, color_helpline, line_width);
}
static void dial_draw_intern(
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 4049a3b9dcb..db57a33f543 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -106,16 +106,21 @@ static void move_geom_draw(const wmGizmo *gz,
wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_move3d, select);
#else
const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
- const bool filled = ((draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
+ const bool filled = (draw_style != ED_GIZMO_MOVE_STYLE_CROSS_2D) &&
+ ((draw_options & (select ? (ED_GIZMO_MOVE_DRAW_FLAG_FILL |
ED_GIZMO_MOVE_DRAW_FLAG_FILL_SELECT) :
ED_GIZMO_MOVE_DRAW_FLAG_FILL)));
- GPU_line_width(gz->line_width);
-
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(filled ? GPU_SHADER_3D_UNIFORM_COLOR :
+ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", gz->line_width * U.pixelsize);
immUniformColor4fv(color);
@@ -372,12 +377,12 @@ static int gizmo_move_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
WM_gizmo_calc_matrix_final(gz, inter->init.matrix_final);
if (use_snap) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_VIEW3D: {
inter->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
- CTX_data_main(C), CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
+ CTX_data_scene(C), 0, CTX_wm_region(C), CTX_wm_view3d(C));
break;
}
default:
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
new file mode 100644
index 00000000000..a3921791427
--- /dev/null
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -0,0 +1,560 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file snap3d_gizmo.c
+ * \ingroup edgizmolib
+ *
+ * \name Snap Gizmo
+ *
+ * 3D Gizmo
+ *
+ * \brief Snap gizmo which exposes the location, normal and index in the props.
+ */
+
+#include "BLI_math.h"
+
+#include "DNA_scene_types.h"
+
+#include "BKE_context.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h" /* icons */
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "DEG_depsgraph_query.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "wm.h"
+
+/* own includes */
+#include "../gizmo_geometry.h"
+#include "../gizmo_library_intern.h"
+
+typedef struct SnapGizmo3D {
+ wmGizmo gizmo;
+ PropertyRNA *prop_prevpoint;
+ PropertyRNA *prop_location;
+ PropertyRNA *prop_normal;
+ PropertyRNA *prop_elem_index;
+ PropertyRNA *prop_snap_force;
+
+ /* We could have other snap contexts, for now only support 3D view. */
+ SnapObjectContext *snap_context_v3d;
+ int mval[2];
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmKeyMap *keymap;
+ int snap_on;
+ bool invert_snap;
+#endif
+ int use_snap_override;
+ short snap_elem;
+} SnapGizmo3D;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+static bool invert_snap(const wmGizmo *gz, const wmWindowManager *wm, const wmEvent *event)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ wmKeyMap *keymap = WM_keymap_active(wm, gizmo_snap->keymap);
+
+ const int snap_on = gizmo_snap->snap_on;
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+
+ if (kmi->propvalue == snap_on) {
+ if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
+ (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
+ (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
+ ((kmi->type == EVT_OSKEY) && event->oskey)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name ED_gizmo_library specific API
+ * \{ */
+
+void ED_gizmotypes_snap_3d_draw_util(RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type)
+{
+ if (!loc_prev && !loc_curr) {
+ return;
+ }
+
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
+
+ /* The size of the circle is larger than the vertex size.
+ * This prevents a drawing overlaps the other. */
+ float radius = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (loc_curr) {
+ immUniformColor4ubv(color_point);
+ imm_drawcircball(loc_curr, ED_view3d_pixel_size(rv3d, loc_curr) * radius, view_inv, pos);
+
+ /* draw normal if needed */
+ if (normal) {
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_curr);
+ immVertex3f(pos, loc_curr[0] + normal[0], loc_curr[1] + normal[1], loc_curr[2] + normal[2]);
+ immEnd();
+ }
+ }
+
+ if (loc_prev) {
+ /* Draw an "X" indicating where the previous snap point is.
+ * This is useful for indicating perpendicular snap. */
+
+ /* v1, v2, v3 and v4 indicate the coordinates of the ends of the "X". */
+ float vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
+
+ /* Multiply by 0.75f so that the final size of the "X" is close to that of
+ * the circle.
+ * (A closer value is 0.7071f, but we don't need to be exact here). */
+ float x_size = 0.75f * radius * ED_view3d_pixel_size(rv3d, loc_prev);
+
+ mul_v3_v3fl(vx, view_inv[0], x_size);
+ mul_v3_v3fl(vy, view_inv[1], x_size);
+
+ add_v3_v3v3(v1, vx, vy);
+ sub_v3_v3v3(v2, vx, vy);
+ negate_v3_v3(v3, v1);
+ negate_v3_v3(v4, v2);
+
+ add_v3_v3(v1, loc_prev);
+ add_v3_v3(v2, loc_prev);
+ add_v3_v3(v3, loc_prev);
+ add_v3_v3(v4, loc_prev);
+
+ immUniformColor4ubv(color_line);
+ immBegin(GPU_PRIM_LINES, 4);
+ immVertex3fv(pos, v3);
+ immVertex3fv(pos, v1);
+ immVertex3fv(pos, v4);
+ immVertex3fv(pos, v2);
+ immEnd();
+
+ if (loc_curr && (snap_elem_type & SCE_SNAP_MODE_EDGE_PERPENDICULAR)) {
+ /* Dashed line. */
+ immUnbindProgram();
+
+ 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]);
+ immUniform1f("dash_width", 6.0f * U.pixelsize);
+ immUniform1f("dash_factor", 1.0f / 4.0f);
+ immUniformColor4ubv(color_line);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, loc_prev);
+ immVertex3fv(pos, loc_curr);
+ immEnd();
+ }
+ }
+
+ immUnbindProgram();
+}
+
+SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(Scene *scene,
+ const ARegion *region,
+ const View3D *v3d,
+ wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d == NULL) {
+ gizmo_snap->snap_context_v3d = ED_transform_snap_object_context_create_view3d(
+ scene, 0, region, v3d);
+ }
+ return gizmo_snap->snap_context_v3d;
+}
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ return gizmo_snap->invert_snap;
+}
+void ED_gizmotypes_snap_3d_toggle_set(wmGizmo *gz, bool enable)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = (int)enable;
+}
+
+void ED_gizmotypes_snap_3d_toggle_clear(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ gizmo_snap->use_snap_override = -1;
+}
+
+short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const ARegion *region,
+ const View3D *v3d,
+ const wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ float co[3], no[3];
+ short snap_elem = 0;
+ int snap_elem_index[3] = {-1, -1, -1};
+ int index = -1;
+
+ if (gizmo_snap->use_snap_override != -1) {
+ if (gizmo_snap->use_snap_override == false) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (wm && wm->winactive) {
+ gizmo_snap->invert_snap = invert_snap(gz, wm, wm->winactive->eventstate);
+ }
+
+ if (gizmo_snap->use_snap_override == -1) {
+ const ToolSettings *ts = scene->toolsettings;
+ if (gizmo_snap->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
+ gizmo_snap->snap_elem = 0;
+ return 0;
+ }
+ }
+#else
+ UNUSED_VARS(wm);
+#endif
+
+ wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "snap_elements");
+ int snap_elements = RNA_property_enum_get(&gz_prop->ptr, gz_prop->prop);
+ if (gz_prop->prop != gizmo_snap->prop_snap_force) {
+ int snap_elements_force = RNA_property_enum_get(gz->ptr, gizmo_snap->prop_snap_force);
+ snap_elements |= snap_elements_force;
+ }
+ snap_elements &= (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR);
+
+ if (snap_elements) {
+ float prev_co[3] = {0.0f};
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_co);
+ }
+ else {
+ snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
+ }
+
+ float dist_px = 12.0f * U.pixelsize;
+
+ ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
+ snap_elem = ED_transform_snap_object_project_view3d_ex(gizmo_snap->snap_context_v3d,
+ depsgraph,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ .use_occlusion_test = true,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ NULL);
+ }
+
+ if (snap_elem == 0) {
+ RegionView3D *rv3d = region->regiondata;
+ ED_view3d_win_to_3d(v3d, region, rv3d->ofs, mval_fl, co);
+ zero_v3(no);
+ }
+ else if (snap_elem == SCE_SNAP_MODE_VERTEX) {
+ snap_elem_index[0] = index;
+ }
+ else if (snap_elem &
+ (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) {
+ snap_elem_index[2] = index;
+ }
+
+ gizmo_snap->snap_elem = snap_elem;
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_location, co);
+ RNA_property_float_set_array(gz->ptr, gizmo_snap->prop_normal, no);
+ RNA_property_int_set_array(gz->ptr, gizmo_snap->prop_elem_index, snap_elem_index);
+
+ if (r_loc) {
+ copy_v3_v3(r_loc, co);
+ }
+ if (r_nor) {
+ copy_v3_v3(r_nor, no);
+ }
+
+ return snap_elem;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name GIZMO_GT_snap_3d
+ * \{ */
+
+static void gizmo_snap_setup(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+
+ /* For quick access to the props. */
+ gizmo_snap->prop_prevpoint = RNA_struct_find_property(gz->ptr, "prev_point");
+ gizmo_snap->prop_location = RNA_struct_find_property(gz->ptr, "location");
+ gizmo_snap->prop_normal = RNA_struct_find_property(gz->ptr, "normal");
+ gizmo_snap->prop_elem_index = RNA_struct_find_property(gz->ptr, "snap_elem_index");
+ gizmo_snap->prop_snap_force = RNA_struct_find_property(gz->ptr, "snap_elements_force");
+
+ gizmo_snap->use_snap_override = -1;
+
+ /* Prop fallback. */
+ WM_gizmo_target_property_def_rna(gz, "snap_elements", gz->ptr, "snap_elements_force", -1);
+
+ /* Flags. */
+ gz->flag |= WM_GIZMO_NO_TOOLTIP;
+}
+
+static void gizmo_snap_draw(const bContext *C, wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_elem == 0) {
+ return;
+ }
+
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
+
+ /* Ideally, we shouldn't assign values here.
+ * But `test_select` is not called during navigation.
+ * And `snap_elem` is not really useful in this case. */
+ if ((rv3d->rflag & RV3D_NAVIGATING) ||
+ (!(gz->state & WM_GIZMO_STATE_HIGHLIGHT) && !wm_gizmomap_modal_get(region->gizmo_map))) {
+ gizmo_snap->snap_elem = 0;
+ return;
+ }
+
+ float location[3], prev_point_stack[3], *prev_point = NULL;
+ uchar color_line[4], color_point[4];
+
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_location, location);
+
+ UI_GetThemeColor3ubv(TH_TRANSFORM, color_line);
+ color_line[3] = 128;
+
+ rgba_float_to_uchar(color_point, gz->color);
+
+ if (RNA_property_is_set(gz->ptr, gizmo_snap->prop_prevpoint)) {
+ RNA_property_float_get_array(gz->ptr, gizmo_snap->prop_prevpoint, prev_point_stack);
+ prev_point = prev_point_stack;
+ }
+
+ GPU_line_smooth(false);
+
+ GPU_line_width(1.0f);
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, prev_point, location, NULL, color_line, color_point, gizmo_snap->snap_elem);
+}
+
+static int gizmo_snap_test_select(bContext *C, wmGizmo *gz, const int mval[2])
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ wmWindowManager *wm = CTX_wm_manager(C);
+ if (gizmo_snap->keymap == NULL) {
+ gizmo_snap->keymap = WM_modalkeymap_find(wm->defaultconf, "Generic Gizmo Tweak Modal Map");
+ RNA_enum_value_from_id(gizmo_snap->keymap->modal_items, "SNAP_ON", &gizmo_snap->snap_on);
+ }
+
+ const bool invert = wm->winactive ? invert_snap(gz, wm, wm->winactive->eventstate) : false;
+ if (gizmo_snap->invert_snap == invert && gizmo_snap->mval[0] == mval[0] &&
+ gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+
+ gizmo_snap->invert_snap = invert;
+#else
+ if (gizmo_snap->mval[0] == mval[0] && gizmo_snap->mval[1] == mval[1]) {
+ /* Performance, do not update. */
+ return gizmo_snap->snap_elem ? 0 : -1;
+ }
+#endif
+ copy_v2_v2_int(gizmo_snap->mval, mval);
+
+ ARegion *region = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ const float mval_fl[2] = {UNPACK2(mval)};
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ gz, CTX_data_ensure_evaluated_depsgraph(C), region, v3d, NULL, mval_fl, NULL, NULL);
+
+ if (snap_elem) {
+ ED_region_tag_redraw_editor_overlays(region);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int gizmo_snap_modal(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event),
+ eWM_GizmoFlagTweak UNUSED(tweak_flag))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int gizmo_snap_invoke(bContext *UNUSED(C),
+ wmGizmo *UNUSED(gz),
+ const wmEvent *UNUSED(event))
+{
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void gizmo_snap_free(wmGizmo *gz)
+{
+ SnapGizmo3D *gizmo_snap = (SnapGizmo3D *)gz;
+ if (gizmo_snap->snap_context_v3d) {
+ ED_transform_snap_object_context_destroy(gizmo_snap->snap_context_v3d);
+ gizmo_snap->snap_context_v3d = NULL;
+ }
+}
+
+static void GIZMO_GT_snap_3d(wmGizmoType *gzt)
+{
+ /* identifiers */
+ gzt->idname = "GIZMO_GT_snap_3d";
+
+ /* api callbacks */
+ gzt->setup = gizmo_snap_setup;
+ gzt->draw = gizmo_snap_draw;
+ gzt->test_select = gizmo_snap_test_select;
+ gzt->modal = gizmo_snap_modal;
+ gzt->invoke = gizmo_snap_invoke;
+ gzt->free = gizmo_snap_free;
+
+ gzt->struct_size = sizeof(SnapGizmo3D);
+
+ const EnumPropertyItem *rna_enum_snap_element_items;
+ {
+ /* Get Snap Element Items enum. */
+ bool free;
+ PointerRNA toolsettings_ptr;
+ RNA_pointer_create(NULL, &RNA_ToolSettings, NULL, &toolsettings_ptr);
+ PropertyRNA *prop = RNA_struct_find_property(&toolsettings_ptr, "snap_elements");
+ RNA_property_enum_items(
+ NULL, &toolsettings_ptr, prop, &rna_enum_snap_element_items, NULL, &free);
+
+ BLI_assert(free == false);
+ }
+
+ /* Setup. */
+ 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,
+ "Snap Elements",
+ "");
+
+ RNA_def_float_vector(gzt->srna,
+ "prev_point",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Previous Point",
+ "Point that defines the location of the perpendicular snap",
+ FLT_MIN,
+ FLT_MAX);
+
+ /* Returns. */
+ RNA_def_float_vector(gzt->srna,
+ "location",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Location",
+ "Snap Point Location",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_float_vector(gzt->srna,
+ "normal",
+ 3,
+ NULL,
+ FLT_MIN,
+ FLT_MAX,
+ "Normal",
+ "Snap Point Normal",
+ FLT_MIN,
+ FLT_MAX);
+
+ RNA_def_int_vector(gzt->srna,
+ "snap_elem_index",
+ 3,
+ NULL,
+ INT_MIN,
+ INT_MAX,
+ "Snap Element",
+ "Array index of face, edge and vert snapped",
+ INT_MIN,
+ INT_MAX);
+
+ /* Read/Write. */
+ WM_gizmotype_target_property_def(gzt, "snap_elements", PROP_ENUM, 1);
+}
+
+void ED_gizmotypes_snap_3d(void)
+{
+ WM_gizmotype_append(GIZMO_GT_snap_3d);
+}
+
+/** \} */
diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c
index 5c396ca9041..22df7bbbf31 100644
--- a/source/blender/editors/gpencil/annotate_draw.c
+++ b/source/blender/editors/gpencil/annotate_draw.c
@@ -90,14 +90,54 @@ typedef enum eDrawStrokeFlags {
/* ----- Tool Buffer Drawing ------ */
+static void annotation_draw_stroke_arrow_buffer(uint pos,
+ const float *corner_point,
+ const float *arrow_coords,
+ const int arrow_style)
+{
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, arrow_style);
+
+ switch (arrow_style) {
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ immVertex2f(pos, arrow_coords[4], arrow_coords[5]);
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ break;
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ immVertex2f(pos, arrow_coords[0], arrow_coords[1]);
+ immVertex2f(pos, arrow_coords[4], arrow_coords[5]);
+ immVertex2f(pos, arrow_coords[6], arrow_coords[7]);
+ immVertex2f(pos, arrow_coords[2], arrow_coords[3]);
+ immVertex2f(pos, corner_point[0], corner_point[1]);
+ break;
+ default:
+ break;
+ }
+ immEnd();
+}
+
/* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */
-static void annotation_draw_stroke_buffer(const tGPspoint *points,
- int totpoints,
+static void annotation_draw_stroke_buffer(bGPdata *gps,
short thickness,
short dflag,
- short sflag,
const float ink[4])
{
+ bGPdata_Runtime runtime = gps->runtime;
+ const tGPspoint *points = runtime.sbuffer;
+ int totpoints = runtime.sbuffer_used;
+ short sflag = runtime.sbuffer_sflag;
+
int draw_points = 0;
/* error checking */
@@ -176,6 +216,26 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points,
}
immEnd();
+
+ /* Draw arrow stroke. */
+ if (totpoints > 1) {
+ /* Draw ending arrow stroke. */
+ if ((sflag & GP_STROKE_USE_ARROW_END) &&
+ (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ float end[2];
+ copy_v2_fl2(end, points[1].x, points[1].y);
+ annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style);
+ }
+ /* Draw starting arrow stroke. */
+ if ((sflag & GP_STROKE_USE_ARROW_START) &&
+ (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ float start[2];
+ copy_v2_fl2(start, points[0].x, points[0].y);
+ annotation_draw_stroke_arrow_buffer(
+ pos, start, runtime.arrow_start, runtime.arrow_start_style);
+ }
+ }
+
immUnbindProgram();
}
@@ -209,7 +269,6 @@ static void annotation_calc_2d_stroke_fxy(
/* draw a given stroke - just a single dot (only one point) */
static void annotation_draw_stroke_point(const bGPDspoint *points,
short thickness,
- short UNUSED(dflag),
short sflag,
int offsx,
int offsy,
@@ -252,12 +311,8 @@ static void annotation_draw_stroke_point(const bGPDspoint *points,
}
/* draw a given stroke in 3d (i.e. in 3d-space), using simple ogl lines */
-static void annotation_draw_stroke_3d(const bGPDspoint *points,
- int totpoints,
- short thickness,
- short UNUSED(sflag),
- const float ink[4],
- bool cyclic)
+static void annotation_draw_stroke_3d(
+ const bGPDspoint *points, int totpoints, short thickness, const float ink[4], bool cyclic)
{
float curpressure = points[0].pressure;
float cyclic_fpt[3];
@@ -333,13 +388,10 @@ static void annotation_draw_stroke_3d(const bGPDspoint *points,
immUnbindProgram();
}
-/* ----- Fancy 2D-Stroke Drawing ------ */
-
-/* draw a given stroke in 2d */
+/* Draw a given stroke in 2d. */
static void annotation_draw_stroke_2d(const bGPDspoint *points,
int totpoints,
short thickness_s,
- short dflag,
short sflag,
int offsx,
int offsy,
@@ -347,167 +399,84 @@ static void annotation_draw_stroke_2d(const bGPDspoint *points,
int winy,
const float ink[4])
{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
+ if (totpoints == 0) {
+ return;
}
+ float thickness = (float)thickness_s;
- /* Tessellation code - draw stroke as series of connected quads
- * (triangle strips in fact) with connection edges rotated to minimize shrinking artifacts,
- * and rounded endcaps.
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ const bGPDspoint *pt;
+ const bGPDspoint *pt_prev;
+ int draw_points = 0;
+ float co[2];
+ float oldpressure = points[0].pressure;
+ if (totpoints == 1) {
+ /* if drawing a single point, draw it larger */
+ GPU_point_size((float)(thickness + 2) * points->pressure);
+ immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
+ immUniformColor3fvAlpha(ink, ink[3]);
+ immBegin(GPU_PRIM_POINTS, 1);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ annotation_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ }
+ else {
+ /* draw stroke curve */
+ GPU_line_width(max_ff(oldpressure * thickness, 1.0));
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3fvAlpha(ink, ink[3]);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- annotation_calc_2d_stroke_fxy(&points->x, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* Get x and y coordinates from point2
- * (point1 has already been computed in previous iteration). */
- annotation_calc_2d_stroke_fxy(&pt2->x, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
+
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints);
+
+ for (int i = 0; i < totpoints; i++) {
+ pt = &points[i];
+ /* If there was a significant pressure change,
+ * stop the curve, change the thickness of the stroke,
+ * and continue drawing again (since line-width cannot change in middle of GL_LINE_STRIP).
+ */
+ if (fabsf(pt->pressure - oldpressure) > 0.2f) {
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ pt_prev = &points[i - 1];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
}
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
+ immEnd();
+ draw_points = 0;
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
- }
+ GPU_line_width(max_ff(pt->pressure * thickness, 1.0f));
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, totpoints - i + 1);
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(pos, t0);
- immVertex2fv(pos, t1);
+ /* need to roll-back one point to ensure that there are no gaps in the stroke */
+ if (i != 0) {
+ pt_prev = &points[i - 1];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ draw_points++;
+ }
+
+ oldpressure = pt->pressure; /* reset our threshold */
}
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
+ /* now the point we want */
+ annotation_calc_2d_stroke_fxy(&pt->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
+ draw_points++;
+ }
+ /* need to have 2 points to avoid immEnd assert error */
+ if (draw_points < 2) {
+ pt_prev = &points[0];
+ annotation_calc_2d_stroke_fxy(&pt_prev->x, sflag, offsx, offsy, winx, winy, co);
+ immVertex2fv(pos, co);
}
-
- immEnd();
- immUnbindProgram();
}
+
+ immEnd();
+ immUnbindProgram();
}
/* ----- Strokes Drawing ------ */
@@ -550,9 +519,7 @@ static bool annotation_can_draw_stroke(const bGPDstroke *gps, const int dflag)
}
/* draw a set of strokes */
-static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
- bGPDlayer *UNUSED(gpl),
- const bGPDframe *gpf,
+static void annotation_draw_strokes(const bGPDframe *gpf,
int offsx,
int offsy,
int winx,
@@ -587,11 +554,11 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
/* 3D Lines - OpenGL primitives-based */
if (gps->totpoints == 1) {
annotation_draw_stroke_point(
- gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
+ gps->points, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
else {
annotation_draw_stroke_3d(
- gps->points, gps->totpoints, lthick, gps->flag, color, gps->flag & GP_STROKE_CYCLIC);
+ gps->points, gps->totpoints, lthick, color, gps->flag & GP_STROKE_CYCLIC);
}
if (no_xray) {
@@ -605,164 +572,22 @@ static void annotation_draw_strokes(bGPdata *UNUSED(gpd),
/* 2D Strokes... */
if (gps->totpoints == 1) {
annotation_draw_stroke_point(
- gps->points, lthick, dflag, gps->flag, offsx, offsy, winx, winy, color);
- }
- else {
- annotation_draw_stroke_2d(gps->points,
- gps->totpoints,
- lthick,
- dflag,
- gps->flag,
- offsx,
- offsy,
- winx,
- winy,
- color);
- }
- }
- }
-
- GPU_program_point_size(false);
-}
-
-/* Draw selected verts for strokes being edited */
-static void annotation_draw_strokes_edit(bGPdata *UNUSED(gpd),
- bGPDlayer *gpl,
- const bGPDframe *gpf,
- int offsx,
- int offsy,
- int winx,
- int winy,
- short dflag,
- short UNUSED(lflag),
- float alpha)
-{
- /* if alpha 0 do not draw */
- if (alpha == 0.0f) {
- return;
- }
-
- const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0;
- int mask_orig = 0;
-
- /* set up depth masks... */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig);
- glDepthMask(0);
- GPU_depth_test(true);
-
- /* first arg is normally rv3d->dist, but this isn't
- * available here and seems to work quite well without */
- bglPolygonOffset(1.0f, 1.0f);
- }
- }
-
- GPU_program_point_size(true);
-
- /* draw stroke verts */
- LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
- /* check if stroke can be drawn */
- if (annotation_can_draw_stroke(gps, dflag) == false) {
- continue;
- }
-
- /* Optimization: only draw points for selected strokes
- * We assume that selected points can only occur in
- * strokes that are selected too.
- */
- if ((gps->flag & GP_STROKE_SELECT) == 0) {
- continue;
- }
-
- /* Get size of verts:
- * - The selected state needs to be larger than the unselected state so that
- * they stand out more.
- * - We use the theme setting for size of the unselected verts
- */
- float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE);
- float vsize;
- if ((int)bsize > 8) {
- vsize = 10.0f;
- bsize = 8.0f;
- }
- else {
- vsize = bsize + 2;
- }
-
- /* Why? */
- UNUSED_VARS(vsize);
-
- float selectColor[4];
- UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor);
- selectColor[3] = alpha;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos; /* specified later */
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (gps->flag & GP_STROKE_3DSPACE) {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
- else {
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR);
- }
-
- immBegin(GPU_PRIM_POINTS, gps->totpoints);
-
- /* Draw all the stroke points (selected or not) */
- bGPDspoint *pt = gps->points;
- for (int i = 0; i < gps->totpoints; i++, pt++) {
- /* size and color first */
- immAttr3fv(color, gpl->color);
- immAttr1f(size, bsize);
-
- /* then position */
- if (gps->flag & GP_STROKE_3DSPACE) {
- immVertex3fv(pos, &pt->x);
+ gps->points, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
else {
- float co[2];
- annotation_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co);
- immVertex2fv(pos, co);
+ annotation_draw_stroke_2d(
+ gps->points, gps->totpoints, lthick, gps->flag, offsx, offsy, winx, winy, color);
}
}
-
- immEnd();
- immUnbindProgram();
}
GPU_program_point_size(false);
-
- /* clear depth mask */
- if (dflag & GP_DRAWDATA_ONLY3D) {
- if (no_xray) {
- glDepthMask(mask_orig);
- GPU_depth_test(false);
-
- bglPolygonOffset(0.0, 0.0);
-#if 0
- glDisable(GL_POLYGON_OFFSET_LINE);
- glPolygonOffset(0, 0);
-#endif
- }
- }
}
/* ----- General Drawing ------ */
/* draw onion-skinning for a layer */
-static void annotation_draw_onionskins(bGPdata *gpd,
- bGPDlayer *gpl,
- bGPDframe *gpf,
- int offsx,
- int offsy,
- int winx,
- int winy,
- int UNUSED(cfra),
- int dflag)
+static void annotation_draw_onionskins(
+ bGPDlayer *gpl, bGPDframe *gpf, int offsx, int offsy, int winx, int winy, int dflag)
{
const float alpha = 1.0f;
float color[4];
@@ -781,8 +606,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gpf->framenum - gf->framenum) / (float)(gpl->gstep + 1));
color[3] = alpha * fac * 0.66f;
- annotation_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
else {
break;
@@ -793,8 +617,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->prev) {
color[3] = (alpha / 7);
- annotation_draw_strokes(
- gpd, gpl, gpf->prev, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gpf->prev, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
}
else {
@@ -815,8 +638,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* alpha decreases with distance from curframe index */
fac = 1.0f - ((float)(gf->framenum - gpf->framenum) / (float)(gpl->gstep_next + 1));
color[3] = alpha * fac * 0.66f;
- annotation_draw_strokes(
- gpd, gpl, gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gf, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
else {
break;
@@ -827,8 +649,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* draw the strokes for the ghost frames (at half of the alpha set by user) */
if (gpf->next) {
color[3] = (alpha / 4);
- annotation_draw_strokes(
- gpd, gpl, gpf->next, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
+ annotation_draw_strokes(gpf->next, offsx, offsy, winx, winy, dflag, gpl->thickness, color);
}
}
else {
@@ -838,7 +659,7 @@ static void annotation_draw_onionskins(bGPdata *gpd,
/* loop over gpencil data layers, drawing them */
static void annotation_draw_data_layers(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
float ink[4];
@@ -875,26 +696,11 @@ static void annotation_draw_data_layers(
/* Draw 'onionskins' (frame left + right) */
if (gpl->onion_flag & GP_LAYER_ONIONSKIN) {
- annotation_draw_onionskins(gpd, gpl, gpf, offsx, offsy, winx, winy, cfra, dflag);
+ annotation_draw_onionskins(gpl, gpf, offsx, offsy, winx, winy, dflag);
}
/* draw the strokes already in active frame */
- annotation_draw_strokes(gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
-
- /* Draw verts of selected strokes:
- * - when doing OpenGL renders, we don't want to be showing these, as that ends up flickering
- * - locked layers can't be edited, so there's no point showing these verts
- * as they will have no bearings on what gets edited
- * - only show when in editmode, since operators shouldn't work otherwise
- * (NOTE: doing it this way means that the toggling editmode
- * shows visible change immediately).
- */
- /* XXX: perhaps we don't want to show these when users are drawing... */
- if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 &&
- (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
- annotation_draw_strokes_edit(
- gpd, gpl, gpf, offsx, offsy, winx, winy, dflag, gpl->flag, alpha);
- }
+ annotation_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, lthick, ink);
/* Check if may need to draw the active stroke cache, only if this layer is the active layer
* that is being edited. (Stroke buffer is currently stored in gp-data)
@@ -907,67 +713,14 @@ static void annotation_draw_data_layers(
* It should also be noted that sbuffer contains temporary point types
* i.e. tGPspoints NOT bGPDspoints
*/
- annotation_draw_stroke_buffer(gpd->runtime.sbuffer,
- gpd->runtime.sbuffer_used,
- lthick,
- dflag,
- gpd->runtime.sbuffer_sflag,
- ink);
+ annotation_draw_stroke_buffer(gpd, lthick, dflag, ink);
}
}
}
-/* draw a short status message in the top-right corner */
-static void annotation_draw_status_text(const bGPdata *gpd, ARegion *region)
-{
-
- /* Cannot draw any status text when drawing OpenGL Renders */
- if (G.f & G_FLAG_RENDER_VIEWPORT) {
- return;
- }
-
- /* Get bounds of region - Necessary to avoid problems with region overlap */
- const rcti *rect = ED_region_visible_rect(region);
-
- /* for now, this should only be used to indicate when we are in stroke editmode */
- if (gpd->flag & GP_DATA_STROKE_EDITMODE) {
- const char *printable = IFACE_("GPencil Stroke Editing");
- float printable_size[2];
-
- int font_id = BLF_default();
-
- BLF_width_and_height(
- font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
-
- int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0];
- int yco = (rect->ymax - U.widget_unit);
-
- /* text label */
- UI_FontThemeColor(font_id, TH_TEXT_HI);
-#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#else
- BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
-#endif
-
- /* grease pencil icon... */
- // XXX: is this too intrusive?
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- GPU_blend(true);
-
- xco -= U.widget_unit;
- yco -= (int)printable_size[1] / 2;
-
- UI_icon_draw(xco, yco, ICON_GREASEPENCIL);
-
- GPU_blend(false);
- }
-}
-
/* draw grease-pencil datablock */
static void annotation_draw_data(
- bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha)
+ bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag)
{
/* turn on smooth lines (i.e. anti-aliasing) */
GPU_line_smooth(true);
@@ -978,7 +731,7 @@ static void annotation_draw_data(
GPU_blend(true);
/* draw! */
- annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag);
/* turn off alpha blending, then smooth lines */
GPU_blend(false); // alpha blending
@@ -998,7 +751,6 @@ static void annotation_draw_data_all(Scene *scene,
const char spacetype)
{
bGPdata *gpd_source = NULL;
- float alpha = 1.0f;
if (scene) {
if (spacetype == SPACE_VIEW3D) {
@@ -1011,14 +763,14 @@ static void annotation_draw_data_all(Scene *scene,
}
if (gpd_source) {
- annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag);
}
}
/* scene/clip data has already been drawn, only object/track data is drawn here
* if gpd_source == gpd, we don't have any object/track data and we can skip */
if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) {
- annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha);
+ annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag);
}
}
@@ -1034,7 +786,7 @@ static void annotation_draw_data_all(Scene *scene,
void ED_annotation_draw_2dimage(const bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -1047,7 +799,7 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* calculate rect */
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: /* image */
case SPACE_CLIP: /* clip */
{
@@ -1096,7 +848,7 @@ void ED_annotation_draw_2dimage(const bContext *C)
}
/* draw it! */
- annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, sa->spacetype);
+ annotation_draw_data_all(scene, gpd, offsx, offsy, sizex, sizey, CFRA, dflag, area->spacetype);
}
/**
@@ -1109,13 +861,13 @@ void ED_annotation_draw_2dimage(const bContext *C)
void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
int dflag = 0;
/* check that we have grease-pencil stuff to draw */
- if (sa == NULL) {
+ if (area == NULL) {
return;
}
bGPdata *gpd = ED_annotation_data_get_active(C);
@@ -1126,7 +878,7 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
/* special hack for Image Editor */
/* FIXME: the opengl poly-strokes don't draw at right thickness when done this way,
* so disabled. */
- if (ELEM(sa->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
+ if (ELEM(area->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
dflag |= GP_DRAWDATA_IEDITHACK;
}
@@ -1139,16 +891,11 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d)
}
annotation_draw_data_all(
- scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, sa->spacetype);
-
- /* draw status text (if in screen/pixel-space) */
- if (!onlyv2d) {
- annotation_draw_status_text(gpd, region);
- }
+ scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype);
}
-/* draw annotations sketches to specified 3d-view assuming that matrices are already set correctly
- * Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
+/* draw annotations sketches to specified 3d-view assuming that matrices are already set
+ * correctly Note: this gets called twice - first time with only3d=true to draw 3d-strokes,
* second time with only3d=false for screen-aligned strokes */
void ED_annotation_draw_view3d(
Scene *scene, struct Depsgraph *depsgraph, View3D *v3d, ARegion *region, bool only3d)
@@ -1158,7 +905,8 @@ void ED_annotation_draw_view3d(
int offsx, offsy, winx, winy;
/* check that we have grease-pencil stuff to draw */
- /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data */
+ /* XXX: Hardcoded reference here may get out of sync if we change how we fetch annotation data
+ */
bGPdata *gpd = scene->gpd;
if (gpd == NULL) {
return;
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 9f2c4070b18..723c7d214e3 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -100,6 +100,9 @@ typedef enum eGPencil_PaintFlags {
GP_PAINTFLAG_STROKEADDED = (1 << 1),
GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2),
GP_PAINTFLAG_SELECTMASK = (1 << 3),
+ /* Flags used to indicate if stabilization is being used. */
+ GP_PAINTFLAG_USE_STABILIZER = (1 << 7),
+ GP_PAINTFLAG_USE_STABILIZER_TEMP = (1 << 8),
} eGPencil_PaintFlags;
/* Temporary 'Stroke' Operation data
@@ -114,7 +117,7 @@ typedef struct tGPsdata {
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
- ScrArea *sa;
+ ScrArea *area;
/** region where painting originated. */
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
@@ -148,6 +151,11 @@ typedef struct tGPsdata {
/** radius of influence for eraser. */
short radius;
+ /* Stabilizer. */
+ float stabilizer_factor;
+ char stabilizer_radius;
+ void *stabilizer_cursor;
+
/** current mouse-position. */
float mval[2];
/** previous recorded mouse-position. */
@@ -278,6 +286,18 @@ static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2
* - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
*/
}
+ /* If lazy mouse, check minimum distance. */
+ else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ if ((dx * dx + dy * dy) > (p->stabilizer_radius * p->stabilizer_radius)) {
+ return true;
+ }
+ else {
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ copy_v2_v2(p->mval, p->mvalo);
+ return false;
+ }
+ }
else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) {
return true;
@@ -418,6 +438,85 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
}
+static void gp_stroke_arrow_calc_points_segment(float stroke_points[8],
+ const float ref_point[2],
+ const float dir_cw[2],
+ const float dir_ccw[2],
+ const float lenght,
+ const float sign)
+{
+ stroke_points[0] = ref_point[0] + dir_cw[0] * lenght * sign;
+ stroke_points[1] = ref_point[1] + dir_cw[1] * lenght * sign;
+ stroke_points[2] = ref_point[0] + dir_ccw[0] * lenght * sign;
+ stroke_points[3] = ref_point[1] + dir_ccw[1] * lenght * sign;
+}
+
+static void gp_stroke_arrow_calc_points(tGPspoint *point,
+ const float stroke_dir[2],
+ float corner[2],
+ float stroke_points[8],
+ const int arrow_style)
+{
+ const int arrow_lenght = 8;
+ float norm_dir[2];
+ copy_v2_v2(norm_dir, stroke_dir);
+ normalize_v2(norm_dir);
+ const float inv_norm_dir_clockwise[2] = {norm_dir[1], -norm_dir[0]};
+ const float inv_norm_dir_counterclockwise[2] = {-norm_dir[1], norm_dir[0]};
+
+ switch (arrow_style) {
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ mul_v2_fl(norm_dir, arrow_lenght);
+ stroke_points[0] = corner[0] + inv_norm_dir_clockwise[0] * arrow_lenght + norm_dir[0];
+ stroke_points[1] = corner[1] + inv_norm_dir_clockwise[1] * arrow_lenght + norm_dir[1];
+ stroke_points[2] = corner[0] + inv_norm_dir_counterclockwise[0] * arrow_lenght + norm_dir[0];
+ stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_lenght + norm_dir[1];
+ break;
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght,
+ 1.0f);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ mul_v2_fl(norm_dir, arrow_lenght);
+ if (point != NULL) {
+ add_v2_v2(&point->x, norm_dir);
+ copy_v2_v2(corner, &point->x);
+ }
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght,
+ -1.0f);
+ stroke_points[4] = corner[0] - norm_dir[0];
+ stroke_points[5] = corner[1] - norm_dir[1];
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ mul_v2_fl(norm_dir, arrow_lenght * 1.5f);
+ if (point != NULL) {
+ add_v2_v2(&point->x, norm_dir);
+ copy_v2_v2(corner, &point->x);
+ }
+ gp_stroke_arrow_calc_points_segment(stroke_points,
+ corner,
+ inv_norm_dir_clockwise,
+ inv_norm_dir_counterclockwise,
+ arrow_lenght * 0.75f,
+ -1.0f);
+ stroke_points[4] = stroke_points[0] - norm_dir[0];
+ stroke_points[5] = stroke_points[1] - norm_dir[1];
+ stroke_points[6] = stroke_points[2] - norm_dir[0];
+ stroke_points[7] = stroke_points[3] - norm_dir[1];
+ break;
+ default:
+ break;
+ }
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
@@ -457,6 +556,32 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
gpd->runtime.sbuffer_used = 2;
+
+ /* Arrows. */
+ if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) {
+ /* Store start and end point coords for arrows. */
+ float end[2];
+ copy_v2_v2(end, &pt->x);
+ pt = ((tGPspoint *)(gpd->runtime.sbuffer));
+ float start[2];
+ copy_v2_v2(start, &pt->x);
+
+ /* Arrow end corner. */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) {
+ pt++;
+ float e_heading[2] = {start[0] - end[0], start[1] - end[1]};
+ /* Calculate points for ending arrow. */
+ gp_stroke_arrow_calc_points(
+ pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style);
+ }
+ /* Arrow start corner. */
+ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) {
+ float s_heading[2] = {end[0] - start[0], end[1] - start[1]};
+ /* Calculate points for starting arrow. */
+ gp_stroke_arrow_calc_points(
+ NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style);
+ }
+ }
}
/* can keep carrying on this way :) */
@@ -481,16 +606,20 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* increment counters */
gpd->runtime.sbuffer_used++;
- /* smooth while drawing previous points with a reduction factor for previous */
- for (int s = 0; s < 3; s++) {
- gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s);
+
+ /* Don't smooth if stabilizer is on. */
+ if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ /* smooth while drawing previous points with a reduction factor for previous */
+ for (int s = 0; s < 3; s++) {
+ gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s);
+ }
}
return GP_STROKEADD_NORMAL;
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
/* get pointer to destination point */
- pt = (tGPspoint *)(gpd->runtime.sbuffer);
+ pt = (tGPspoint *)gpd->runtime.sbuffer;
/* store settings */
copy_v2_v2(&pt->x, mval);
@@ -521,7 +650,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
* so initialize depth buffer before converting coordinates
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph,
@@ -552,6 +681,123 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
return GP_STROKEADD_INVALID;
}
+static void gp_stroke_arrow_init_point_default(bGPDspoint *pt)
+{
+ pt->pressure = 1.0f;
+ pt->strength = 1.0f;
+ pt->time = 1.0f;
+}
+
+static void gp_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3])
+{
+ copy_v3_v3(&pt->x, point);
+ gp_stroke_arrow_init_point_default(pt);
+}
+
+static void gp_stroke_arrow_init_point(
+ tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx)
+{
+ /* Note: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
+ float real_co[2] = {co[co_idx], co[co_idx + 1]};
+ copy_v2_v2(&ptc->x, real_co);
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+}
+
+static void gp_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints)
+{
+ /* Copy appropriate settings for stroke. */
+ gps->totpoints = totpoints;
+ /* Allocate enough memory for a continuous array for storage points. */
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+}
+
+static void gp_arrow_create_open(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float corner_point[3],
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+}
+
+static void gp_arrow_create_segm(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+}
+
+static void gp_arrow_create_closed(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+}
+
+static void gp_arrow_create_square(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ const float corner_point[3],
+ const float arrow_points[8])
+{
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6);
+ pt++;
+ gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
+ pt++;
+ gp_stroke_arrow_init_conv_point(pt, corner_point);
+}
+
+static void gp_arrow_create(tGPsdata *p,
+ tGPspoint *ptc,
+ bGPDspoint *pt,
+ bGPDstroke *arrow_stroke,
+ const float arrow_points[8],
+ const int style)
+{
+ float corner_conv[3];
+ copy_v3_v3(corner_conv, &pt->x);
+
+ switch (style) {
+ case GP_STROKE_ARROWSTYLE_SEGMENT:
+ gp_arrow_create_segm(p, ptc, pt, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_CLOSED:
+ gp_arrow_create_closed(p, ptc, pt, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_OPEN:
+ gp_arrow_create_open(p, ptc, pt, corner_conv, arrow_points);
+ break;
+ case GP_STROKE_ARROWSTYLE_SQUARE:
+ gp_arrow_create_square(p, ptc, pt, corner_conv, arrow_points);
+ break;
+ default:
+ break;
+ }
+ /* Link stroke to frame. */
+ BLI_addtail(&p->gpf->strokes, arrow_stroke);
+}
+
/* make a new stroke from the buffer data */
static void gp_stroke_newfrombuffer(tGPsdata *p)
{
@@ -637,17 +883,61 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
if (totelem == 2) {
- /* last point if applicable */
- ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1);
+ bGPdata_Runtime runtime = gpd->runtime;
- /* convert screen-coordinates to appropriate coordinates (and store them) */
+ /* Last point if applicable. */
+ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
+
+ /* Convert screen-coordinates to appropriate coordinates (and store them). */
gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
- /* copy pressure and time */
+ /* Copy pressure and time. */
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
+
+ /** Create arrow strokes. **/
+ /* End arrow stroke. */
+ if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) &&
+ (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ int totarrowpoints = runtime.arrow_end_style;
+
+ /* Setting up arrow stroke. */
+ bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
+ gp_stroke_arrow_allocate(e_arrow_gps, totarrowpoints);
+
+ /* Set pointer to first non-initialized point. */
+ pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints);
+
+ /* End point. */
+ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+
+ /* Fill and convert arrow points to create arrow shape. */
+ gp_arrow_create(p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style);
+ }
+ /* Start arrow stroke. */
+ if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) &&
+ (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) {
+ int totarrowpoints = runtime.arrow_start_style;
+
+ /* Setting up arrow stroke. */
+ bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false);
+ gp_stroke_arrow_allocate(s_arrow_gps, totarrowpoints);
+
+ /* Set pointer to first non-initialized point. */
+ pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints);
+
+ /* Start point. */
+ ptc = runtime.sbuffer;
+ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL);
+ gp_stroke_arrow_init_point_default(pt);
+
+ /* Fill and convert arrow points to create arrow shape. */
+ gp_arrow_create(p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style);
+ }
}
}
else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
@@ -793,7 +1083,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
const int x,
const int y)
{
- if ((p->sa->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
+ if ((p->area->spacetype == SPACE_VIEW3D) && (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH)) {
RegionView3D *rv3d = p->region->regiondata;
const int mval_i[2] = {x, y};
float mval_3d[3];
@@ -816,7 +1106,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
- const float mvalo[2],
const int radius,
const rcti *rect)
{
@@ -885,7 +1174,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
if ((gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
/* Edge is affected - Check individual points now */
@@ -921,9 +1210,9 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + p->radius;
rect.ymax = p->mval[1] + p->radius;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0);
}
@@ -937,8 +1226,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, p->radius, &rect);
+ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->radius, &rect);
}
}
}
@@ -998,7 +1287,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
* - must verify that region data is 3D-view (and not something else)
*/
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->align_flag = &ts->annotate_v3d_align;
@@ -1017,7 +1306,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* SpaceNode *snode = curarea->spacedata.first; */
/* set current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_v2d_align;
@@ -1027,7 +1316,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
SpaceSeq *sseq = curarea->spacedata.first;
/* set current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_seq_align;
@@ -1046,7 +1335,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
/* SpaceImage *sima = curarea->spacedata.first; */
/* set the current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_ima_align;
@@ -1062,7 +1351,7 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p)
}
/* set the current area */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->v2d = &region->v2d;
p->align_flag = &ts->gpencil_v2d_align;
@@ -1280,7 +1569,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_ERASER;
/* check if we should respect depth while erasing */
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
p->flags |= GP_PAINTFLAG_V3D_ERASER_DEPTH;
}
@@ -1290,7 +1579,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* disable eraser flags - so that we can switch modes during a session */
p->gpd->runtime.sbuffer_sflag &= ~GP_STROKE_ERASER;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if (p->gpl->flag & GP_LAYER_NO_XRAY) {
p->flags &= ~GP_PAINTFLAG_V3D_ERASER_DEPTH;
}
@@ -1303,8 +1592,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
+ if (p->area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->area->spacedata.first;
RegionView3D *rv3d = p->region->regiondata;
/* for camera view set the subrect */
@@ -1321,7 +1610,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gsc.gpd = p->gpd;
p->gsc.gpl = p->gpl;
- p->gsc.sa = p->sa;
+ p->gsc.area = p->area;
p->gsc.region = p->region;
p->gsc.v2d = p->v2d;
@@ -1332,7 +1621,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
+ switch (p->area->spacetype) {
case SPACE_VIEW3D: {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
@@ -1356,7 +1645,7 @@ static void gp_paint_strokeend(tGPsdata *p)
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->region);
@@ -1440,23 +1729,83 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
}
/* Turn brush cursor in 3D view on/off */
-static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
{
if (p->erasercursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ WM_paint_cursor_end(p->erasercursor);
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
NULL, /* XXX */
gpencil_draw_eraser,
p);
}
}
+static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
+{
+ ARegion *region = CTX_wm_region(C);
+ tGPsdata *p = (tGPsdata *)p_ptr;
+ bGPdata_Runtime runtime = p->gpd->runtime;
+ const tGPspoint *points = runtime.sbuffer;
+ int totpoints = runtime.sbuffer_used;
+ if (totpoints < 2) {
+ return;
+ }
+ const tGPspoint *pt = &points[totpoints - 1];
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ GPU_line_width(1.25f);
+ const float color[3] = {1.0f, 0.39f, 0.39f};
+
+ /* default radius and color */
+ float darkcolor[3];
+ const float radius = 4.0f;
+
+ /* Inner Ring: Color from UI panel */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius, 40);
+
+ /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
+ mul_v3_v3fl(darkcolor, color, 0.40f);
+ immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
+ imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
+
+ /* Rope Simple. */
+ immUniformColor4f(color[0], color[1], color[2], 0.8f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin);
+ immVertex2f(pos, x, y);
+ immEnd();
+
+ /* Returns back all GPU settings */
+ GPU_blend(false);
+ GPU_line_smooth(false);
+
+ immUnbindProgram();
+}
+
+/* Turn *stabilizer* brush cursor in 3D view on/off */
+static void gpencil_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable)
+{
+ if (p->stabilizer_cursor && !enable) {
+ /* clear cursor */
+ WM_paint_cursor_end(p->stabilizer_cursor);
+ p->stabilizer_cursor = NULL;
+ }
+ else if (enable && !p->stabilizer_cursor) {
+ /* enable cursor */
+ p->stabilizer_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p);
+ }
+}
/* Check if tablet eraser is being used (when processing events) */
static bool gpencil_is_tablet_eraser_active(const wmEvent *event)
@@ -1478,7 +1827,10 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* check size of buffer before cleanup, to determine if anything happened here */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) {
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
}
/* always store the new eraser size to be used again next time
@@ -1567,8 +1919,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
"ESC/Enter to end (or click outside this area)"));
break;
default:
- /* Do nothing - the others are self explanatory, exit quickly once the mouse is released
- * Showing any text would just be annoying as it would flicker.
+ /* Do nothing - the others are self explanatory, exit quickly once the mouse is
+ * released Showing any text would just be annoying as it would flicker.
*/
break;
}
@@ -1633,6 +1985,16 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph
/* Only add current point to buffer if mouse moved
* (even though we got an event, it might be just noise). */
else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) {
+ /* If lazy mouse, interpolate the last and current mouse positions. */
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ float now_mouse[2];
+ float last_mouse[2];
+ copy_v2_v2(now_mouse, p->mval);
+ copy_v2_v2(last_mouse, p->mvalo);
+ interp_v2_v2v2(now_mouse, now_mouse, last_mouse, min_ff(p->stabilizer_factor, .995f));
+ copy_v2_v2(p->mval, now_mouse);
+ }
+
/* try to add point */
short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
@@ -1688,8 +2050,23 @@ static void annotation_draw_apply_event(
p->mval[0] = (float)event->mval[0] - x;
p->mval[1] = (float)event->mval[1] - y;
+ /* Key to toggle stabilization. */
+ if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) {
+ /* Using permanent stabilization, shift will deactivate the flag. */
+ if (p->flags & (GP_PAINTFLAG_USE_STABILIZER)) {
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
+ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ }
+ }
+ /* Not using any stabilization flag. Activate temporal one. */
+ else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
+ }
/* verify key status for straight lines */
- if ((event->ctrl > 0) || (event->alt > 0)) {
+ else if ((event->ctrl > 0) || (event->alt > 0)) {
if (p->straight[0] == 0) {
int dx = abs((int)(p->mval[0] - p->mvalo[0]));
int dy = abs((int)(p->mval[1] - p->mvalo[1]));
@@ -1710,6 +2087,22 @@ static void annotation_draw_apply_event(
}
else {
p->straight[0] = 0;
+ /* We were using shift while having permanent stabilization actived,
+ so activate the temp flag back again. */
+ if (p->flags & GP_PAINTFLAG_USE_STABILIZER) {
+ if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ }
+ }
+ /* We are using the temporal stabilizer flag atm,
+ but shift is not pressed as well as the permanent flag is not used,
+ so we don't need the cursor anymore. */
+ else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
+ /* Reset temporal stabilizer flag and remove cursor. */
+ p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, false);
+ }
}
p->curtime = PIL_check_seconds_timer();
@@ -1897,11 +2290,34 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
/* TODO: set any additional settings that we can take from the events?
* TODO? if tablet is erasing, force eraser to be on? */
- /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */
+ /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway...
+ */
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ gpencil_draw_toggle_eraser_cursor(p, true);
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
+ if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_START;
+ p->gpd->runtime.arrow_start_style = RNA_enum_get(op->ptr, "arrowstyle_start");
+ }
+ if (RNA_enum_get(op->ptr, "arrowstyle_end") != GP_STROKE_ARROWSTYLE_NONE) {
+ p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_END;
+ p->gpd->runtime.arrow_end_style = RNA_enum_get(op->ptr, "arrowstyle_end");
+ }
+ }
+ else if (p->paintmode == GP_PAINTMODE_DRAW) {
+ p->stabilizer_factor = RNA_float_get(op->ptr, "stabilizer_factor");
+ p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius");
+ if (RNA_boolean_get(op->ptr, "use_stabilizer")) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
+ else if (event->shift > 0) {
+ p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP;
+ gpencil_draw_toggle_stabilizer_cursor(p, true);
+ }
}
/* set cursor
* NOTE: This may change later (i.e. intentionally via brush toggle,
@@ -1932,10 +2348,10 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
-static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *screen = CTX_wm_screen(C);
+ return (BLI_findindex(&screen->areabase, area_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
@@ -1945,7 +2361,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
- if (CTX_wm_area(C) != p->sa) {
+ if (CTX_wm_area(C) != p->area) {
printf("\t\t\tGP - wrong area execution abort!\n");
p->status = GP_STATUS_ERROR;
}
@@ -2107,7 +2523,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* toggle painting mode upon mouse-button movement
- * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only)
+ * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
+ * only)
* - RIGHTMOUSE = polyline (hotkey) / eraser (all)
* (Disabling RIGHTMOUSE case here results in bugs like [#32647])
* also making sure we have a valid event value, to not exit too early
@@ -2144,7 +2561,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* Just hiding this makes it seem like
* you can paint again...
*/
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
}
}
@@ -2169,18 +2586,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(
+ p->area, RGN_TYPE_ANY, event->x, event->y);
if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n",
current_region,
p->region,
event->x,
event->y,
- p->sa->totrct.xmin,
- p->sa->totrct.ymin,
- p->sa->totrct.xmax,
- p->sa->totrct.ymax);
+ p->area->totrct.xmin,
+ p->area->totrct.ymin,
+ p->area->totrct.xmax,
+ p->area->totrct.ymax);
}
if (current_region) {
@@ -2228,7 +2646,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p->paintmode = RNA_enum_get(op->ptr, "mode");
}
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+ gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER);
/* not painting, so start stroke (this should be mouse-button down) */
p = gpencil_stroke_begin(C, op);
@@ -2315,7 +2733,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa)) {
+ if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
else {
@@ -2370,6 +2788,19 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = {
{0, NULL, 0, NULL, NULL},
};
+static const EnumPropertyItem arrow_types[] = {
+ {GP_STROKE_ARROWSTYLE_NONE, "NONE", 0, "None", "Don't use any arrow/style in corner"},
+ {GP_STROKE_ARROWSTYLE_CLOSED, "ARROW", 0, "Arrow", "Use closed arrow style"},
+ {GP_STROKE_ARROWSTYLE_OPEN, "ARROW_OPEN", 0, "Open Arrow", "Use open arrow style"},
+ {GP_STROKE_ARROWSTYLE_SEGMENT,
+ "ARROW_OPEN_INVERTED",
+ 0,
+ "Segment",
+ "Use perpendicular segment style"},
+ {GP_STROKE_ARROWSTYLE_SQUARE, "DIAMOND", 0, "Square", "Use square style"},
+ {0, NULL, 0, NULL, NULL},
+};
+
void GPENCIL_OT_annotate(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2393,6 +2824,37 @@ void GPENCIL_OT_annotate(wmOperatorType *ot)
ot->prop = RNA_def_enum(
ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
+ /* properties */
+ prop = RNA_def_enum(
+ ot->srna, "arrowstyle_start", arrow_types, 0, "Start Arrow Style", "Stroke start style");
+ prop = RNA_def_enum(
+ ot->srna, "arrowstyle_end", arrow_types, 0, "End Arrow Style", "Stroke end style");
+ prop = RNA_def_boolean(ot->srna,
+ "use_stabilizer",
+ false,
+ "Stabilize Stroke",
+ "Helper to draw smooth and clean lines. Press Shift for an invert effect "
+ "(even if this option is not active)");
+ prop = RNA_def_float(ot->srna,
+ "stabilizer_factor",
+ 0.75f,
+ 0.0f,
+ 1.0f,
+ "Stabilizer Stroke Factor",
+ "Higher values gives a smoother stroke",
+ 0.0f,
+ 1.0f);
+ prop = RNA_def_int(ot->srna,
+ "stabilizer_radius",
+ 35,
+ 0,
+ 200,
+ "Stabilizer Stroke Radius",
+ "Minimun distance from last point before stroke continues",
+ 1,
+ 100);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+
prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 896ef7a9ad3..6d41e9bddbe 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -114,13 +114,6 @@ typedef enum eDrawStrokeFlags {
/* ----- Tool Buffer Drawing ------ */
/* helper functions to set color of buffer point */
-static void gp_set_point_uniform_color(const bGPDspoint *pt, const float ink[4])
-{
- float alpha = ink[3] * pt->strength;
- CLAMP(alpha, GPENCIL_STRENGTH_MIN, 1.0f);
- immUniformColor3fvAlpha(ink, alpha);
-}
-
static void gp_set_point_varying_color(const bGPDspoint *pt,
const float ink[4],
uint attr_id,
@@ -134,74 +127,8 @@ static void gp_set_point_varying_color(const bGPDspoint *pt,
immAttr4ub(attr_id, F2UB(ink[0]), F2UB(ink[1]), F2UB(ink[2]), F2UB(alpha));
}
-/* --------- 2D Stroke Drawing Helpers --------- */
-/* change in parameter list */
-static void gp_calc_2d_stroke_fxy(
- const float pt[3], short sflag, int offsx, int offsy, int winx, int winy, float r_co[2])
-{
- if (sflag & GP_STROKE_2DSPACE) {
- r_co[0] = pt[0];
- r_co[1] = pt[1];
- }
- else if (sflag & GP_STROKE_2DIMAGE) {
- const float x = (float)((pt[0] * winx) + offsx);
- const float y = (float)((pt[1] * winy) + offsy);
-
- r_co[0] = x;
- r_co[1] = y;
- }
- else {
- const float x = (float)(pt[0] / 100 * winx) + offsx;
- const float y = (float)(pt[1] / 100 * winy) + offsy;
-
- r_co[0] = x;
- r_co[1] = y;
- }
-}
/* ----------- Volumetric Strokes --------------- */
-/* draw a 2D strokes in "volumetric" style */
-static void gp_draw_stroke_volumetric_2d(const bGPDspoint *points,
- int totpoints,
- short thickness,
- short UNUSED(dflag),
- short sflag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
- uint color = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR);
- GPU_program_point_size(true);
- immBegin(GPU_PRIM_POINTS, totpoints);
-
- const bGPDspoint *pt = points;
- for (int i = 0; i < totpoints; i++, pt++) {
- /* transform position to 2D */
- float co[2];
- float fpt[3];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
-
- gp_set_point_varying_color(pt, ink, color, false);
- immAttr1f(size, pt->pressure * thickness); /* TODO: scale based on view transform */
- immVertex2f(pos, co[0], co[1]);
- }
-
- immEnd();
- immUnbindProgram();
- GPU_program_point_size(false);
-}
-
/* draw a 3D stroke in "volumetric" style */
static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
int totpoints,
@@ -232,136 +159,8 @@ static void gp_draw_stroke_volumetric_3d(const bGPDspoint *points,
GPU_program_point_size(false);
}
-/* --------------- Stroke Fills ----------------- */
-/* add a new fill point and texture coordinates to vertex buffer */
-static void gp_add_filldata_tobuffer(const bGPDspoint *pt,
- uint pos,
- uint texcoord,
- short flag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4])
-{
- float fpt[3];
- float co[2];
-
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* if 2d, need conversion */
- if (!(flag & GP_STROKE_3DSPACE)) {
- gp_calc_2d_stroke_fxy(fpt, flag, offsx, offsy, winx, winy, co);
- copy_v2_v2(fpt, co);
- fpt[2] = 0.0f; /* 2d always is z=0.0f */
- }
-
- immAttr2f(texcoord, pt->uv_fill[0], pt->uv_fill[1]); /* texture coordinates */
- immVertex3fv(pos, fpt); /* position */
-}
-
-/* draw fills for shapes */
-static void gp_draw_stroke_fill(bGPdata *gpd,
- bGPDstroke *gps,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float color[4])
-{
- BLI_assert(gps->totpoints >= 3);
- BLI_assert(gps->tot_triangles >= 1);
- const bool use_mat = (gpd->mat != NULL);
-
- Material *ma = (use_mat) ? gpd->mat[gps->mat_nr] : BKE_material_default_gpencil();
- MaterialGPencilStyle *gp_style = (ma) ? ma->gp_style : NULL;
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- uint texcoord = GPU_vertformat_attr_add(format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_GPENCIL_FILL);
-
- immUniformColor4fv(color);
- immUniform4fv("color2", gp_style->mix_rgba);
- immUniform1i("fill_type", gp_style->fill_style);
- immUniform1f("mix_factor", gp_style->mix_factor);
-
- immUniform1f("texture_angle", gp_style->texture_angle);
- immUniform2fv("texture_scale", gp_style->texture_scale);
- immUniform2fv("texture_offset", gp_style->texture_offset);
- immUniform1f("texture_opacity", gp_style->texture_opacity);
- immUniform1i("t_mix", (gp_style->flag & GP_MATERIAL_FILL_TEX_MIX) != 0);
- immUniform1i("t_flip", (gp_style->flag & GP_MATERIAL_FLIP_FILL) != 0);
-
- /* Draw all triangles for filling the polygon (cache must be calculated before) */
- immBegin(GPU_PRIM_TRIS, gps->tot_triangles * 3);
- /* TODO: use batch instead of immediate mode, to share vertices */
-
- const bGPDtriangle *stroke_triangle = gps->triangles;
- for (int i = 0; i < gps->tot_triangles; i++, stroke_triangle++) {
- for (int j = 0; j < 3; j++) {
- gp_add_filldata_tobuffer(&gps->points[stroke_triangle->verts[j]],
- pos,
- texcoord,
- gps->flag,
- offsx,
- offsy,
- winx,
- winy,
- diff_mat);
- }
- }
-
- immEnd();
- immUnbindProgram();
-}
-
/* ----- Existing Strokes Drawing (3D and Point) ------ */
-/* draw a given stroke - just a single dot (only one point) */
-static void gp_draw_stroke_point(const bGPDspoint *points,
- short thickness,
- short UNUSED(dflag),
- short sflag,
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- const bGPDspoint *pt = points;
-
- /* get final position using parent matrix */
- float fpt[3];
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- if (sflag & GP_STROKE_3DSPACE) {
- immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
- }
- else {
- immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA);
-
- /* get 2D coordinates of point */
- float co[3] = {0.0f};
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, co);
- copy_v3_v3(fpt, co);
- }
-
- gp_set_point_uniform_color(pt, ink);
- /* set point thickness (since there's only one of these) */
- immUniform1f("size", (float)(thickness + 2) * pt->pressure);
-
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(pos, fpt);
- immEnd();
-
- immUnbindProgram();
-}
-
/* draw a given stroke in 3d (i.e. in 3d-space) */
static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4], bool cyclic)
{
@@ -454,200 +253,6 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4
immUnbindProgram();
}
-/* ----- Fancy 2D-Stroke Drawing ------ */
-
-/* draw a given stroke in 2d */
-static void gp_draw_stroke_2d(const bGPDspoint *points,
- int totpoints,
- short thickness_s,
- short dflag,
- short sflag,
- bool UNUSED(debug),
- int offsx,
- int offsy,
- int winx,
- int winy,
- const float diff_mat[4][4],
- const float ink[4])
-{
- /* otherwise thickness is twice that of the 3D view */
- float thickness = (float)thickness_s * 0.5f;
-
- /* strokes in Image Editor need a scale factor, since units there are not pixels! */
- float scalefac = 1.0f;
- if ((dflag & GP_DRAWDATA_IEDITHACK) && (dflag & GP_DRAWDATA_ONLYV2D)) {
- scalefac = 0.001f;
- }
-
- /* TODO: fancy++ with the magic of shaders */
-
- /* tessellation code - draw stroke as series of connected quads (triangle strips in fact)
- * with connection edges rotated to minimize shrinking artifacts, and rounded endcaps.
- */
- {
- const bGPDspoint *pt1, *pt2;
- float s0[2], s1[2]; /* segment 'center' points */
- float pm[2]; /* normal from previous segment. */
- int i;
- float fpt[3];
-
- GPUVertFormat *format = immVertexFormat();
- const struct {
- uint pos, color;
- } attr_id = {
- .pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT),
- .color = GPU_vertformat_attr_add(
- format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT),
- };
-
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- immBegin(GPU_PRIM_TRI_STRIP, totpoints * 2 + 4);
-
- /* get x and y coordinates from first point */
- mul_v3_m4v3(fpt, diff_mat, &points->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s0);
-
- for (i = 0, pt1 = points, pt2 = points + 1; i < (totpoints - 1); i++, pt1++, pt2++) {
- float t0[2], t1[2]; /* tessellated coordinates */
- float m1[2], m2[2]; /* gradient and normal */
- float mt[2], sc[2]; /* gradient for thickness, point for end-cap */
- float pthick; /* thickness at segment point */
-
- /* Get x and y coordinates from point2
- * (point1 has already been computed in previous iteration). */
- mul_v3_m4v3(fpt, diff_mat, &pt2->x);
- gp_calc_2d_stroke_fxy(fpt, sflag, offsx, offsy, winx, winy, s1);
-
- /* calculate gradient and normal - 'angle'=(ny/nx) */
- m1[1] = s1[1] - s0[1];
- m1[0] = s1[0] - s0[0];
- normalize_v2(m1);
- m2[1] = -m1[0];
- m2[0] = m1[1];
-
- /* always use pressure from first point here */
- pthick = (pt1->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt1, ink, attr_id.color, false);
-
- /* if the first segment, start of segment is segment's normal */
- if (i == 0) {
- /* draw start cap first
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s0[0] - (m1[0] * pthick * 0.75f);
- sc[1] = s0[1] - (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* First two points of cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* calculate points for start of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of start cap (and first two points of first segment). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
- /* if not the first segment, use bisector of angle between segments */
- else {
- float mb[2]; /* bisector normal */
- float athick, dfac; /* actual thickness, difference between thicknesses */
-
- /* calculate gradient of bisector (as average of normals) */
- mb[0] = (pm[0] + m2[0]) / 2;
- mb[1] = (pm[1] + m2[1]) / 2;
- normalize_v2(mb);
-
- /* calculate gradient to apply
- * - as basis, use just pthick * bisector gradient
- * - if cross-section not as thick as it should be, add extra padding to fix it
- */
- mt[0] = mb[0] * pthick;
- mt[1] = mb[1] * pthick;
- athick = len_v2(mt);
- dfac = pthick - (athick * 2);
-
- if (((athick * 2.0f) < pthick) && (IS_EQF(athick, pthick) == 0)) {
- mt[0] += (mb[0] * dfac);
- mt[1] += (mb[1] * dfac);
- }
-
- /* calculate points for start of segment */
- t0[0] = s0[0] - mt[0];
- t0[1] = s0[1] - mt[1];
- t1[0] = s0[0] + mt[0];
- t1[1] = s0[1] + mt[1];
-
- /* Last two points of previous segment, and first two points of current segment. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* if last segment, also draw end of segment (defined as segment's normal) */
- if (i == totpoints - 2) {
- /* for once, we use second point's pressure (otherwise it won't be drawn) */
- pthick = (pt2->pressure * thickness * scalefac);
-
- /* color of point */
- gp_set_point_varying_color(pt2, ink, attr_id.color, false);
-
- /* calculate points for end of segment */
- mt[0] = m2[0] * pthick;
- mt[1] = m2[1] * pthick;
-
- t0[0] = s1[0] - mt[0];
- t0[1] = s1[1] - mt[1];
- t1[0] = s1[0] + mt[0];
- t1[1] = s1[1] + mt[1];
-
- /* Last two points of last segment (and first two points of end cap). */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
-
- /* draw end cap as last step
- * - make points slightly closer to center (about halfway across)
- */
- mt[0] = m2[0] * pthick * 0.5f;
- mt[1] = m2[1] * pthick * 0.5f;
- sc[0] = s1[0] + (m1[0] * pthick * 0.75f);
- sc[1] = s1[1] + (m1[1] * pthick * 0.75f);
-
- t0[0] = sc[0] - mt[0];
- t0[1] = sc[1] - mt[1];
- t1[0] = sc[0] + mt[0];
- t1[1] = sc[1] + mt[1];
-
- /* Last two points of end cap. */
- immVertex2fv(attr_id.pos, t0);
- immVertex2fv(attr_id.pos, t1);
- }
-
- /* store computed point2 coordinates as point1 ones of next segment. */
- copy_v2_v2(s0, s1);
- /* store stroke's 'natural' normal for next stroke to use */
- copy_v2_v2(pm, m2);
- }
-
- immEnd();
- immUnbindProgram();
- }
-}
-
/* ----- Strokes Drawing ------ */
/* Helper for doing all the checks on whether a stroke can be drawn */
@@ -691,7 +296,6 @@ static bool gp_can_draw_stroke(const bGPDstroke *gps, const int dflag)
static void gp_draw_strokes(tGPDdraw *tgpw)
{
float tcolor[4];
- float tfill[4];
short sthickness;
float ink[4];
const bool is_unique = (tgpw->gps != NULL);
@@ -748,37 +352,6 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
bglPolygonOffset(1.0f, 1.0f);
}
- /* 3D Fill */
- // if ((dflag & GP_DRAWDATA_FILL) && (gps->totpoints >= 3)) {
- if ((gps->totpoints >= 3) && (tgpw->disable_fill != 1)) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(tgpw->gpd,
- gps,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- color);
- }
- }
-
/* 3D Stroke */
/* set color using material tint color and opacity */
if (!tgpw->onion) {
@@ -811,21 +384,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
}
else {
/* 3D Lines - OpenGL primitives-based */
- if (gps->totpoints == 1) {
- if (tgpw->disable_fill != 1) {
- gp_draw_stroke_point(gps->points,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- }
- else {
+ if (gps->totpoints > 1) {
tgpw->gps = gps;
gp_draw_stroke_3d(tgpw, sthickness, ink, gps->flag & GP_STROKE_CYCLIC);
}
@@ -837,97 +396,6 @@ static void gp_draw_strokes(tGPDdraw *tgpw)
bglPolygonOffset(0.0, 0.0);
}
}
- else {
- /* 2D - Fill */
- if (gps->totpoints >= 3) {
- /* set color using material, tint color and opacity */
- interp_v3_v3v3(tfill, gp_style->fill_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tfill[3] = gp_style->fill_rgba[3] * tgpw->opacity;
- if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) {
- const float *color;
- if (!tgpw->onion) {
- color = tfill;
- }
- else {
- if (tgpw->custonion) {
- color = tgpw->tintcolor;
- }
- else {
- ARRAY_SET_ITEMS(tfill, UNPACK3(gp_style->fill_rgba), tgpw->tintcolor[3]);
- color = tfill;
- }
- }
- gp_draw_stroke_fill(tgpw->gpd,
- gps,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- color);
- }
- }
-
- /* 2D Strokes... */
- /* set color using material, tint color and opacity */
- if (!tgpw->onion) {
- interp_v3_v3v3(tcolor, gp_style->stroke_rgba, tgpw->tintcolor, tgpw->tintcolor[3]);
- tcolor[3] = gp_style->stroke_rgba[3] * tgpw->opacity;
- copy_v4_v4(ink, tcolor);
- }
- else {
- if (tgpw->custonion) {
- copy_v4_v4(ink, tgpw->tintcolor);
- }
- else {
- ARRAY_SET_ITEMS(tcolor, UNPACK3(gp_style->stroke_rgba), tgpw->opacity);
- copy_v4_v4(ink, tcolor);
- }
- }
- if (gp_style->mode == GP_MATERIAL_MODE_DOT) {
- /* blob/disk-based "volumetric" drawing */
- gp_draw_stroke_volumetric_2d(gps->points,
- gps->totpoints,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- else {
- /* normal 2D strokes */
- if (gps->totpoints == 1) {
- gp_draw_stroke_point(gps->points,
- sthickness,
- tgpw->dflag,
- gps->flag,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- else {
- gp_draw_stroke_2d(gps->points,
- gps->totpoints,
- sthickness,
- tgpw->dflag,
- gps->flag,
- false,
- tgpw->offsx,
- tgpw->offsy,
- tgpw->winx,
- tgpw->winy,
- tgpw->diff_mat,
- ink);
- }
- }
- }
/* if only one stroke, exit from loop */
if (is_unique) {
break;
diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c
index 9566495715a..962a74d9e6f 100644
--- a/source/blender/editors/gpencil/gpencil_armature.c
+++ b/source/blender/editors/gpencil/gpencil_armature.c
@@ -481,8 +481,7 @@ static void gpencil_object_vgroup_calc_from_armature(const bContext *C,
DEG_relations_tag_update(CTX_data_main(C));
}
-bool ED_gpencil_add_armature_weights(
- const bContext *C, ReportList *reports, Object *ob, Object *ob_arm, int mode)
+bool ED_gpencil_add_armature(const bContext *C, ReportList *reports, Object *ob, Object *ob_arm)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
@@ -492,7 +491,7 @@ bool ED_gpencil_add_armature_weights(
}
/* if no armature modifier, add a new one */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Armature);
if (md == NULL) {
md = ED_object_gpencil_modifier_add(
reports, bmain, scene, ob, "Armature", eGpencilModifierType_Armature);
@@ -516,11 +515,24 @@ bool ED_gpencil_add_armature_weights(
return false;
}
}
+ return true;
+}
+
+bool ED_gpencil_add_armature_weights(
+ const bContext *C, ReportList *reports, Object *ob, Object *ob_arm, int mode)
+{
+ if (ob == NULL) {
+ return false;
+ }
+
+ bool success = ED_gpencil_add_armature(C, reports, ob, ob_arm);
/* add weights */
- gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+ if (success) {
+ gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
+ }
- return true;
+ return success;
}
/* ***************** Generate armature weights ************************** */
static bool gpencil_generate_weights_poll(bContext *C)
@@ -543,7 +555,7 @@ static bool gpencil_generate_weights_poll(bContext *C)
}
/* need some armature in the view layer */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->type == OB_ARMATURE) {
return true;
}
@@ -578,8 +590,8 @@ static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
}
else {
/* get armature from modifier */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval,
- eGpencilModifierType_Armature);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob_eval,
+ eGpencilModifierType_Armature);
if (md == NULL) {
BKE_report(op->reports, RPT_ERROR, "The grease pencil object need an Armature modifier");
return OPERATOR_CANCELLED;
@@ -630,7 +642,7 @@ static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C,
RNA_enum_item_add(&item, &totitem, &item_tmp);
i++;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->type == OB_ARMATURE) {
item_tmp.identifier = item_tmp.name = ob->id.name + 2;
diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c
index 6e2c6936b1a..5441d4e24a6 100644
--- a/source/blender/editors/gpencil/gpencil_convert.c
+++ b/source/blender/editors/gpencil/gpencil_convert.c
@@ -152,7 +152,6 @@ static const EnumPropertyItem *rna_GPConvert_mode_items(bContext *UNUSED(C),
* - assumes that the active space is the 3D-View
*/
static void gp_strokepoint_convertcoords(bContext *C,
- bGPdata *UNUSED(gpd),
bGPDlayer *gpl,
bGPDstroke *gps,
bGPDspoint *source_pt,
@@ -163,7 +162,7 @@ static void gp_strokepoint_convertcoords(bContext *C,
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
/* TODO(sergey): This function might be called from a loop, but no tagging is happening in it,
- * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the
+ * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the
* parameters are to wrapped into a context style struct and queried from Context once.*/
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obact = CTX_data_active_object(C);
@@ -633,7 +632,6 @@ static void gp_stroke_to_path_add_point(tGpTimingData *gtd,
}
static void gp_stroke_to_path(bContext *C,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
Curve *cu,
@@ -708,7 +706,7 @@ static void gp_stroke_to_path(bContext *C,
bp = &nu->bp[old_nbp - 1];
/* First point */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (prev_bp) {
interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
if (do_gtd) {
@@ -737,7 +735,7 @@ static void gp_stroke_to_path(bContext *C,
/* Second point */
/* Note dt2 is always negative, which marks the gap. */
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -759,9 +757,9 @@ static void gp_stroke_to_path(bContext *C,
float p[3], next_p[3];
float dt = 0.0f;
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
if (gps->totpoints > 1) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, gps->points + 1, next_p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
if (do_gtd) {
dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
@@ -794,7 +792,7 @@ static void gp_stroke_to_path(bContext *C,
float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
/* get coordinates to add at */
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, p, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
gp_stroke_to_path_add_point(gtd,
bp,
@@ -882,7 +880,6 @@ static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd,
}
static void gp_stroke_to_bezier(bContext *C,
- bGPdata *gpd,
bGPDlayer *gpl,
bGPDstroke *gps,
Curve *cu,
@@ -934,13 +931,12 @@ static void gp_stroke_to_bezier(bContext *C,
/* get initial coordinates */
pt = gps->points;
if (tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
if (tot > 1) {
- gp_strokepoint_convertcoords(
- C, gpd, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
}
if (stitch && tot > 2) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
}
@@ -1106,7 +1102,7 @@ static void gp_stroke_to_bezier(bContext *C,
copy_v3_v3(p3d_cur, p3d_next);
if (i + 2 < tot) {
- gp_strokepoint_convertcoords(C, gpd, gpl, gps, pt + 2, p3d_next, subrect);
+ gp_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
}
prev_bezt = bezt;
@@ -1334,7 +1330,6 @@ static void gp_layer_to_curve(bContext *C,
switch (mode) {
case GP_STROKECONVERT_PATH:
gp_stroke_to_path(C,
- gpd,
gpl,
gps,
cu,
@@ -1350,7 +1345,6 @@ static void gp_layer_to_curve(bContext *C,
case GP_STROKECONVERT_CURVE:
case GP_STROKECONVERT_POLY: /* convert after */
gp_stroke_to_bezier(C,
- gpd,
gpl,
gps,
cu,
@@ -1471,12 +1465,12 @@ static bool gp_convert_poll(bContext *C)
bGPdata *gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = NULL;
bGPDframe *gpf = NULL;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
* and if we are not in edit mode!
*/
- return ((sa && sa->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
+ 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->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
}
@@ -1828,7 +1822,7 @@ void GPENCIL_OT_image_to_grease_pencil(wmOperatorType *ot)
0.0001f,
10.0f,
"Point Size",
- "Size used for graese pencil points",
+ "Size used for grease pencil points",
0.001f,
1.0f);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 898facb86e8..8c80334bf8a 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -50,11 +50,12 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_deform.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_lib_id.h"
@@ -240,10 +241,8 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op)
if ((ob != NULL) && (ob->type == OB_GPENCIL)) {
gpd = (bGPdata *)ob->data;
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
- ScrArea *sa = CTX_wm_area(C);
-
- /* In dopesheet add a new frame. */
- if ((gpl != NULL) && (sa->spacetype == SPACE_ACTION)) {
+ /* 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);
}
}
@@ -331,6 +330,7 @@ static int gp_layer_remove_exec(bContext *C, wmOperator *op)
/* 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);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -478,6 +478,7 @@ static int gp_layer_copy_exec(bContext *C, wmOperator *UNUSED(op))
/* 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);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -519,7 +520,7 @@ static bool gp_layer_duplicate_object_poll(bContext *C)
}
/* check there are more grease pencil objects */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->object != ob) && (base->object->type == OB_GPENCIL)) {
return true;
}
@@ -568,7 +569,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
gpl_dst->opacity = gpl_src->opacity;
/* Create all frames. */
- for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
@@ -578,7 +579,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
/* Copy strokes. */
- for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true);
@@ -1181,12 +1182,12 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
/* Collect frames of gpl_current in hash table to avoid O(n^2) lookups */
GHash *gh_frames_cur = BLI_ghash_int_new_ex(__func__, 64);
- for (bGPDframe *gpf = gpl_current->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_current->frames) {
BLI_ghash_insert(gh_frames_cur, POINTER_FROM_INT(gpf->framenum), gpf);
}
/* read all frames from next layer and add any missing in current layer */
- for (bGPDframe *gpf = gpl_next->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_next->frames) {
/* try to find frame in current layer */
bGPDframe *frame = BLI_ghash_lookup(gh_frames_cur, POINTER_FROM_INT(gpf->framenum));
if (!frame) {
@@ -1228,6 +1229,7 @@ static int gp_merge_layer_exec(bContext *C, wmOperator *op)
/* 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);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1291,6 +1293,7 @@ static int gp_layer_change_exec(bContext *C, wmOperator *op)
/* updates */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1336,6 +1339,7 @@ static int gp_layer_active_exec(bContext *C, wmOperator *op)
/* updates */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
return OPERATOR_FINISHED;
}
@@ -1433,7 +1437,7 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
switch (direction) {
/* Bring to Front */
case GP_STROKE_MOVE_TOP:
- for (LinkData *link = selected.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &selected) {
gps = link->data;
BLI_remlink(&gpf->strokes, gps);
BLI_addtail(&gpf->strokes, gps);
@@ -1448,7 +1452,7 @@ static int gp_stroke_arrange_exec(bContext *C, wmOperator *op)
break;
/* Send Backward */
case GP_STROKE_MOVE_DOWN:
- for (LinkData *link = selected.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &selected) {
gps = link->data;
BLI_listbase_link_move(&gpf->strokes, gps, -1);
}
@@ -1903,19 +1907,19 @@ static int gp_brush_reset_all_exec(bContext *C, wmOperator *UNUSED(op))
switch (mode) {
case CTX_MODE_PAINT_GPENCIL: {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
break;
}
case CTX_MODE_SCULPT_GPENCIL: {
- BKE_brush_gpencil_sculpt_presets(bmain, ts);
+ BKE_brush_gpencil_sculpt_presets(bmain, ts, true);
break;
}
case CTX_MODE_WEIGHT_GPENCIL: {
- BKE_brush_gpencil_weight_presets(bmain, ts);
+ BKE_brush_gpencil_weight_presets(bmain, ts, true);
break;
}
case CTX_MODE_VERTEX_GPENCIL: {
- BKE_brush_gpencil_vertex_presets(bmain, ts);
+ BKE_brush_gpencil_vertex_presets(bmain, ts, true);
break;
}
default: {
@@ -2523,7 +2527,7 @@ static void joined_gpencil_fix_animdata_cb(ID *id, FCurve *fcu, void *user_data)
/* Fix driver targets */
if (fcu->driver) {
/* Fix driver references to invalid ID's */
- for (DriverVar *dvar = fcu->driver->variables.first; dvar; dvar = dvar->next) {
+ LISTBASE_FOREACH (DriverVar *, dvar, &fcu->driver->variables) {
/* Only change the used targets, since the others will need fixing manually anyway. */
DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
/* Change the ID's used. */
@@ -2614,8 +2618,8 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = ob_iter->data;
/* Apply all GP modifiers before */
- for (GpencilModifierData *md = ob_iter->greasepencil_modifiers.first; md; md = md->next) {
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ LISTBASE_FOREACH (GpencilModifierData *, md, &ob_iter->greasepencil_modifiers) {
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->bakeModifier) {
mti->bakeModifier(bmain, depsgraph, md, ob_iter);
}
@@ -2623,7 +2627,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
/* copy vertex groups to the base one's */
int old_idx = 0;
- for (bDeformGroup *dg = ob_iter->defbase.first; dg; dg = dg->next) {
+ LISTBASE_FOREACH (bDeformGroup *, dg, &ob_iter->defbase) {
bDeformGroup *vgroup = MEM_dupallocN(dg);
int idx = BLI_listbase_count(&ob_active->defbase);
BKE_object_defgroup_unique_name(vgroup, ob_active);
@@ -2675,7 +2679,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
mul_m3_v3(imat, offset_global);
mul_v3_m3v3(offset_local, imat, offset_global);
- for (bGPDlayer *gpl_src = gpd_src->layers.first; gpl_src; gpl_src = gpl_src->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
bGPDlayer *gpl_new = BKE_gpencil_layer_duplicate(gpl_src);
float diff_mat[4][4];
float inverse_diff_mat[4][4];
@@ -2685,7 +2689,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
invert_m4_m4(inverse_diff_mat, diff_mat);
Material *ma_src = NULL;
- for (bGPDframe *gpf = gpl_new->frames.first; gpf; gpf = gpf->next) {
+ LISTBASE_FOREACH (bGPDframe *, gpf, &gpl_new->frames) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* Reassign material. Look old material and try to find in destination. */
@@ -3189,7 +3193,7 @@ void GPENCIL_OT_material_unlock_all(wmOperatorType *ot)
/* ***************** Select all strokes using color ************************ */
-static int gpencil_select_material_exec(bContext *C, wmOperator *op)
+static int gpencil_material_select_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
@@ -3259,15 +3263,15 @@ static int gpencil_select_material_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void GPENCIL_OT_select_material(wmOperatorType *ot)
+void GPENCIL_OT_material_select(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Select Material";
- ot->idname = "GPENCIL_OT_select_material";
+ ot->idname = "GPENCIL_OT_material_select";
ot->description = "Select/Deselect all Grease Pencil strokes using current material";
/* callbacks */
- ot->exec = gpencil_select_material_exec;
+ ot->exec = gpencil_material_select_exec;
ot->poll = gpencil_active_material_poll;
/* flags */
@@ -3278,6 +3282,48 @@ void GPENCIL_OT_select_material(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/* ***************** Set active material ************************* */
+static int gpencil_material_set_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ int slot = RNA_enum_get(op->ptr, "slot");
+
+ /* Try to get material */
+ if ((slot < 1) || (slot > ob->totcol)) {
+ BKE_reportf(
+ op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot);
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set active material. */
+ ob->actcol = slot;
+
+ /* updates */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_material_set(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Material";
+ ot->idname = "GPENCIL_OT_material_set";
+ ot->description = "Set active material";
+
+ /* callbacks */
+ ot->exec = gpencil_material_set_exec;
+ ot->poll = gpencil_active_material_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* Material to use (dynamic enum) */
+ ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", "");
+ RNA_def_enum_funcs(ot->prop, ED_gpencil_material_enum_itemf);
+}
+
/* ***************** Set selected stroke material the active material ************************ */
static int gpencil_set_active_material_exec(bContext *C, wmOperator *op)
@@ -3340,7 +3386,7 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C,
}
/* if no lattice modifier, add a new one */
- GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Lattice);
+ GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Lattice);
if (md == NULL) {
md = ED_object_gpencil_modifier_add(
reports, bmain, scene, ob, "Lattice", eGpencilModifierType_Lattice);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 1b42334499e..8771fcb0c8d 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -77,6 +77,7 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_space_api.h"
@@ -89,8 +90,9 @@
#include "gpencil_intern.h"
-/* ************************************************ */
-/* Stroke Edit Mode Management */
+/* -------------------------------------------------------------------- */
+/** \name Stroke Edit Mode Management
+ * \{ */
/* poll callback for all stroke editing operators */
static bool gp_stroke_edit_poll(bContext *C)
@@ -137,6 +139,12 @@ static bool gpencil_editmode_toggle_poll(bContext *C)
return ED_gpencil_data_get_active(C) != NULL;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Edit Mode Operator
+ * \{ */
+
static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op)
{
const int back = RNA_boolean_get(op->ptr, "back");
@@ -222,6 +230,12 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Select Mode Operator
+ * \{ */
+
/* set select mode */
static bool gpencil_selectmode_toggle_poll(bContext *C)
{
@@ -297,7 +311,11 @@ void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Stroke Paint Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Stroke Paint Mode Operator
+ * \{ */
static bool gpencil_paintmode_toggle_poll(bContext *C)
{
@@ -351,12 +369,20 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_PAINT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes and Paint settings.
+ * Need Draw and Vertex (used for Tint). */
BKE_paint_ensure(ts, (Paint **)&ts->gp_paint);
+ BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+
+ BKE_brush_gpencil_paint_presets(bmain, ts, false);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
+
Paint *paint = &ts->gp_paint->paint;
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
@@ -401,7 +427,11 @@ void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Stroke Sculpt Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Stroke Sculpt Mode Operator
+ * \{ */
static bool gpencil_sculptmode_toggle_poll(bContext *C)
{
@@ -455,8 +485,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_SCULPT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_sculptpaint);
+
+ const bool reset_mode = (ts->gp_sculptpaint->paint.brush == NULL);
+ BKE_brush_gpencil_sculpt_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_sculptpaint->paint);
}
@@ -478,6 +512,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Weight Paint Mode Operator
+ * \{ */
+
void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -554,8 +594,12 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_WEIGHT_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_weightpaint);
+
+ const bool reset_mode = (ts->gp_weightpaint->paint.brush == NULL);
+ BKE_brush_gpencil_weight_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_weightpaint->paint);
}
@@ -599,7 +643,11 @@ void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* Vertex Paint Mode Management */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Vertex Paint Mode Operator
+ * \{ */
static bool gpencil_vertexmode_toggle_poll(bContext *C)
{
@@ -652,9 +700,16 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op)
}
if (mode == OB_MODE_VERTEX_GPENCIL) {
- /* be sure we have brushes */
+ /* Be sure we have brushes. */
BKE_paint_ensure(ts, (Paint **)&ts->gp_vertexpaint);
+
+ const bool reset_mode = (ts->gp_vertexpaint->paint.brush == NULL);
+ BKE_brush_gpencil_vertex_presets(bmain, ts, reset_mode);
+
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_vertexpaint->paint);
+
+ /* Ensure Palette by default. */
+ BKE_gpencil_palette_ensure(bmain, CTX_data_scene(C));
}
/* setup other modes */
@@ -697,10 +752,11 @@ void GPENCIL_OT_vertexmode_toggle(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ************************************************ */
-/* Stroke Editing Operators */
+/** \} */
-/* ************ Stroke Hide selection Toggle ************** */
+/* -------------------------------------------------------------------- */
+/** \name Stroke Hide Selection Toggle Operator
+ * \{ */
static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -739,7 +795,11 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
-/* ************** Duplicate Selected Strokes **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Selected Strokes Operator
+ * \{ */
/* Make copies of selected point segments in a selected stroke */
static void gp_duplicate_points(const bGPDstroke *gps,
@@ -916,7 +976,11 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************** Extrude Selected Strokes **************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Extrude Selected Strokes Operator
+ * \{ */
/* helper to copy a point to temp area */
static void copy_move_point(bGPDstroke *gps,
@@ -1137,14 +1201,18 @@ void GPENCIL_OT_extrude(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Copy/Paste Strokes ************************* */
-/* Grease Pencil stroke data copy/paste buffer:
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy/Paste Strokes Utilities
+ *
+ * Grease Pencil stroke data copy/paste buffer:
* - The copy operation collects all segments of selected strokes,
* dumping "ready to be copied" copies of the strokes into the buffer.
* - The paste operation makes a copy of those elements, and adds them
* to the active layer. This effectively flattens down the strokes
* from several different layers into a single layer.
- */
+ * \{ */
/* list of bGPDstroke instances */
/* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */
@@ -1256,8 +1324,11 @@ GHash *gp_copybuf_validate_colormap(bContext *C)
return new_colors;
}
-/* --------------------- */
-/* Copy selected strokes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Copy Selected Strokes Operator
+ * \{ */
static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
{
@@ -1333,7 +1404,7 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
if (gp_strokes_copypastebuf.first) {
gp_strokes_copypastebuf_colors = BLI_ghash_int_new("GPencil CopyBuf Colors");
GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
- for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gp_strokes_copypastebuf) {
if (ED_gpencil_stroke_can_use(C, gps)) {
Material *ma = BKE_object_material_get(ob, gps->mat_nr + 1);
/* Avoid default material. */
@@ -1374,13 +1445,16 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
// ot->flag = OPTYPE_REGISTER;
}
-/* --------------------- */
-/* Paste selected strokes */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paste Selected Strokes Operator
+ * \{ */
static bool gp_strokes_paste_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (!((sa != NULL) && (sa->spacetype == SPACE_VIEW3D))) {
+ ScrArea *area = CTX_wm_area(C);
+ if (!((area != NULL) && (area->spacetype == SPACE_VIEW3D))) {
return false;
}
/* 1) Must have GP datablock to paste to
@@ -1546,7 +1620,11 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Move To Layer ****************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Move To Layer Operator
+ * \{ */
static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
{
@@ -1569,7 +1647,13 @@ static int gp_move_to_layer_exec(bContext *C, wmOperator *op)
}
/* Try to get layer */
- target_layer = BLI_findlink(&gpd->layers, layer_num);
+ if (layer_num > -1) {
+ target_layer = BLI_findlink(&gpd->layers, layer_num);
+ }
+ else {
+ /* Create a new layer. */
+ target_layer = BKE_gpencil_layer_addnew(gpd, "GP_Layer", true);
+ }
if (target_layer == NULL) {
/* back autolock status */
@@ -1655,11 +1739,16 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* GPencil layer to use. */
- ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
+ ot->prop = RNA_def_int(
+ ot->srna, "layer", 0, -1, INT_MAX, "Grease Pencil Layer", "", -1, INT_MAX);
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
-/* ********************* Add Blank Frame *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Blank Frame Operator
+ * \{ */
static int gp_blank_frame_add_exec(bContext *C, wmOperator *op)
{
@@ -1733,7 +1822,11 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Delete Active Frame ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Active Frame Operator
+ * \{ */
static bool gp_actframe_delete_poll(bContext *C)
{
@@ -1814,7 +1907,12 @@ void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot)
ot->exec = gp_actframe_delete_exec;
ot->poll = gp_annotation_actframe_delete_poll;
}
-/* **************** Delete All Active Frames ****************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete All Active Frames
+ * \{ */
static bool gp_actframe_delete_all_poll(bContext *C)
{
@@ -1875,7 +1973,11 @@ void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot)
ot->poll = gp_actframe_delete_all_poll;
}
-/* ******************* Delete Operator ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete/Dissolve Utilities
+ * \{ */
typedef enum eGP_DeleteMode {
/* delete selected stroke points */
@@ -1895,8 +1997,6 @@ typedef enum eGP_DissolveMode {
GP_DISSOLVE_UNSELECT = 2,
} eGP_DissolveMode;
-/* ----------------------------------- */
-
/* Delete selected strokes */
static int gp_delete_selected_strokes(bContext *C)
{
@@ -2490,7 +2590,11 @@ int gp_delete_selected_point_wrap(bContext *C)
return gp_delete_selected_points(C);
}
-/* ----------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Operator
+ * \{ */
static int gp_delete_exec(bContext *C, wmOperator *op)
{
@@ -2549,6 +2653,12 @@ void GPENCIL_OT_delete(wmOperatorType *ot)
"Method used for deleting Grease Pencil data");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Dissolve Operator
+ * \{ */
+
static int gp_dissolve_exec(bContext *C, wmOperator *op)
{
eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type");
@@ -2591,7 +2701,11 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
"Method used for dissolving Stroke points");
}
-/* ****************** Snapping - Strokes <-> Cursor ************************ */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Selection to Grid Operator
+ * \{ */
/* Poll callback for snap operators */
/* NOTE: For now, we only allow these in the 3D view, as other editors do not
@@ -2599,15 +2713,13 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot)
*/
static bool gp_snap_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
return (ob != NULL) && (ob->type == OB_GPENCIL) &&
- ((sa != NULL) && (sa->spacetype == SPACE_VIEW3D));
+ ((area != NULL) && (area->spacetype == SPACE_VIEW3D));
}
-/* --------------------------------- */
-
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -2682,7 +2794,11 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Selection to Cursor Operator
+ * \{ */
static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
@@ -2774,7 +2890,11 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
"Offset the entire stroke instead of selected points only");
}
-/* ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Snapping Cursor to Selection Operator
+ * \{ */
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
@@ -2865,7 +2985,11 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Apply layer thickness change to strokes ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Apply Layer Thickness Change to Strokes Operator
+ * \{ */
static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2912,7 +3036,11 @@ void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
}
-/* ******************* Close Strokes ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Toggle Cyclic Operator
+ * \{ */
enum {
GP_STROKE_CYCLIC_CLOSE = 1,
@@ -3032,7 +3160,11 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Flat Stroke Caps ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Toggle Flat Caps Operator
+ * \{ */
enum {
GP_STROKE_CAPS_TOGGLE_BOTH = 0,
@@ -3128,7 +3260,11 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", toggle_type, GP_STROKE_CAPS_TOGGLE_BOTH, "Type", "");
}
-/* ******************* Stroke join ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Join Operator
+ * \{ */
/* Helper: flip stroke */
static void gpencil_flip_stroke(bGPDstroke *gps)
@@ -3178,8 +3314,8 @@ static void gpencil_flip_stroke(bGPDstroke *gps)
/* Helper: copy point between strokes */
static void gpencil_stroke_copy_point(bGPDstroke *gps,
+ MDeformVert *dvert,
bGPDspoint *point,
- int idx,
const float delta[3],
float pressure,
float strength,
@@ -3191,6 +3327,13 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
if (gps->dvert != NULL) {
gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1));
}
+ else {
+ /* If destination has weight add weight to origin. */
+ if (dvert != NULL) {
+ gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__);
+ }
+ }
+
gps->totpoints++;
newpoint = &gps->points[gps->totpoints - 1];
@@ -3204,11 +3347,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps,
copy_v4_v4(newpoint->vert_color, point->vert_color);
if (gps->dvert != NULL) {
- MDeformVert *dvert = &gps->dvert[idx];
MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1];
- newdvert->totweight = dvert->totweight;
- newdvert->dw = MEM_dupallocN(dvert->dw);
+ if (dvert != NULL) {
+ newdvert->totweight = dvert->totweight;
+ newdvert->dw = MEM_dupallocN(dvert->dw);
+ }
+ else {
+ newdvert->totweight = 0;
+ newdvert->dw = NULL;
+ }
}
}
@@ -3233,9 +3381,9 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
}
/* define start and end points of each stroke */
- float sa[3], sb[3], ea[3], eb[3];
+ float area[3], sb[3], ea[3], eb[3];
pt = &gps_a->points[0];
- copy_v3_v3(sa, &pt->x);
+ copy_v3_v3(area, &pt->x);
pt = &gps_a->points[gps_a->totpoints - 1];
copy_v3_v3(ea, &pt->x);
@@ -3259,16 +3407,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a,
/* 1st: add one tail point to start invisible area */
point = gps_a->points[gps_a->totpoints - 1];
deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f);
+
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f);
/* 2nd: add one head point to finish invisible area */
point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime);
+ gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime);
}
/* 3rd: add all points */
for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime);
+ MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL;
+ gpencil_stroke_copy_point(gps_a, dvert, pt, delta, pt->pressure, pt->strength, deltatime);
}
}
@@ -3414,7 +3564,11 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot)
"Leave gaps between joined strokes instead of linking them");
}
-/* ******************* Stroke flip ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Flip Operator
+ * \{ */
static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3473,7 +3627,11 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Reproject Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Re-project Operator
+ * \{ */
typedef enum eGP_ReprojectModes {
/* Axis */
@@ -3511,7 +3669,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
int cfra_prv = INT_MIN;
/* init snap context for geometry projection */
- sctx = ED_transform_snap_object_context_create_view3d(bmain, scene, 0, region, CTX_wm_view3d(C));
+ sctx = ED_transform_snap_object_context_create_view3d(scene, 0, region, CTX_wm_view3d(C));
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
@@ -3546,7 +3704,7 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op)
GP_REPROJECT_TOP,
GP_REPROJECT_CURSOR)) {
if (mode != GP_REPROJECT_CURSOR) {
- ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, origin);
}
else {
copy_v3_v3(origin, scene->cursor.location);
@@ -3711,7 +3869,6 @@ static int gp_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op))
void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Recalculate internal geometry";
ot->idname = "GPENCIL_OT_recalc_geometry";
@@ -3725,7 +3882,12 @@ void GPENCIL_OT_recalc_geometry(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* Stroke subdivide ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Subdivide Operator
+ * \{ */
+
/* helper to smooth */
static void gp_smooth_stroke(bContext *C, wmOperator *op)
{
@@ -4106,7 +4268,12 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ******************* Stroke trim ************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Trim Operator
+ * \{ */
+
static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op))
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4171,7 +4338,12 @@ void GPENCIL_OT_stroke_trim(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ***************** Separate Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Separate Operator
+ * \{ */
+
typedef enum eGP_SeparateModes {
/* Points */
GP_SEPARATE_POINT = 0,
@@ -4249,7 +4421,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- /* separate selected strokes */
+ /* Separate selected strokes. */
if (gps->flag & GP_STROKE_SELECT) {
/* add layer if not created before */
if (gpl_dst == NULL) {
@@ -4357,6 +4529,8 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -4387,7 +4561,12 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", "");
}
-/* ***************** Split Strokes ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Split Operator
+ * \{ */
+
static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
@@ -4422,7 +4601,7 @@ static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
- /* split selected strokes */
+ /* Split selected strokes. */
if (gps->flag & GP_STROKE_SELECT) {
/* make copy of source stroke */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps, true);
@@ -4484,6 +4663,12 @@ void GPENCIL_OT_stroke_split(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Smooth Operator
+ * \{ */
+
static int gp_stroke_smooth_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
@@ -4534,11 +4719,17 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", "");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Stroke Cutter Operator
+ * \{ */
+
/* smart stroke cutter for trimming stroke ends */
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -4554,7 +4745,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
typedef bool (*GPencilTestFn)(bGPDstroke *gps,
@@ -4617,7 +4808,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
void *user_data)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
@@ -4628,7 +4819,7 @@ static int gpencil_cutter_lasso_select(bContext *C,
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -4724,27 +4915,27 @@ static bool gpencil_cutter_poll(bContext *C)
static int gpencil_cutter_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return OPERATOR_FINISHED;
}
@@ -4790,7 +4981,12 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
return ok;
}
-/* ** merge by distance *** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Merge By Distance Operator
+ * \{ */
+
static bool gp_merge_by_distance_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -4859,3 +5055,5 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points");
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 f61572fffca..d23a914fc49 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -45,6 +45,7 @@
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
#include "BKE_image.h"
+#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_paint.h"
@@ -92,7 +93,7 @@ typedef struct tGPDfill {
/** current active gp object */
struct Object *ob;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct RegionView3D *rv3d;
/** view3 where painting originated */
@@ -294,18 +295,15 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4])
tgpw.onion = true;
tgpw.custonion = true;
- bool textured_stroke = (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE);
-
/* normal strokes */
- if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) &&
- !textured_stroke) {
+ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) ||
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) {
ED_gp_draw_fill(&tgpw);
}
/* 3D Lines with basic shapes and invisible lines */
if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ||
- (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) || textured_stroke) {
+ (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) {
gp_draw_basic_stroke(tgpf,
gps,
tgpw.diff_mat,
@@ -620,40 +618,38 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf)
get_pixel(ibuf, v, rgba);
- if (true) { /* Was: 'rgba' */
- /* check if no border(red) or already filled color(green) */
- if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
- /* fill current pixel with green */
- set_pixel(ibuf, v, fill_col);
-
- /* add contact pixels */
- /* pixel left */
- if (v - 1 >= 0) {
- index = v - 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
+ /* check if no border(red) or already filled color(green) */
+ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) {
+ /* fill current pixel with green */
+ set_pixel(ibuf, v, fill_col);
+
+ /* add contact pixels */
+ /* pixel left */
+ if (v - 1 >= 0) {
+ index = v - 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel right */
- if (v + 1 <= maxpixel) {
- index = v + 1;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel right */
+ if (v + 1 <= maxpixel) {
+ index = v + 1;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel top */
- if (v + ibuf->x <= maxpixel) {
- index = v + ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel top */
+ if (v + ibuf->x <= maxpixel) {
+ index = v + ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
}
- /* pixel bottom */
- if (v - ibuf->x >= 0) {
- index = v - ibuf->x;
- if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
- BLI_stack_push(stack, &index);
- }
+ }
+ /* pixel bottom */
+ if (v - ibuf->x >= 0) {
+ index = v - ibuf->x;
+ if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) {
+ BLI_stack_push(stack, &index);
}
}
}
@@ -670,7 +666,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf)
}
/* Check if there are some pixel not filled with green. If no points, means nothing to fill. */
-static bool gpencil_check_borders(tGPDfill *tgpf)
+static bool UNUSED_FUNCTION(gpencil_check_borders)(tGPDfill *tgpf)
{
ImBuf *ibuf;
void *lock;
@@ -725,31 +721,32 @@ static bool gpencil_check_borders(tGPDfill *tgpf)
return found;
}
-/* clean external border of image to avoid infinite loops */
-static void gpencil_clean_borders(tGPDfill *tgpf)
+/* Set a border to create image limits. */
+static void gpencil_set_borders(tGPDfill *tgpf, const bool transparent)
{
ImBuf *ibuf;
void *lock;
- const float fill_col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float fill_col[2][4] = {{1.0f, 0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f, 0.0f}};
ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock);
int idx;
int pixel = 0;
+ const int coloridx = transparent ? 0 : 1;
/* horizontal lines */
for (idx = 0; idx < ibuf->x; idx++) {
/* bottom line */
- set_pixel(ibuf, idx, fill_col);
+ set_pixel(ibuf, idx, fill_col[coloridx]);
/* top line */
pixel = idx + (ibuf->x * (ibuf->y - 1));
- set_pixel(ibuf, pixel, fill_col);
+ set_pixel(ibuf, pixel, fill_col[coloridx]);
}
/* vertical lines */
for (idx = 0; idx < ibuf->y; idx++) {
/* left line */
- set_pixel(ibuf, ibuf->x * idx, fill_col);
+ set_pixel(ibuf, ibuf->x * idx, fill_col[coloridx]);
/* right line */
pixel = ibuf->x * idx + (ibuf->x - 1);
- set_pixel(ibuf, pixel, fill_col);
+ set_pixel(ibuf, pixel, fill_col[coloridx]);
}
/* release ibuf */
@@ -1143,7 +1140,6 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gp_stroke_convertcoords_tpoint(tgpf->scene,
tgpf->region,
tgpf->ob,
- tgpf->gpl,
point2D,
tgpf->depth_arr ? tgpf->depth_arr + i : NULL,
&pt->x);
@@ -1153,7 +1149,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
pt->time = 0.0f;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, NULL);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr);
@@ -1186,8 +1182,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) &&
((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) {
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpf->scene, tgpf->ob, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1);
}
@@ -1250,8 +1245,8 @@ static bool gpencil_fill_poll(bContext *C)
Object *obact = CTX_data_active_object(C);
if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_VIEW3D) {
if ((obact == NULL) || (obact->type != OB_GPENCIL) ||
(obact->mode != OB_MODE_PAINT_GPENCIL)) {
return false;
@@ -1285,10 +1280,10 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op))
tgpf->bmain = CTX_data_main(C);
tgpf->scene = CTX_data_scene(C);
tgpf->ob = CTX_data_active_object(C);
- tgpf->sa = CTX_wm_area(C);
+ tgpf->area = CTX_wm_area(C);
tgpf->region = CTX_wm_region(C);
tgpf->rv3d = tgpf->region->regiondata;
- tgpf->v3d = tgpf->sa->spacedata.first;
+ tgpf->v3d = tgpf->area->spacedata.first;
tgpf->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpf->win = CTX_wm_window(C);
@@ -1362,19 +1357,9 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op)
ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d);
}
- /* delete temp image */
+ /* Delete temp image. */
if (tgpf->ima) {
- for (Image *ima = bmain->images.first; ima; ima = ima->id.next) {
- if (ima == tgpf->ima) {
- /* XXX This is super, super suspicious!
- * There should NEVER be any need to handle datablocks in Main in such custom code.
- * Please change to using BKE_id_free() or similar! */
- BLI_remlink(&bmain->images, ima);
- BKE_image_free(tgpf->ima);
- MEM_SAFE_FREE(tgpf->ima);
- break;
- }
- }
+ BKE_id_free(bmain, tgpf->ima);
}
/* finally, free memory used by temp data */
@@ -1514,30 +1499,26 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* render screen to temp image */
if (gp_render_offscreen(tgpf)) {
+ /* Set red borders to create a external limit. */
+ gpencil_set_borders(tgpf, true);
+
/* apply boundary fill */
gpencil_boundaryfill_area(tgpf);
- /* Check if detected some border to fill. */
- if (gpencil_check_borders(tgpf)) {
-
- /* clean borders to avoid infinite loops */
- gpencil_clean_borders(tgpf);
+ /* Clean borders to avoid infinite loops. */
+ gpencil_set_borders(tgpf, false);
- /* analyze outline */
- gpencil_get_outline_points(tgpf);
+ /* analyze outline */
+ gpencil_get_outline_points(tgpf);
- /* create array of points from stack */
- gpencil_points_from_stack(tgpf);
+ /* create array of points from stack */
+ gpencil_points_from_stack(tgpf);
- /* create z-depth array for reproject */
- gpencil_get_depth_array(tgpf);
+ /* create z-depth array for reproject */
+ gpencil_get_depth_array(tgpf);
- /* create stroke and reproject */
- gpencil_stroke_from_buffer(tgpf);
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Fill canceled. No edges detected");
- }
+ /* create stroke and reproject */
+ gpencil_stroke_from_buffer(tgpf);
}
/* free temp stack data */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 79f672274a7..473913c5459 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -68,6 +68,17 @@ struct PropertyRNA;
/* Internal Operator-State Data ------------------------ */
+/** Random settings by stroke */
+typedef struct GpRandomSettings {
+ /** Pressure used for evaluated curves. */
+ float pen_press;
+
+ float hsv[3];
+ float pressure;
+ float strength;
+ float uv;
+} GpRandomSettings;
+
/* Temporary draw data (no draw manager mode) */
typedef struct tGPDdraw {
struct RegionView3D *rv3d; /* region to draw */
@@ -116,7 +127,7 @@ typedef struct tGPDinterpolate {
/** current scene from context */
struct Scene *scene;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct ARegion *region;
/** current GP datablock */
@@ -156,7 +167,7 @@ typedef struct tGPDprimitive {
/** current evaluated gp object */
struct Object *ob_eval;
/** area where painting originated */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** region where painting originated */
struct RegionView3D *rv3d;
/** view3d where painting originated */
@@ -230,6 +241,10 @@ typedef struct tGPDprimitive {
/** size in pixels for uv calculation */
float totpixlen;
+
+ /** Random settings by stroke */
+ GpRandomSettings random_settings;
+
} tGPDprimitive;
/* Modal Operator Drawing Callbacks ------------------------ */
@@ -247,7 +262,7 @@ typedef struct GP_SpaceConversion {
struct bGPdata *gpd;
struct bGPDlayer *gpl;
- struct ScrArea *sa;
+ struct ScrArea *area;
struct ARegion *region;
struct View2D *v2d;
@@ -257,8 +272,7 @@ typedef struct GP_SpaceConversion {
float mat[4][4]; /* transform matrix on the strokes (introduced in [b770964]) */
} GP_SpaceConversion;
-bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1);
+bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1);
void gp_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc);
@@ -304,7 +318,6 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
void gp_stroke_convertcoords_tpoint(struct Scene *scene,
struct ARegion *region,
struct Object *ob,
- bGPDlayer *gpl,
const struct tGPspoint *point2D,
float *depth,
float out[3]);
@@ -347,6 +360,10 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bCon
struct PointerRNA *ptr,
struct PropertyRNA *prop,
bool *r_free);
+const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C,
+ struct PointerRNA *ptr,
+ struct PropertyRNA *prop,
+ bool *r_free);
/* ***************************************************** */
/* Operator Defines */
@@ -552,7 +569,8 @@ void GPENCIL_OT_material_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_unlock_all(struct wmOperatorType *ot);
void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot);
-void GPENCIL_OT_select_material(struct wmOperatorType *ot);
+void GPENCIL_OT_material_select(struct wmOperatorType *ot);
+void GPENCIL_OT_material_set(struct wmOperatorType *ot);
void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
@@ -681,16 +699,13 @@ struct GP_EditableStrokes_Iter {
const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \
if (BKE_gpencil_layer_is_editable(gpl)) { \
- bGPDframe *init_gpf_ = gpl->actframe; \
- if (is_multiedit_) { \
- init_gpf_ = gpl->frames.first; \
- } \
+ 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_)) { \
BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* loop over strokes */ \
- for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \
/* skip strokes that are invalid for current view */ \
if (ED_gpencil_stroke_can_use(C, gps) == false) \
continue; \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index fef88007542..5cb49600d05 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -86,8 +86,8 @@ static bool gpencil_view3d_poll(bContext *C)
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
/* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return 0;
}
@@ -134,6 +134,19 @@ static void gp_interpolate_free_temp_strokes(bGPDframe *gpf)
}
}
}
+
+/* Helper: Untag all strokes. */
+static void gp_interpolate_untag_strokes(bGPDframe *gpf)
+{
+ BLI_assert(gpf != NULL);
+
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ if (gps->flag & GP_STROKE_TAG) {
+ gps->flag &= ~GP_STROKE_TAG;
+ }
+ }
+}
+
/* Helper: Update all strokes interpolated */
static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
{
@@ -265,6 +278,10 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
tgpil->prevFrame = gpl->actframe;
tgpil->nextFrame = gpl->actframe->next;
+ /* Untag interpolated strokes to be sure nothing is pending. */
+ gp_interpolate_untag_strokes(tgpil->prevFrame);
+ gp_interpolate_untag_strokes(tgpil->nextFrame);
+
BLI_addtail(&tgpi->ilayers, tgpil);
/* create a new temporary frame */
@@ -383,7 +400,7 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *
(int)((p->init_factor + p->shift) * 100.0f));
}
- ED_area_status_text(p->sa, status_str);
+ ED_area_status_text(p->area, status_str);
ED_workspace_status_text(
C, TIP_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
}
@@ -410,7 +427,7 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
/* don't assume that operator data exists at all */
if (tgpi) {
/* clear status message area */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
/* Clear any temp stroke. */
@@ -445,7 +462,7 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte
/* set current scene and window */
tgpi->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
tgpi->scene = CTX_data_scene(C);
- tgpi->sa = CTX_wm_area(C);
+ tgpi->area = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
tgpi->flag = ts->gp_interpolate.flag;
@@ -567,7 +584,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_PADENTER:
case EVT_RETKEY: {
/* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
@@ -602,7 +619,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent
case EVT_ESCKEY: /* cancel */
case RIGHTMOUSE: {
/* return to normal cursor and header status */
- ED_area_status_text(tgpi->sa, NULL);
+ ED_area_status_text(tgpi->area, NULL);
ED_workspace_status_text(C, NULL);
WM_cursor_modal_restore(win);
@@ -953,12 +970,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
bGPDstroke *gps_from, *gps_to;
int cframe, fFrame;
+ /* Need a set of frames to interpolate. */
+ if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
+ continue;
+ }
/* all layers or only active */
if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
continue;
}
/* only editable and visible layers are considered */
- if (!BKE_gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ if (!BKE_gpencil_layer_is_editable(gpl)) {
continue;
}
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index bd9daa83411..e71bf2098dd 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -117,7 +117,7 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, false);
}
Brush *brush = paint->brush;
@@ -132,18 +132,8 @@ static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpo
bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, add_frame_mode);
/* stroke */
- bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "gp_stroke");
- gps->totpoints = totpoints;
- gps->inittime = 0.0f;
- gps->thickness = brush->size;
- gps->hardeness = brush->gpencil_settings->hardeness;
- copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
+ bGPDstroke *gps = BKE_gpencil_stroke_new(ob->actcol - 1, totpoints, brush->size);
gps->flag |= GP_STROKE_SELECT;
- gps->flag |= GP_STROKE_3DSPACE;
- gps->mat_nr = ob->actcol - 1;
-
- /* allocate memory for points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * totpoints, "gp_stroke_points");
if (cyclic) {
gps->flag |= GP_STROKE_CYCLIC;
@@ -529,6 +519,8 @@ static int gp_stroke_merge_exec(bContext *C, wmOperator *op)
gpencil_dissolve_points(C);
}
+ BKE_gpencil_stroke_geometry_update(gps);
+
/* free memory */
MEM_SAFE_FREE(original_array);
MEM_SAFE_FREE(sorted_array);
@@ -630,7 +622,7 @@ static int gp_stroke_merge_material_exec(bContext *C, wmOperator *op)
/* notifiers */
if (changed) {
- BKE_reportf(op->reports, RPT_INFO, "Merged %d materiales of %d", removed, *totcol);
+ BKE_reportf(op->reports, RPT_INFO, "Merged %d materials of %d", removed, *totcol);
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 8b126912efc..94c86572fd3 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -178,10 +178,10 @@ static bool gp_stroke_sculptmode_poll(bContext *C)
{
bGPdata *gpd = CTX_data_gpencil_data(C);
Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* if not gpencil object and not view3d, need sculpt keys if edit mode */
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE));
}
else {
@@ -653,7 +653,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_material_reveal);
WM_operatortype_append(GPENCIL_OT_material_lock_all);
WM_operatortype_append(GPENCIL_OT_material_unlock_all);
- WM_operatortype_append(GPENCIL_OT_select_material);
+ WM_operatortype_append(GPENCIL_OT_material_select);
+ WM_operatortype_append(GPENCIL_OT_material_set);
/* Editing (Time) --------------- */
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index df094ff5bd0..2dd98bb8df1 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -117,9 +117,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain); /* added object */
/* convert grease pencil palettes (version >= 2.78) to materials and weights */
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
- palcolor = palcolor->next) {
+ LISTBASE_FOREACH (const bGPDpalette *, palette, &gpd->palettes) {
+ LISTBASE_FOREACH (bGPDpalettecolor *, palcolor, &palette->colors) {
/* create material slot */
Material *ma = BKE_gpencil_object_material_new(bmain, ob, palcolor->info, NULL);
@@ -134,7 +133,6 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
ARRAY_SET_ITEMS(gp_style->mix_rgba, 1.0f, 1.0f, 1.0f, 0.2f);
ARRAY_SET_ITEMS(gp_style->gradient_scale, 1.0f, 1.0f);
ARRAY_SET_ITEMS(gp_style->texture_scale, 1.0f, 1.0f);
- gp_style->texture_opacity = 1.0f;
gp_style->texture_pixsize = 100.0f;
gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
@@ -169,9 +167,8 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
}
if (is_annotation) {
- for (const bGPDpalette *palette = gpd->palettes.first; palette; palette = palette->next) {
- for (bGPDpalettecolor *palcolor = palette->colors.first; palcolor;
- palcolor = palcolor->next) {
+ LISTBASE_FOREACH (const bGPDpalette *, palette, &gpd->palettes) {
+ LISTBASE_FOREACH (bGPDpalettecolor *, palcolor, &palette->colors) {
/* fix layers */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* unlock/unhide layer */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 01b0fe80dfc..06079c34d12 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_math_geom.h"
#include "BLI_rand.h"
@@ -155,7 +156,7 @@ typedef struct tGPsdata {
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
- ScrArea *sa;
+ ScrArea *area;
/** region where painting originated. */
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
@@ -254,6 +255,10 @@ typedef struct tGPsdata {
tGPguide guide;
ReportList *reports;
+
+ /** Random settings by stroke */
+ GpRandomSettings random_settings;
+
} tGPsdata;
/* ------ */
@@ -296,9 +301,9 @@ static void gp_session_validatebuffer(tGPsdata *p);
static bool gpencil_draw_poll(bContext *C)
{
if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* 3D Viewport */
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return false;
}
@@ -353,7 +358,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
if (p->ownerPtr.type == &RNA_Object) {
ob = (Object *)p->ownerPtr.data;
}
- ED_gpencil_drawing_reference_get(p->scene, ob, p->gpl, *p->align_flag, vec);
+ ED_gpencil_drawing_reference_get(p->scene, ob, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
@@ -444,7 +449,10 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
}
int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
+ float rmval[2];
+ rmval[0] = mval[0] - 0.5f;
+ rmval[1] = mval[1] - 0.5f;
+ round_v2i_v2fl(mval_i, rmval);
if (gpencil_project_check(p) &&
(ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
@@ -486,6 +494,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
/* Apply jitter to stroke point. */
static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
{
+ const float axis[2] = {0.0f, 1.0f};
/* Jitter is applied perpendicular to the mouse movement vector (2D space). */
float mvec[2];
/* Mouse movement in ints -> floats. */
@@ -493,16 +502,15 @@ static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
tGPspoint *pt_prev = pt - 1;
sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
normalize_v2(mvec);
+ /* Rotate mvec by 90 degrees... */
+ float angle = angle_v2v2(mvec, axis);
+ /* Reduce noise in the direction of the stroke. */
+ mvec[0] *= cos(angle);
+ mvec[1] *= sin(angle);
+
+ /* Scale by displacement amount, and apply. */
+ madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
}
- else {
- mvec[0] = 0.0f;
- mvec[1] = 0.0f;
- }
- /* Rotate mvec by 90 degrees... */
- SWAP(float, mvec[0], mvec[1]);
- mvec[0] -= mvec[0];
- /* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude);
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
@@ -511,7 +519,6 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
float mvec[2];
float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
float fac;
- float mpressure;
/* default angle of brush in radians */
float angle = brush->gpencil_settings->draw_angle;
@@ -539,9 +546,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
- pt->pressure = mpressure;
-
+ pt->pressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
}
@@ -686,6 +691,78 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t
}
}
+static void gp_apply_randomness(tGPsdata *p,
+ BrushGpencilSettings *brush_settings,
+ tGPspoint *pt,
+ const bool press,
+ const bool strength,
+ const bool uv)
+{
+ bGPdata *gpd = p->gpd;
+ GpRandomSettings random_settings = p->random_settings;
+ float value = 0.0f;
+ /* Apply randomness to pressure. */
+ if ((brush_settings->draw_random_press > 0.0f) && (press)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ }
+ else {
+ value = 1.0 + random_settings.pressure * brush_settings->draw_random_press;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->pressure *= value;
+ CLAMP(pt->pressure, 0.1f, 1.0f);
+ }
+
+ /* Apply randomness to color strength. */
+ if ((brush_settings->draw_random_strength) && (strength)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * brush_settings->draw_random_strength;
+ }
+ else {
+ value = 1.0 + random_settings.strength * brush_settings->draw_random_strength;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->strength *= value;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* Apply randomness to uv texture rotation. */
+ if ((brush_settings->uv_random > 0.0f) && (uv)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ 1.0f;
+ value = rand * M_PI_2 * brush_settings->uv_random;
+ }
+ else {
+ value = random_settings.uv * M_PI_2 * brush_settings->uv_random;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_UV_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_uv, 0, random_settings.pen_press);
+ }
+
+ pt->uv_rot += value;
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
@@ -743,10 +820,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
return GP_STROKEADD_INVALID;
}
- /* Set vertex colors for buffer. */
- ED_gpencil_sbuffer_vertex_color_set(
- p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
-
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
@@ -767,6 +840,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(p->depsgraph,
+ p->ob,
+ p->scene->toolsettings,
+ p->brush,
+ p->material,
+ p->random_settings.hsv,
+ p->random_settings.pen_press);
+
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
/* Apply jitter to position */
if (brush_settings->draw_jitter > 0.0f) {
@@ -780,24 +862,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
const float fac = rand * square_f(exp_factor) * jitpress;
gp_brush_jitter(gpd, pt, fac);
}
- /* apply randomness to pressure */
- if (brush_settings->draw_random_press > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
- CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
- }
- /* apply randomness to uv texture rotation */
- if (brush_settings->uv_random > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->uv_rot += rand * M_PI * brush_settings->uv_random;
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
- /* apply randomness to color strength */
- if (brush_settings->draw_random_strength) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->strength *= 1.0 + rand * brush_settings->draw_random_strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, true, true, true);
}
/* apply angle of stroke to brush size */
@@ -809,7 +876,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
pt->time = (float)(curtime - p->inittime);
/* point uv (only 3d view) */
- if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
+ if ((p->area->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
@@ -956,9 +1023,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
pt++;
@@ -991,7 +1059,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
BKE_gpencil_dvert_ensure(gps);
@@ -1110,11 +1178,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
pt->uv_rot = ptc->uv_rot;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if (dvert != NULL) {
dvert->totweight = 0;
@@ -1142,6 +1211,16 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; /* reduce the factor */
}
}
+ /* If reproject the stroke using Stroke mode, need to apply a smooth because
+ * the reprojection creates small jitter. */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) {
+ float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
+ float sfac = interpf(1.0f, 0.2f, ifac);
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_stroke_smooth(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
+ }
+ }
/* Simplify adaptive */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
@@ -1239,7 +1318,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
gp_settings = eraser->gpencil_settings;
}
- if ((gp_settings != NULL) && (p->sa->spacetype == SPACE_VIEW3D) &&
+ if ((gp_settings != NULL) && (p->area->spacetype == SPACE_VIEW3D) &&
(gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
RegionView3D *rv3d = p->region->regiondata;
bGPDlayer *gpl = p->gpl;
@@ -1356,7 +1435,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
- const float mvalo[2],
const int radius,
const rcti *rect)
{
@@ -1475,7 +1553,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
@@ -1591,9 +1669,9 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + calc_radius;
rect.ymax = p->mval[1] + calc_radius;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0);
}
@@ -1631,8 +1709,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
+ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect);
}
}
}
@@ -1736,13 +1814,19 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
changed = true;
}
- /* be sure curves are initializated */
+ /* Be sure curves are initializated. */
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_pressure);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_strength);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_uv);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_hue);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_saturation);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_value);
/* assign to temp tGPsdata */
p->brush = paint->brush;
@@ -1814,7 +1898,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
* - must verify that region data is 3D-view (and not something else)
*/
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->align_flag = &ts->gpencil_v3d_align;
@@ -1829,7 +1913,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
}
if ((!obact) || (obact->type != OB_GPENCIL)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* if active object doesn't exist or isn't a GP Object, create one */
const float *cur = p->scene->cursor.location;
@@ -1987,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
return;
}
- /* Eraser mode: If no active strokes, just return. */
+ /* Eraser mode: If no active strokes, add one or just return. */
if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ *
+ * This is done only if additive drawing is enabled.
+ */
bool has_layer_to_erase = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
@@ -1997,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
continue;
}
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
+ */
if (gpl->actframe && gpl->actframe->strokes.first) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ }
has_layer_to_erase = true;
break;
}
}
+ /* Ensure this gets set. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ p->gpf = p->gpl->actframe;
+ }
+
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
@@ -2056,8 +2162,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
+ if (p->area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->area->spacedata.first;
RegionView3D *rv3d = p->region->regiondata;
/* for camera view set the subrect */
@@ -2074,7 +2180,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gsc.gpd = p->gpd;
p->gsc.gpl = p->gpl;
- p->gsc.sa = p->sa;
+ p->gsc.area = p->area;
p->gsc.region = p->region;
p->gsc.v2d = p->v2d;
@@ -2085,7 +2191,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
+ switch (p->area->spacetype) {
case SPACE_VIEW3D: {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
@@ -2110,7 +2216,7 @@ static void gp_paint_strokeend(tGPsdata *p)
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->region);
@@ -2193,18 +2299,17 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
}
/* Turn brush cursor in 3D view on/off */
-static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
{
if (p->erasercursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ WM_paint_cursor_end(p->erasercursor);
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
NULL, /* XXX */
gpencil_draw_eraser,
@@ -2229,7 +2334,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* check size of buffer before cleanup, to determine if anything happened here */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
}
/* always store the new eraser size to be used again next time
@@ -2241,7 +2346,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
}
/* restore cursor to indicate end of drawing */
- if (p->sa->spacetype != SPACE_VIEW3D) {
+ if (p->area->spacetype != SPACE_VIEW3D) {
WM_cursor_modal_restore(CTX_wm_window(C));
}
else {
@@ -2688,6 +2793,8 @@ static void gpencil_draw_apply_event(bContext *C,
/* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
p->pressure = event->tablet.pressure;
+ /* By default use pen pressure for random curves but attenuated. */
+ p->random_settings.pen_press = pow(p->pressure, 3.0f);
/* Hack for pressure sensitive eraser on D+RMB when using a tablet:
* The pen has to float over the tablet surface, resulting in
@@ -3040,11 +3147,13 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
p = op->customdata;
}
+ /* Init random settings. */
+ ED_gpencil_init_random_settings(p->brush, event->mval, &p->random_settings);
/* TODO: set any additional settings that we can take from the events?
* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ gpencil_draw_toggle_eraser_cursor(p, true);
}
else {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
@@ -3094,10 +3203,10 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
-static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *screen = CTX_wm_screen(C);
+ return (BLI_findindex(&screen->areabase, area_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
@@ -3107,7 +3216,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
- if (CTX_wm_area(C) != p->sa) {
+ if (CTX_wm_area(C) != p->area) {
printf("\t\t\tGP - wrong area execution abort!\n");
p->status = GP_STATUS_ERROR;
}
@@ -3125,6 +3234,30 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
return op->customdata;
}
+/* Apply pressure change depending of the angle of the stroke for a segment. */
+static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt)
+{
+ Brush *brush = p->brush;
+ /* Sensitivity. */
+ const float sen = brush->gpencil_settings->draw_angle_factor;
+ /* Default angle of brush in radians */
+ const float angle = brush->gpencil_settings->draw_angle;
+
+ float mvec[2];
+ float fac;
+
+ /* angle vector of the brush with full thickness */
+ float v0[2] = {cos(angle), sin(angle)};
+
+ mvec[0] = pt->x - pt_prev->x;
+ mvec[1] = pt->y - pt_prev->y;
+ normalize_v2(mvec);
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f);
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+}
+
/* Add arc points between two mouse events using the previous segment to determine the vertice of
* the arc.
* /+ CTL
@@ -3139,10 +3272,17 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
{
bGPdata *gpd = p->gpd;
+ BrushGpencilSettings *brush_settings = p->brush->gpencil_settings;
+
if (gpd->runtime.sbuffer_used < 3) {
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Apply other randomness to first points. */
+ for (int i = 0; i < gpd->runtime.sbuffer_used; i++) {
+ tGPspoint *pt = &points[i];
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
+ }
return;
}
-
int idx_prev = gpd->runtime.sbuffer_used;
/* Add space for new arc points. */
@@ -3197,7 +3337,9 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
+ float stepcolor = 1.0f / segments;
+ tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
@@ -3206,6 +3348,20 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
pt->strength = pt_prev->strength;
+ /* Interpolate vertex color. */
+ interp_v4_v4v4(
+ pt->vert_color, pt_before->vert_color, pt_prev->vert_color, stepcolor * (i + 1));
+
+ /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */
+ if (brush_settings->draw_angle_factor != 0.0f) {
+ gp_brush_angle_segment(p, pt_step, pt);
+ CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f);
+ /* Use the previous interpolated point for next segment. */
+ pt_step = pt;
+ }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
a += step;
}
@@ -3257,6 +3413,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
else {
@@ -3273,6 +3430,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
}
@@ -3481,18 +3639,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(
+ p->area, RGN_TYPE_ANY, event->x, event->y);
if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n",
current_region,
p->region,
event->x,
event->y,
- p->sa->totrct.xmin,
- p->sa->totrct.ymin,
- p->sa->totrct.xmax,
- p->sa->totrct.ymax);
+ p->area->totrct.xmin,
+ p->area->totrct.ymin,
+ p->area->totrct.xmax,
+ p->area->totrct.ymax);
}
if (current_region) {
@@ -3540,7 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p->paintmode = RNA_enum_get(op->ptr, "mode");
}
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+ gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER);
/* not painting, so start stroke (this should be mouse-button down) */
p = gpencil_stroke_begin(C, op);
@@ -3637,7 +3796,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa)) {
+ if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 2b30a415086..875a6265497 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -124,8 +124,13 @@ static void gp_session_validatebuffer(tGPDprimitive *p)
gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
/* Set vertex colors for buffer. */
- ED_gpencil_sbuffer_vertex_color_set(
- p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
+ ED_gpencil_sbuffer_vertex_color_set(p->depsgraph,
+ p->ob,
+ p->scene->toolsettings,
+ p->brush,
+ p->material,
+ p->random_settings.hsv,
+ 1.0f);
if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC;
@@ -240,8 +245,8 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi)
static bool gpencil_primitive_add_poll(bContext *C)
{
/* only 3D view */
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return 0;
}
@@ -681,6 +686,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
ToolSettings *ts = tgpi->scene->toolsettings;
bGPdata *gpd = tgpi->gpd;
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ GpRandomSettings random_settings = tgpi->random_settings;
bGPDstroke *gps = tgpi->gpf->strokes.first;
GP_Sculpt_Settings *gset = &ts->gp_sculpt;
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -735,11 +742,11 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
BKE_curvemapping_initialize(ts->gp_sculpt.cur_primitive);
}
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter);
+ if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ BKE_curvemapping_initialize(brush_settings->curve_jitter);
}
- if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength);
+ if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ BKE_curvemapping_initialize(brush_settings->curve_strength);
}
/* get an array of depths, far depths are blended */
@@ -841,10 +848,9 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
tGPspoint *p2d = &points2D[i];
/* set rnd value for reuse */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
+ if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) {
p2d->rnd[0] = BLI_rng_get_float(tgpi->rng);
p2d->rnd[1] = BLI_rng_get_float(tgpi->rng);
- p2d->rnd[2] = BLI_rng_get_float(tgpi->rng);
p2d->rnd_dirty = true;
}
@@ -858,7 +864,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* calc pressure */
float curve_pressure = 1.0;
float pressure = 1.0;
- float strength = brush->gpencil_settings->draw_strength;
+ float strength = brush_settings->draw_strength;
/* normalize value to evaluate curve */
if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) {
@@ -868,20 +874,18 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* apply jitter to position */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_jitter > 0.0f)) {
+ if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush_settings->draw_jitter > 0.0f)) {
float jitter;
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
- jitter = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_jitter, 0, curve_pressure);
+ if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) {
+ jitter = BKE_curvemapping_evaluateF(brush_settings->curve_jitter, 0, curve_pressure);
}
else {
- jitter = brush->gpencil_settings->draw_jitter;
+ jitter = brush_settings->draw_jitter;
}
/* exponential value */
- const float exfactor = square_f(brush->gpencil_settings->draw_jitter + 2.0f);
+ const float exfactor = square_f(brush_settings->draw_jitter + 2.0f);
const float fac = p2d->rnd[0] * exfactor * jitter;
/* vector */
@@ -906,47 +910,68 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
add_v2_v2(&p2d->x, svec);
}
- /* apply randomness to pressure */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_press > 0.0f)) {
- if (p2d->rnd[0] > 0.5f) {
- pressure -= (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[1];
- }
- else {
- pressure += (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[2];
- }
- }
-
/* color strength */
- if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
- float curvef = BKE_curvemapping_evaluateF(
- brush->gpencil_settings->curve_strength, 0, curve_pressure);
+ if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) {
+ float curvef = BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, curve_pressure);
strength *= curvef;
- strength *= brush->gpencil_settings->draw_strength;
+ strength *= brush_settings->draw_strength;
}
CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
- /* apply randomness to color strength */
- if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) &&
- (brush->gpencil_settings->draw_random_strength > 0.0f)) {
- if (p2d->rnd[2] > 0.5f) {
- strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0];
+ if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
+ /* Apply randomness to pressure. */
+ if (brush_settings->draw_random_press > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f;
+ pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ }
+ else {
+ pressure *= 1.0 + random_settings.pressure * brush_settings->draw_random_press;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) {
+ pressure *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_pressure, 0, pressure);
+ }
+
+ CLAMP(pressure, 0.1f, 1.0f);
}
- else {
- strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1];
+
+ /* Apply randomness to color strength. */
+ if (brush_settings->draw_random_strength) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f;
+ strength *= 1.0 + rand * brush_settings->draw_random_strength;
+ }
+ else {
+ strength *= 1.0 + random_settings.strength * brush_settings->draw_random_strength;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) {
+ strength *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_strength, 0, pressure);
+ }
+
+ CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
- CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
copy_v2_v2(&tpt->x, &p2d->x);
- CLAMP_MIN(pressure, 0.1f);
-
tpt->pressure = pressure;
tpt->strength = strength;
tpt->time = p2d->time;
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(tgpi->depsgraph,
+ tgpi->ob,
+ tgpi->scene->toolsettings,
+ tgpi->brush,
+ tgpi->material,
+ tgpi->random_settings.hsv,
+ strength);
+
/* point uv */
if (gpd->runtime.sbuffer_used > 0) {
tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
@@ -954,8 +979,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
/* get origin to reproject point */
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin);
/* reproject current */
ED_gpencil_tpoint_to_point(tgpi->region, origin, tpt, &spt);
ED_gp_project_point_to_plane(
@@ -987,21 +1011,15 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
}
/* convert screen-coordinates to 3D coordinates */
- gp_stroke_convertcoords_tpoint(tgpi->scene,
- tgpi->region,
- tgpi->ob,
- tgpi->gpl,
- p2d,
- depth_arr ? depth_arr + i : NULL,
- &pt->x);
+ gp_stroke_convertcoords_tpoint(
+ tgpi->scene, tgpi->region, tgpi->ob, p2d, depth_arr ? depth_arr + i : NULL, &pt->x);
pt->pressure = pressure;
pt->strength = strength;
pt->time = 0.0f;
pt->flag = 0;
pt->uv_fac = tpt->uv_fac;
- /* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ copy_v4_v4(pt->vert_color, tpt->vert_color);
if (gps->dvert != NULL) {
MDeformVert *dvert = &gps->dvert[i];
@@ -1019,15 +1037,14 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
for (int i = 0; i < tgpi->gpd->runtime.tot_cp_points; i++) {
bGPDcontrolpoint *cp = &cps[i];
gp_stroke_convertcoords_tpoint(
- tgpi->scene, tgpi->region, tgpi->ob, tgpi->gpl, (tGPspoint *)cp, NULL, &cp->x);
+ tgpi->scene, tgpi->region, tgpi->ob, (tGPspoint *)cp, NULL, &cp->x);
}
}
/* reproject to plane */
if (!is_depth) {
float origin[3];
- ED_gpencil_drawing_reference_get(
- tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin);
+ ED_gpencil_drawing_reference_get(tgpi->scene, tgpi->ob, ts->gpencil_v3d_align, origin);
ED_gp_project_stroke_to_plane(
tgpi->scene, tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1);
}
@@ -1144,10 +1161,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
tgpi->scene = scene;
tgpi->ob = CTX_data_active_object(C);
tgpi->ob_eval = (Object *)DEG_get_evaluated_object(tgpi->depsgraph, tgpi->ob);
- tgpi->sa = CTX_wm_area(C);
+ tgpi->area = CTX_wm_area(C);
tgpi->region = CTX_wm_region(C);
tgpi->rv3d = tgpi->region->regiondata;
- tgpi->v3d = tgpi->sa->spacedata.first;
+ tgpi->v3d = tgpi->area->spacedata.first;
tgpi->win = CTX_wm_window(C);
/* save original type */
@@ -1161,11 +1178,12 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* if brush doesn't exist, create a new set (fix damaged files from old versions) */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
/* Set Draw brush. */
Brush *brush = BKE_paint_toolslots_brush_get(paint, 0);
+
BKE_brush_tool_set(brush, paint, 0);
BKE_paint_brush_set(paint, brush);
tgpi->brush = brush;
@@ -1233,6 +1251,9 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
gpencil_primitive_init(C, op);
tgpi = op->customdata;
+ /* Init random settings. */
+ ED_gpencil_init_random_settings(tgpi->brush, event->mval, &tgpi->random_settings);
+
const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
if (!is_modal) {
tgpi->flag = IN_PROGRESS;
@@ -1269,6 +1290,7 @@ static void gpencil_primitive_interaction_end(bContext *C,
ToolSettings *ts = tgpi->scene->toolsettings;
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
const int def_nr = tgpi->ob->actdef - 1;
const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr);
@@ -1292,8 +1314,8 @@ static void gpencil_primitive_interaction_end(bContext *C,
gps = tgpi->gpf->strokes.first;
if (gps) {
gps->thickness = brush->size;
- gps->hardeness = brush->gpencil_settings->hardeness;
- copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio);
+ gps->hardeness = brush_settings->hardeness;
+ copy_v2_v2(gps->aspect_ratio, brush_settings->aspect_ratio);
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
@@ -1456,23 +1478,25 @@ static void gpencil_primitive_edit_event_handling(
static void gpencil_primitive_strength(tGPDprimitive *tgpi, bool reset)
{
Brush *brush = tgpi->brush;
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+
if (brush) {
if (reset) {
- brush->gpencil_settings->draw_strength = tgpi->brush_strength;
+ brush_settings->draw_strength = tgpi->brush_strength;
tgpi->brush_strength = 0.0f;
}
else {
if (tgpi->brush_strength == 0.0f) {
- tgpi->brush_strength = brush->gpencil_settings->draw_strength;
+ tgpi->brush_strength = brush_settings->draw_strength;
}
float move[2];
sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo);
float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f;
- brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
+ brush_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move));
}
/* limit low limit because below 0.2f the stroke is invisible */
- CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f);
+ CLAMP(brush_settings->draw_strength, 0.2f, 1.0f);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 59b14a47d1d..f7f3b128351 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -91,7 +91,7 @@ typedef struct tGP_BrushEditData {
Scene *scene;
Object *object;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
/* Current GPencil datablock */
@@ -1181,7 +1181,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gso->is_transformed = false;
}
- gso->sa = CTX_wm_area(C);
+ gso->area = CTX_wm_area(C);
gso->region = CTX_wm_region(C);
Paint *paint = &ts->gp_sculptpaint->paint;
@@ -1307,8 +1307,8 @@ static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
/* poll callback for stroke sculpting operator(s) */
static bool gpsculpt_brush_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype != SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype != SPACE_VIEW3D) {
return false;
}
@@ -1371,7 +1371,7 @@ static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
}
GP_SpaceConversion *gsc = &gso->gsc;
- bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
+ bGPDstroke *gps_orig = (gps_eval->runtime.gps_orig) ? gps_eval->runtime.gps_orig : gps_eval;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
bGPDspoint *pt_orig_prev = NULL;
@@ -1422,6 +1422,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
GP_SpaceConversion *gsc = &gso->gsc;
rcti *rect = &gso->brush_rect;
Brush *brush = gso->brush;
+ char tool = gso->brush->gpencil_sculpt_tool;
const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
gso->brush->size;
@@ -1495,16 +1496,18 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* Apply operation to these points */
bool ok = false;
/* To each point individually... */
pt = &gps->points[i];
+ if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) {
+ continue;
+ }
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
@@ -1521,7 +1524,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
pt = &gps->points[i + 1];
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
@@ -1542,7 +1545,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
pt = &gps->points[i];
pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
- if (pt_active != NULL) {
+ if ((pt_active != NULL) && (index < gps_active->totpoints)) {
rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 03e8001341f..7accf48832a 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -43,6 +43,7 @@
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_material.h"
#include "BKE_report.h"
#include "UI_interface.h"
@@ -67,6 +68,45 @@
/** \name Shared Utilities
* \{ */
+/* Check if mouse inside stroke. */
+static bool gpencil_point_inside_stroke(bGPDstroke *gps,
+ GP_SpaceConversion *gsc,
+ int mouse[2],
+ const float diff_mat[4][4])
+{
+ bool hit = false;
+ if (gps->totpoints == 0) {
+ return hit;
+ }
+
+ int(*mcoords)[2] = NULL;
+ int len = gps->totpoints;
+ mcoords = MEM_mallocN(sizeof(int) * 2 * len, __func__);
+
+ /* Convert stroke to 2D array of points. */
+ bGPDspoint *pt;
+ int i;
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy(gsc, gps, &pt2, &mcoords[i][0], &mcoords[i][1]);
+ }
+
+ /* Compute boundbox of lasso (for faster testing later). */
+ rcti rect;
+ BLI_lasso_boundbox(&rect, mcoords, len);
+
+ /* Test if point inside stroke. */
+ hit = ((!ELEM(V2D_IS_CLIPPED, mouse[0], mouse[1])) &&
+ BLI_rcti_isect_pt(&rect, mouse[0], mouse[1]) &&
+ BLI_lasso_is_point_inside(mcoords, len, mouse[0], mouse[1], INT_MAX));
+
+ /* Free memory. */
+ MEM_SAFE_FREE(mcoords);
+
+ return hit;
+}
+
/* Convert sculpt mask mode to Select mode */
static int gpencil_select_mode_from_sculpt(eGP_Sculpt_SelectMaskFlag mode)
{
@@ -919,13 +959,12 @@ static bool gp_stroke_do_circle_sel(bGPdata *UNUSED(gpd),
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
((!ELEM(V2D_IS_CLIPPED, x1, y1)) && BLI_rcti_isect_pt(rect, x1, y1))) {
float mval[2] = {(float)mx, (float)my};
- float mvalo[2] = {(float)mx, (float)my}; /* dummy - this isn't used... */
/* check if point segment of stroke had anything to do with
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, x0, y0, x1, y1)) {
+ if (gp_stroke_inside_circle(mval, radius, x0, y0, x1, y1)) {
/* change selection of stroke, and then of both points
* (as the last point otherwise wouldn't get selected
* as we only do n-1 loops through).
@@ -1016,7 +1055,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const int mx = RNA_int_get(op->ptr, "x");
const int my = RNA_int_get(op->ptr, "y");
@@ -1029,7 +1068,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1052,8 +1091,7 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
rect.ymax = my + radius;
/* find visible strokes, and select if hit */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
changed |= gp_stroke_do_circle_sel(gpd,
gpl,
gps,
@@ -1120,15 +1158,13 @@ typedef bool (*GPencilTestFn)(bGPDstroke *gps,
const float diff_mat[4][4],
void *user_data);
-static int gpencil_generic_select_exec(bContext *C,
- wmOperator *op,
- GPencilTestFn is_inside_fn,
- void *user_data)
+static int gpencil_generic_select_exec(
+ bContext *C, wmOperator *op, GPencilTestFn is_inside_fn, rcti box, void *user_data)
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int selectmode;
if (ob && ob->mode == OB_MODE_SCULPT_GPENCIL) {
@@ -1145,7 +1181,6 @@ static int gpencil_generic_select_exec(bContext *C,
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
const bool segmentmode = ((selectmode == GP_SELECTMODE_SEGMENT) &&
((gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0));
- const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const float scale = ts->gp_sculpt.isect_threshold;
@@ -1155,7 +1190,7 @@ static int gpencil_generic_select_exec(bContext *C,
bool changed = false;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1180,18 +1215,15 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* select/deselect points */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
+ bool whole = false;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
- continue;
- }
- bGPDspoint *pt_active = pt->runtime.pt_orig;
+ bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
/* convert point coords to screenspace */
const bool is_inside = is_inside_fn(gps, pt, &gsc, gpstroke_iter.diff_mat, user_data);
@@ -1201,9 +1233,10 @@ static int gpencil_generic_select_exec(bContext *C,
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
+ hit = true;
- /* expand selection to segment */
- if ((sel_op_result != -1) && (segmentmode)) {
+ /* Expand selection to segment. */
+ if (segmentmode) {
bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
ED_gpencil_select_stroke_segment(
@@ -1219,16 +1252,28 @@ static int gpencil_generic_select_exec(bContext *C,
}
}
- /* if stroke mode expand selection */
- if (strokemode) {
- const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
- const bool is_inside = hit;
+ /* If nothing hit, check if the mouse is inside a filled stroke using the center or
+ * Box or lasso area. */
+ if (!hit) {
+ /* Only check filled strokes. */
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+ continue;
+ }
+ int mval[2];
+ mval[0] = (box.xmax + box.xmin) / 2;
+ mval[1] = (box.ymax + box.ymin) / 2;
+
+ whole = gpencil_point_inside_stroke(gps_active, &gsc, mval, gpstroke_iter.diff_mat);
+ }
+
+ /* if stroke mode expand selection. */
+ if ((strokemode) || (whole)) {
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active) || whole;
+ const bool is_inside = hit || whole;
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
- continue;
- }
bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
if (sel_op_result) {
@@ -1264,7 +1309,6 @@ static int gpencil_generic_select_exec(bContext *C,
WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
}
-
return OPERATOR_FINISHED;
}
@@ -1296,7 +1340,8 @@ static int gpencil_box_select_exec(bContext *C, wmOperator *op)
{
struct GP_SelectBoxUserData data = {0};
WM_operator_properties_border_to_rcti(op, &data.rect);
- return gpencil_generic_select_exec(C, op, gpencil_test_box, &data);
+ rcti rect = data.rect;
+ return gpencil_generic_select_exec(C, op, gpencil_test_box, rect, &data);
}
void GPENCIL_OT_select_box(wmOperatorType *ot)
@@ -1330,8 +1375,8 @@ void GPENCIL_OT_select_box(wmOperatorType *ot)
struct GP_SelectLassoUserData {
rcti rect;
- const int (*mcords)[2];
- int mcords_len;
+ const int (*mcoords)[2];
+ int mcoords_len;
};
static bool gpencil_test_lasso(bGPDstroke *gps,
@@ -1347,25 +1392,26 @@ static bool gpencil_test_lasso(bGPDstroke *gps,
gp_point_to_xy(gsc, gps, &pt2, &x0, &y0);
/* test if in lasso boundbox + within the lasso noose */
return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) &&
- BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX));
+ BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX));
}
static int gpencil_lasso_select_exec(bContext *C, wmOperator *op)
{
struct GP_SelectLassoUserData data = {0};
- data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len);
+ data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len);
/* Sanity check. */
- if (data.mcords == NULL) {
+ if (data.mcoords == NULL) {
return OPERATOR_PASS_THROUGH;
}
/* Compute boundbox of lasso (for faster testing later). */
- BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len);
+ BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len);
- int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data);
+ rcti rect = data.rect;
+ int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, rect, &data);
- MEM_freeN((void *)data.mcords);
+ MEM_freeN((void *)data.mcoords);
return ret;
}
@@ -1419,7 +1465,7 @@ static void deselect_all_selected(bContext *C)
static int gpencil_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1427,7 +1473,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* "radius" is simply a threshold (screen space) to make it easier to test with a tolerance */
- const float radius = 0.50f * U.widget_unit;
+ const float radius = 0.4f * U.widget_unit;
const int radius_squared = (int)(radius * radius);
const bool use_shift_extend = RNA_boolean_get(op->ptr, "use_shift_extend");
@@ -1447,7 +1493,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
int hit_distance = radius_squared;
/* sanity checks */
- if (sa == NULL) {
+ if (area == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active area");
return OPERATOR_CANCELLED;
}
@@ -1472,13 +1518,19 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
RNA_int_get_array(op->ptr, "location", mval);
/* First Pass: Find stroke point which gets hit */
- /* XXX: maybe we should go from the top of the stack down instead... */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
+ /* Check boundbox to speedup. */
+ float fmval[2];
+ copy_v2fl_v2i(fmval, mval);
+ if (!ED_gpencil_stroke_check_collision(
+ &gsc, gps_active, fmval, radius, gpstroke_iter.diff_mat)) {
+ continue;
+ }
+
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
@@ -1506,11 +1558,27 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
}
}
}
+ if (ELEM(NULL, hit_stroke, hit_point)) {
+ /* If nothing hit, check if the mouse is inside any filled stroke.
+ * Only check filling materials. */
+ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
+ if ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0) {
+ continue;
+ }
+ bool hit_fill = gpencil_point_inside_stroke(gps, &gsc, mval, gpstroke_iter.diff_mat);
+ if (hit_fill) {
+ hit_stroke = gps_active;
+ hit_point = &gps_active->points[0];
+ /* Extend selection to all stroke. */
+ whole = true;
+ }
+ }
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
/* Abort if nothing hit... */
if (ELEM(NULL, hit_stroke, hit_point)) {
+
if (deselect_all) {
/* since left mouse select change, deselect all if click outside any hit */
deselect_all_selected(C);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 276be071e0b..1962eba5017 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -30,11 +30,14 @@
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
+#include "PIL_time.h"
+
#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_meshdata_types.h"
@@ -74,6 +77,7 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
#include "GPU_immediate.h"
@@ -93,13 +97,13 @@
* and an RNA-pointer to trace back to whatever owns it,
* when context info is not available.
*/
-bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *sa, Object *ob, PointerRNA *r_ptr)
+bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, PointerRNA *r_ptr)
{
/* if there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing...
*/
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES: /* properties */
case SPACE_INFO: /* header info */
case SPACE_TOPBAR: /* Topbar */
@@ -132,16 +136,16 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *sa, Object *ob, PointerRN
* when context info is not available.
*/
bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
- ScrArea *sa,
+ ScrArea *area,
Scene *scene,
PointerRNA *r_ptr)
{
/* If there's an active area, check if the particular editor may
* have defined any special Grease Pencil context for editing. */
- if (sa) {
- SpaceLink *sl = sa->spacedata.first;
+ if (area) {
+ SpaceLink *sl = area->spacedata.first;
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES: /* properties */
case SPACE_INFO: /* header info */
{
@@ -236,10 +240,10 @@ bGPdata **ED_annotation_data_get_pointers_direct(ID *screen_id,
* and an RNA-pointer to trace back to whatever owns it. */
bGPdata **ED_gpencil_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
- return ED_gpencil_data_get_pointers_direct(sa, ob, r_ptr);
+ return ED_gpencil_data_get_pointers_direct(area, ob, r_ptr);
}
/* Get pointer to active Grease Pencil datablock,
@@ -248,23 +252,23 @@ bGPdata **ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
{
ID *screen_id = (ID *)CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- return ED_annotation_data_get_pointers_direct(screen_id, sa, scene, r_ptr);
+ return ED_annotation_data_get_pointers_direct(screen_id, area, scene, r_ptr);
}
/* -------------------------------------------------------- */
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_gpencil_data_get_active_direct(ScrArea *sa, Object *ob)
+bGPdata *ED_gpencil_data_get_active_direct(ScrArea *area, Object *ob)
{
- bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, ob, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, ob, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
/* Get the active Grease Pencil datablock, when context is not available */
-bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *sa, Scene *scene)
+bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scene *scene)
{
- bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, sa, scene, NULL);
+ bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct(screen_id, area, scene, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
@@ -299,13 +303,13 @@ bGPdata *ED_annotation_data_get_active(const bContext *C)
*/
bGPdata *ED_gpencil_data_get_active_evaluated(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- return ED_gpencil_data_get_active_direct(sa, ob_eval);
+ return ED_gpencil_data_get_active_direct(area, ob_eval);
}
/* -------------------------------------------------------- */
@@ -481,6 +485,40 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
return item;
}
+/* Just existing Materials */
+const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C,
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ Object *ob = CTX_data_active_object(C);
+ EnumPropertyItem *item = NULL, item_tmp = {0};
+ int totitem = 0;
+ int i = 0;
+
+ if (ELEM(NULL, C, ob)) {
+ return DummyRNA_DEFAULT_items;
+ }
+
+ /* Existing materials */
+ for (i = 1; i <= ob->totcol; i++) {
+ Material *ma = BKE_object_material_get(ob, i);
+ if (ma) {
+ item_tmp.identifier = ma->id.name + 2;
+ item_tmp.name = ma->id.name + 2;
+ item_tmp.value = i;
+ item_tmp.icon = ma->preview ? ma->preview->icon_id : ICON_NONE;
+
+ RNA_enum_item_add(&item, &totitem, &item_tmp);
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
+}
+
/* ******************************************************** */
/* Brush Tool Core */
@@ -494,8 +532,7 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C,
* \param x0, y0: The screen-space x and y coordinates of the start of the stroke segment
* \param x1, y1: The screen-space x and y coordinates of the end of the stroke segment
*/
-bool gp_stroke_inside_circle(
- const float mval[2], const float UNUSED(mvalo[2]), int rad, int x0, int y0, int x1, int y1)
+bool gp_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
{
/* simple within-radius check for now */
const float screen_co_a[2] = {x0, y0};
@@ -514,25 +551,25 @@ bool gp_stroke_inside_circle(
/* Check whether given stroke can be edited given the supplied context */
/* TODO: do we need additional flags for screenspace vs dataspace? */
-bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
+bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
{
/* sanity check */
- if (ELEM(NULL, sa, gps)) {
+ if (ELEM(NULL, area, gps)) {
return false;
}
/* filter stroke types by flags + spacetype */
if (gps->flag & GP_STROKE_3DSPACE) {
/* 3D strokes - only in 3D view */
- return ((sa->spacetype == SPACE_VIEW3D) || (sa->spacetype == SPACE_PROPERTIES));
+ return ((area->spacetype == SPACE_VIEW3D) || (area->spacetype == SPACE_PROPERTIES));
}
else if (gps->flag & GP_STROKE_2DIMAGE) {
/* Special "image" strokes - only in Image Editor */
- return (sa->spacetype == SPACE_IMAGE);
+ return (area->spacetype == SPACE_IMAGE);
}
else if (gps->flag & GP_STROKE_2DSPACE) {
/* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
- return (sa->spacetype != SPACE_VIEW3D);
+ return (area->spacetype != SPACE_VIEW3D);
}
else {
/* view aligned - anything goes */
@@ -543,8 +580,8 @@ bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
/* Check whether given stroke can be edited in the current context */
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
{
- ScrArea *sa = CTX_wm_area(C);
- return ED_gpencil_stroke_can_use_direct(sa, gps);
+ ScrArea *area = CTX_wm_area(C);
+ return ED_gpencil_stroke_can_use_direct(area, gps);
}
/* Check whether given stroke can be edited for the current color */
@@ -575,7 +612,7 @@ bool ED_gpencil_stroke_color_use(Object *ob, const bGPDlayer *gpl, const bGPDstr
*/
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
/* zero out the storage (just in case) */
@@ -586,12 +623,12 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
r_gsc->scene = CTX_data_scene(C);
r_gsc->ob = CTX_data_active_object(C);
- r_gsc->sa = sa;
+ r_gsc->area = area;
r_gsc->region = region;
r_gsc->v2d = &region->v2d;
/* init region-specific stuff */
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (area->spacetype == SPACE_VIEW3D) {
wmWindow *win = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@@ -671,8 +708,8 @@ void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl,
/**
* Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
*
- * \param[out] r_x The screen-space x-coordinate of the point
- * \param[out] r_y The screen-space y-coordinate of the point
+ * \param[out] r_x: The screen-space x-coordinate of the point
+ * \param[out] r_y: The screen-space y-coordinate of the point
*
* \warning This assumes that the caller has already checked
* whether the stroke in question can be drawn.
@@ -686,8 +723,8 @@ void gp_point_to_xy(
int xyval[2];
/* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
if (gps->flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_int_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
@@ -744,8 +781,8 @@ void gp_point_to_xy_fl(const GP_SpaceConversion *gsc,
float xyval[2];
/* sanity checks */
- BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
- BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->area->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->area->spacetype != SPACE_VIEW3D));
if (gps->flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_float_global(region, &pt->x, xyval, V3D_PROJ_TEST_NOP) ==
@@ -803,7 +840,7 @@ void gp_point_3d_to_xy(const GP_SpaceConversion *gsc,
float xyval[2];
/* sanity checks */
- BLI_assert((gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert((gsc->area->spacetype == SPACE_VIEW3D));
if (flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_float_global(region, pt, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
@@ -869,8 +906,7 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
const RegionView3D *rv3d = gsc->region->regiondata;
float rvec[3];
- ED_gpencil_drawing_reference_get(
- scene, gsc->ob, gsc->gpl, scene->toolsettings->gpencil_v3d_align, rvec);
+ ED_gpencil_drawing_reference_get(scene, gsc->ob, scene->toolsettings->gpencil_v3d_align, rvec);
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
@@ -905,7 +941,6 @@ bool gp_point_xy_to_3d(const GP_SpaceConversion *gsc,
void gp_stroke_convertcoords_tpoint(Scene *scene,
ARegion *region,
Object *ob,
- bGPDlayer *gpl,
const tGPspoint *point2D,
float *depth,
float r_out[3])
@@ -929,7 +964,7 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
/* Current method just converts each point in screen-coordinates to
* 3D-coordinates using the 3D-cursor as reference.
*/
- ED_gpencil_drawing_reference_get(scene, ob, gpl, ts->gpencil_v3d_align, rvec);
+ ED_gpencil_drawing_reference_get(scene, ob, ts->gpencil_v3d_align, rvec);
zfac = ED_view3d_calc_zfac(region->regiondata, rvec, NULL);
if (ED_view3d_project_float_global(region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
@@ -948,8 +983,10 @@ void gp_stroke_convertcoords_tpoint(Scene *scene,
* Get drawing reference point for conversion or projection of the stroke
* \param[out] r_vec : Reference point found
*/
-void ED_gpencil_drawing_reference_get(
- const Scene *scene, const Object *ob, bGPDlayer *UNUSED(gpl), char align_flag, float r_vec[3])
+void ED_gpencil_drawing_reference_get(const Scene *scene,
+ const Object *ob,
+ char align_flag,
+ float r_vec[3])
{
const float *fp = scene->cursor.location;
@@ -1328,7 +1365,7 @@ void ED_gpencil_add_defaults(bContext *C, Object *ob)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
}
/* ensure a color exists and is assigned to object */
@@ -1564,7 +1601,7 @@ void ED_gpencil_vgroup_deselect(bContext *C, Object *ob)
static bool gp_check_cursor_region(bContext *C, int mval_i[2])
{
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (!ELEM(ob->mode,
@@ -1576,7 +1613,7 @@ static bool gp_check_cursor_region(bContext *C, int mval_i[2])
}
/* TODO: add more spacetypes */
- if (!ELEM(sa->spacetype, SPACE_VIEW3D)) {
+ if (!ELEM(area->spacetype, SPACE_VIEW3D)) {
return false;
}
if ((region) && (region->regiontype != RGN_TYPE_WINDOW)) {
@@ -1834,19 +1871,18 @@ void ED_gpencil_toggle_brush_cursor(bContext *C, bool enable, void *customdata)
if (gset->paintcursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ WM_paint_cursor_end(gset->paintcursor);
gset->paintcursor = NULL;
}
else if (enable) {
/* in some situations cursor could be duplicated, so it is better disable first if exist */
if (gset->paintcursor) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), gset->paintcursor);
+ WM_paint_cursor_end(gset->paintcursor);
gset->paintcursor = NULL;
}
/* enable cursor */
- gset->paintcursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ gset->paintcursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
gp_brush_cursor_poll,
gp_brush_cursor_draw,
@@ -2174,7 +2210,8 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
float f = 0.0f;
int i2 = 0;
- bGPDframe *gpf = gpl->actframe;
+ bGPDlayer *gpl_orig = (gpl->runtime.gpl_orig) ? gpl->runtime.gpl_orig : gpl;
+ bGPDframe *gpf = gpl_orig->actframe;
if (gpf == NULL) {
return 0;
}
@@ -2187,7 +2224,7 @@ int ED_gpencil_select_stroke_segment(bGPDlayer *gpl,
/* Save list of strokes to check */
int totstrokes = 0;
- for (bGPDstroke *gps_iter = gpf->strokes.first; gps_iter; gps_iter = gps_iter->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps_iter, &gpf->strokes) {
if (gps_iter->totpoints < 2) {
continue;
}
@@ -2525,26 +2562,170 @@ void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke
}
}
-void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt)
+void ED_gpencil_point_vertex_color_set(ToolSettings *ts,
+ Brush *brush,
+ bGPDspoint *pt,
+ tGPspoint *tpt)
{
if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
- copy_v3_v3(pt->vert_color, brush->rgb);
- pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
- srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ if (tpt == NULL) {
+ copy_v3_v3(pt->vert_color, brush->rgb);
+ pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
+ srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color);
+ }
+ else {
+ copy_v3_v3(pt->vert_color, tpt->vert_color);
+ pt->vert_color[3] = brush->gpencil_settings->vertex_factor;
+ }
}
else {
zero_v4(pt->vert_color);
}
}
-void ED_gpencil_sbuffer_vertex_color_set(
- Depsgraph *depsgraph, Object *ob, ToolSettings *ts, Brush *brush, Material *material)
+void ED_gpencil_init_random_settings(Brush *brush,
+ const int mval[2],
+ GpRandomSettings *random_settings)
+{
+ int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+ /* Use mouse position to get randomness. */
+ int ix = mval[0] * seed;
+ int iy = mval[1] * seed;
+ int iz = ix + iy * seed;
+ zero_v3(random_settings->hsv);
+
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ /* Random to Hue. */
+ if (brush_settings->random_hue > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, iy)) * 2.0f - 1.0f;
+ random_settings->hsv[0] = rand * brush_settings->random_hue * 0.5f;
+ }
+ /* Random to Saturation. */
+ if (brush_settings->random_saturation > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, ix)) * 2.0f - 1.0f;
+ random_settings->hsv[1] = rand * brush_settings->random_saturation;
+ }
+ /* Random to Value. */
+ if (brush_settings->random_value > 0.0f) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix * iz, iy * iz)) * 2.0f - 1.0f;
+ random_settings->hsv[2] = rand * brush_settings->random_value;
+ }
+
+ /* Random to pressure. */
+ if (brush_settings->draw_random_press > 0.0f) {
+ random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f;
+ }
+
+ /* Randomn to color strength. */
+ if (brush_settings->draw_random_strength) {
+ random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f -
+ 1.0f;
+ }
+
+ /* Random to uv texture rotation. */
+ if (brush_settings->uv_random > 0.0f) {
+ random_settings->uv = BLI_hash_int_01(BLI_hash_int_2d(iy + iz, ix * iz)) * 2.0f - 1.0f;
+ }
+}
+
+static void gpencil_sbuffer_vertex_color_random(
+ bGPdata *gpd, Brush *brush, tGPspoint *tpt, float random_color[3], float pen_pressure)
+{
+ BrushGpencilSettings *brush_settings = brush->gpencil_settings;
+ if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
+ int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128;
+
+ int ix = (int)(tpt->x * seed);
+ int iy = (int)(tpt->y * seed);
+ int iz = ix + iy * seed;
+ float hsv[3];
+ float factor_value[3];
+ zero_v3(factor_value);
+
+ /* Apply randomness to Hue. */
+ if (brush_settings->random_hue > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) {
+
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[0] = rand * brush_settings->random_hue * 0.5f;
+ }
+ else {
+ factor_value[0] = random_color[0];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) {
+ factor_value[0] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_hue, 0, pen_pressure);
+ }
+ }
+
+ /* Apply randomness to Saturation. */
+ if (brush_settings->random_saturation > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[1] = rand * brush_settings->random_saturation;
+ }
+ else {
+ factor_value[1] = random_color[1];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) {
+ factor_value[1] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_saturation, 0, pen_pressure);
+ }
+ }
+
+ /* Apply randomness to Value. */
+ if (brush_settings->random_value > 0.0f) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d(iz, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f;
+ factor_value[2] = rand * brush_settings->random_value;
+ }
+ else {
+ factor_value[2] = random_color[2];
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) {
+ factor_value[2] *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_value, 0, pen_pressure);
+ }
+ }
+
+ rgb_to_hsv_v(tpt->vert_color, hsv);
+ add_v3_v3(hsv, factor_value);
+ /* For Hue need to cover all range, but for Saturation and Value
+ * is not logic because the effect is too hard, so the value is just clamped. */
+ if (hsv[0] < 0.0f) {
+ hsv[0] += 1.0f;
+ }
+ else if (hsv[0] > 1.0f) {
+ hsv[0] -= 1.0f;
+ }
+
+ CLAMP3(hsv, 0.0f, 1.0f);
+ hsv_to_rgb_v(hsv, tpt->vert_color);
+ }
+}
+
+void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph,
+ Object *ob,
+ ToolSettings *ts,
+ Brush *brush,
+ Material *material,
+ float random_color[3],
+ float pen_pressure)
{
bGPdata *gpd = (bGPdata *)ob->data;
Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id);
bGPdata *gpd_eval = (bGPdata *)ob_eval->data;
MaterialGPencilStyle *gp_style = material->gp_style;
+ int idx = gpd->runtime.sbuffer_used;
+ tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx;
+
float vertex_color[4];
copy_v3_v3(vertex_color, brush->rgb);
vertex_color[3] = brush->gpencil_settings->vertex_factor;
@@ -2559,15 +2740,18 @@ void ED_gpencil_sbuffer_vertex_color_set(
}
/* Copy stroke vertex color. */
if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) {
- copy_v4_v4(gpd->runtime.vert_color, vertex_color);
+ copy_v4_v4(tpt->vert_color, vertex_color);
}
else {
- copy_v4_v4(gpd->runtime.vert_color, gp_style->stroke_rgba);
+ copy_v4_v4(tpt->vert_color, gp_style->stroke_rgba);
}
- /* Copy to eval data because paint operators don't tag refresh until end for speedup painting. */
+ /* Random Color. */
+ gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure);
+
+ /* Copy to eval data because paint operators don't tag refresh until end for speedup
+ painting. */
if (gpd_eval != NULL) {
- copy_v4_v4(gpd_eval->runtime.vert_color, gpd->runtime.vert_color);
copy_v4_v4(gpd_eval->runtime.vert_color_fill, gpd->runtime.vert_color_fill);
gpd_eval->runtime.matid = gpd->runtime.matid;
}
diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c
index 1da32dcc537..0dfc7e0728e 100644
--- a/source/blender/editors/gpencil/gpencil_uv.c
+++ b/source/blender/editors/gpencil/gpencil_uv.c
@@ -59,8 +59,8 @@ typedef struct GpUvData {
float ob_scale;
float initial_length;
+ float initial_transform[2];
float pixel_size; /* use when mouse input is interpreted as spatial distance */
- bool is_modal;
/* Arrays of original loc/rot/scale by stroke. */
float (*array_loc)[2];
@@ -92,9 +92,9 @@ static void gpencil_uv_transform_update_header(wmOperator *op, bContext *C)
const char *str = TIP_("Confirm: Enter/LClick, Cancel: (Esc/RClick) %s");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
char flts_str[NUM_STR_REP_LEN * 2];
switch (mode) {
case GP_UV_TRANSLATE: {
@@ -120,7 +120,7 @@ static void gpencil_uv_transform_update_header(wmOperator *op, bContext *C)
break;
}
BLI_snprintf(msg, sizeof(msg), str, flts_str, flts_str + NUM_STR_REP_LEN);
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
}
@@ -140,19 +140,12 @@ static void gpencil_stroke_center(bGPDstroke *gps, float r_center[3])
}
}
-static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is_modal)
+static bool gpencil_uv_transform_init(bContext *C, wmOperator *op)
{
GpUvData *opdata;
- if (is_modal) {
- float zero[2] = {0.0f};
- RNA_float_set_array(op->ptr, "location", zero);
- RNA_float_set(op->ptr, "rotation", 0.0f);
- RNA_float_set(op->ptr, "scale", 1.0f);
- }
op->customdata = opdata = MEM_mallocN(sizeof(GpUvData), __func__);
- opdata->is_modal = is_modal;
opdata->ob = CTX_data_active_object(C);
opdata->gpd = (bGPdata *)opdata->ob->data;
gp_point_conversion_init(C, &opdata->gsc);
@@ -164,20 +157,17 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
opdata->vinit_rotation[0] = 1.0f;
opdata->vinit_rotation[1] = 0.0f;
- if (is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- opdata->draw_handle_pixel = ED_region_draw_cb_activate(
- region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
- }
+ opdata->draw_handle_pixel = ED_region_draw_cb_activate(
+ region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
/* Calc selected strokes center. */
zero_v2(opdata->mcenter);
float center[3] = {0.0f};
int i = 0;
/* Need use evaluated to get the viewport final position. */
- GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
- {
+ GP_EVALUATED_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
float r_center[3];
gpencil_stroke_center(gps, r_center);
@@ -206,7 +196,7 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- /* convert to 2D */
+ /* Convert to 2D. */
gp_point_3d_to_xy(&opdata->gsc, GP_STROKE_3DSPACE, center, opdata->mcenter);
return true;
@@ -215,20 +205,18 @@ static bool gpencil_uv_transform_init(bContext *C, wmOperator *op, const bool is
static void gpencil_uv_transform_exit(bContext *C, wmOperator *op)
{
GpUvData *opdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
opdata = op->customdata;
- if (opdata->is_modal) {
- ARegion *region = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- }
+ ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
WM_cursor_set(CTX_wm_window(C), WM_CURSOR_DEFAULT);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
@@ -254,66 +242,54 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
const int mode = RNA_enum_get(op->ptr, "mode");
GpUvData *opdata = op->customdata;
bGPdata *gpd = opdata->gpd;
+
bool changed = false;
/* Get actual vector. */
float vr[2];
+ float mdiff[2];
+
sub_v2_v2v2(vr, opdata->mouse, opdata->mcenter);
normalize_v2(vr);
- float location[2];
- RNA_float_get_array(op->ptr, "location", location);
-
- float uv_rotation = (opdata->is_modal) ? angle_signed_v2v2(opdata->vinit_rotation, vr) :
- RNA_float_get(op->ptr, "rotation");
- uv_rotation *= SMOOTH_FACTOR;
-
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "rotation", uv_rotation);
- }
+ float uv_rotation = angle_signed_v2v2(opdata->vinit_rotation, vr);
int i = 0;
- /* Apply transformations to all strokes. */
- if ((mode == GP_UV_TRANSLATE) || (!opdata->is_modal)) {
- float mdiff[2];
- mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
- mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
+ /* Translate. */
+ if (mode == GP_UV_TRANSLATE) {
+
+ mdiff[0] = opdata->mouse[0] - opdata->initial_transform[0];
+ /* Y axis is inverted. */
+ mdiff[1] = (opdata->mouse[1] - opdata->initial_transform[1]) * -1.0f;
/* Apply a big amount of smooth always for translate to get smooth result. */
- mul_v2_fl(mdiff, 0.006f);
+ mul_v2_fl(mdiff, 0.002f);
+ RNA_float_set_array(op->ptr, "location", mdiff);
- /* Apply angle in translation. */
- mdiff[0] *= cos(uv_rotation);
- mdiff[1] *= sin(uv_rotation);
- if (opdata->is_modal) {
- RNA_float_set_array(op->ptr, "location", mdiff);
- }
+ GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
+ if (gps->flag & GP_STROKE_SELECT) {
- changed = (bool)((mdiff[0] != 0.0f) || (mdiff[1] != 0.0f));
- if (changed) {
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- if (gps->flag & GP_STROKE_SELECT) {
- if (opdata->is_modal) {
- add_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
- }
- else {
- copy_v2_v2(gps->uv_translation, location);
- }
- /* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
- i++;
- }
+ sub_v2_v2v2(gps->uv_translation, opdata->array_loc[i], mdiff);
+ changed = true;
+
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
+ i++;
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
}
+ GP_EDITABLE_STROKES_END(gpstroke_iter);
}
- if ((mode == GP_UV_ROTATE) || (!opdata->is_modal)) {
- changed = (bool)(uv_rotation != 0.0f);
+ /* Rotate. */
+ if (mode == GP_UV_ROTATE) {
+ changed |= (bool)(uv_rotation != 0.0f);
+ RNA_float_set(op->ptr, "rotation", uv_rotation);
+
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_rotation = (opdata->is_modal) ? opdata->array_rot[i] + uv_rotation : uv_rotation;
+ gps->uv_rotation = opdata->array_rot[i] - uv_rotation;
+
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -323,25 +299,22 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((mode == GP_UV_SCALE) || (!opdata->is_modal)) {
- float mdiff[2];
+ /* Scale. */
+ if (mode == GP_UV_SCALE) {
mdiff[0] = opdata->mcenter[0] - opdata->mouse[0];
mdiff[1] = opdata->mcenter[1] - opdata->mouse[1];
- float scale = (opdata->is_modal) ?
- ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
- opdata->ob_scale :
- RNA_float_get(op->ptr, "scale");
+ float scale = ((len_v2(mdiff) - opdata->initial_length) * opdata->pixel_size) /
+ opdata->ob_scale;
+
scale *= SMOOTH_FACTOR;
+ RNA_float_set(op->ptr, "scale", scale);
- if (opdata->is_modal) {
- RNA_float_set(op->ptr, "scale", scale);
- }
+ changed |= (bool)(scale != 0.0f);
- changed = (bool)(scale != 0.0f);
if (changed) {
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
- gps->uv_scale = (opdata->is_modal) ? opdata->array_scale[i] + scale : scale;
+ gps->uv_scale = opdata->array_scale[i] + scale;
/* Calc geometry data. */
BKE_gpencil_stroke_geometry_update(gps);
i++;
@@ -351,7 +324,7 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
}
}
- if ((!opdata->is_modal) || (changed)) {
+ if (changed) {
/* Update cursor line. */
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, NULL);
@@ -361,23 +334,11 @@ static bool gpencil_uv_transform_calc(bContext *C, wmOperator *op)
return changed;
}
-static int gpencil_transform_fill_exec(bContext *C, wmOperator *op)
-{
- if (!gpencil_uv_transform_init(C, op, false)) {
- return OPERATOR_CANCELLED;
- }
-
- if (!gpencil_uv_transform_calc(C, op)) {
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-
- gpencil_uv_transform_exit(C, op);
- return OPERATOR_FINISHED;
-}
-
static bool gpencil_transform_fill_poll(bContext *C)
{
+ if (!ED_operator_view3d_active(C)) {
+ return false;
+ }
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
return false;
@@ -402,7 +363,7 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
float mlen[2];
float center_3d[3];
- if (!gpencil_uv_transform_init(C, op, true)) {
+ if (!gpencil_uv_transform_init(C, op)) {
return OPERATOR_CANCELLED;
}
@@ -412,16 +373,22 @@ static int gpencil_transform_fill_invoke(bContext *C, wmOperator *op, const wmEv
opdata->mouse[1] = event->mval[1];
copy_v3_v3(center_3d, opdata->ob->loc);
- mlen[0] = opdata->mcenter[0] - event->mval[0];
- mlen[1] = opdata->mcenter[1] - event->mval[1];
+ mlen[0] = event->mval[0] - opdata->mcenter[0];
+ mlen[1] = event->mval[1] - opdata->mcenter[1];
opdata->initial_length = len_v2(mlen);
- opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
+ /* Consider initial offset as zero position. */
+ copy_v2fl_v2i(opdata->initial_transform, event->mval);
+
+ /* Consider initial position as the orientation vector. */
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ if (mode == GP_UV_ROTATE) {
+ opdata->vinit_rotation[0] = mlen[0];
+ opdata->vinit_rotation[1] = mlen[1];
+ normalize_v2(opdata->vinit_rotation);
+ }
- /* Calc init rotation vector. */
- float mouse[2] = {event->mval[0], event->mval[1]};
- sub_v2_v2v2(opdata->vinit_rotation, mouse, opdata->mcenter);
- normalize_v2(opdata->vinit_rotation);
+ opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
gpencil_uv_transform_calc(C, op);
@@ -490,7 +457,6 @@ void GPENCIL_OT_transform_fill(wmOperatorType *ot)
/* api callbacks */
ot->invoke = gpencil_transform_fill_invoke;
ot->modal = gpencil_transform_fill_modal;
- ot->exec = gpencil_transform_fill_exec;
ot->cancel = gpencil_transform_fill_cancel;
ot->poll = gpencil_transform_fill_poll;
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 3039a83009e..4db88bd552f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -844,7 +844,7 @@ void GPENCIL_OT_material_to_vertex_color(wmOperatorType *ot)
ot->prop = RNA_def_boolean(ot->srna,
"remove",
true,
- "Remove Unused Materiales",
+ "Remove Unused Materials",
"Remove any unused material after the conversion");
RNA_def_boolean(ot->srna, "palette", true, "Create Palette", "Create a new palette with colors");
RNA_def_boolean(ot->srna, "selected", false, "Only Selected", "Convert only selected strokes");
diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c
index 0c3b29ab1ea..10867bd1e0d 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_paint.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c
@@ -897,8 +897,7 @@ static void gp_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* To each point individually... */
pt = &gps->points[i];
diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c
index 51d5df1f405..2ebf1aba353 100644
--- a/source/blender/editors/gpencil/gpencil_weight_paint.c
+++ b/source/blender/editors/gpencil/gpencil_weight_paint.c
@@ -449,8 +449,7 @@ static void gp_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso,
* brush region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(
- gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
/* To each point individually... */
pt = &gps->points[i];
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 7f4c3470020..426a470b128 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -74,13 +74,13 @@ typedef struct bAnimContext {
/** editor->mode */
short mode;
- /** sa->spacetype */
+ /** area->spacetype */
short spacetype;
/** active region -> type (channels or main) */
short regiontype;
/** editor host */
- struct ScrArea *sa;
+ struct ScrArea *area;
/** editor data */
struct SpaceLink *sl;
/** region within editor */
@@ -229,6 +229,7 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_DSHAIR,
ANIMTYPE_DSPOINTCLOUD,
ANIMTYPE_DSVOLUME,
+ ANIMTYPE_DSSIMULATION,
ANIMTYPE_SHAPEKEY,
@@ -337,17 +338,17 @@ typedef enum eAnimFilter_Flags {
/* 'Object' channels */
#define SEL_OBJC(base) (CHECK_TYPE_INLINE(base, Base *), ((base->flag & SELECT)))
#define EXPANDED_OBJC(ob) \
- (CHECK_TYPE_INLINE(ob, Object *), ((ob->nlaflag & OB_ADS_COLLAPSED) == 0))
+ (CHECK_TYPE_INLINE(ob, Object *), (((ob)->nlaflag & OB_ADS_COLLAPSED) == 0))
/* 'Sub-object' channels (flags stored in Data block) */
#define FILTER_SKE_OBJD(key) (CHECK_TYPE_INLINE(key, Key *), ((key->flag & KEY_DS_EXPAND)))
#define FILTER_MAT_OBJD(ma) (CHECK_TYPE_INLINE(ma, Material *), ((ma->flag & MA_DS_EXPAND)))
#define FILTER_LAM_OBJD(la) (CHECK_TYPE_INLINE(la, Light *), ((la->flag & LA_DS_EXPAND)))
#define FILTER_CAM_OBJD(ca) (CHECK_TYPE_INLINE(ca, Camera *), ((ca->flag & CAM_DS_EXPAND)))
#define FILTER_CACHEFILE_OBJD(cf) \
- (CHECK_TYPE_INLINE(cf, CacheFile *), ((cf->flag & CACHEFILE_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(cf, CacheFile *), (((cf)->flag & CACHEFILE_DS_EXPAND)))
#define FILTER_CUR_OBJD(cu) (CHECK_TYPE_INLINE(cu, Curve *), ((cu->flag & CU_DS_EXPAND)))
#define FILTER_PART_OBJD(part) \
- (CHECK_TYPE_INLINE(part, ParticleSettings *), ((part->flag & PART_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(part, ParticleSettings *), (((part)->flag & PART_DS_EXPAND)))
#define FILTER_MBALL_OBJD(mb) (CHECK_TYPE_INLINE(mb, MetaBall *), ((mb->flag2 & MB_DS_EXPAND)))
#define FILTER_ARM_OBJD(arm) (CHECK_TYPE_INLINE(arm, bArmature *), ((arm->flag & ARM_DS_EXPAND)))
#define FILTER_MESH_OBJD(me) (CHECK_TYPE_INLINE(me, Mesh *), ((me->flag & ME_DS_EXPAND)))
@@ -356,9 +357,11 @@ typedef enum eAnimFilter_Flags {
#define FILTER_HAIR_OBJD(ha) (CHECK_TYPE_INLINE(ha, Hair *), ((ha->flag & HA_DS_EXPAND)))
#define FILTER_POINTS_OBJD(pt) (CHECK_TYPE_INLINE(pt, PointCloud *), ((pt->flag & PT_DS_EXPAND)))
#define FILTER_VOLUME_OBJD(vo) (CHECK_TYPE_INLINE(vo, Volume *), ((vo->flag & VO_DS_EXPAND)))
+#define FILTER_SIMULATION_OBJD(sim) \
+ (CHECK_TYPE_INLINE(sim, Simulation *), ((sim->flag & SIM_DS_EXPAND)))
/* Variable use expanders */
#define FILTER_NTREE_DATA(ntree) \
- (CHECK_TYPE_INLINE(ntree, bNodeTree *), ((ntree->flag & NTREE_DS_EXPAND)))
+ (CHECK_TYPE_INLINE(ntree, bNodeTree *), (((ntree)->flag & NTREE_DS_EXPAND)))
#define FILTER_TEX_DATA(tex) (CHECK_TYPE_INLINE(tex, Tex *), ((tex->flag & TEX_DS_EXPAND)))
/* 'Sub-object/Action' channels (flags stored in Action) */
@@ -369,11 +372,11 @@ typedef enum eAnimFilter_Flags {
/* Actions (also used for Dopesheet) */
/* Action Channel Group */
-#define EDITABLE_AGRP(agrp) ((agrp->flag & AGRP_PROTECTED) == 0)
+#define EDITABLE_AGRP(agrp) (((agrp)->flag & AGRP_PROTECTED) == 0)
#define EXPANDED_AGRP(ac, agrp) \
- (((!(ac) || ((ac)->spacetype != SPACE_GRAPH)) && (agrp->flag & AGRP_EXPANDED)) || \
- (((ac) && ((ac)->spacetype == SPACE_GRAPH)) && (agrp->flag & AGRP_EXPANDED_G)))
-#define SEL_AGRP(agrp) ((agrp->flag & AGRP_SELECTED) || (agrp->flag & AGRP_ACTIVE))
+ (((!(ac) || ((ac)->spacetype != SPACE_GRAPH)) && ((agrp)->flag & AGRP_EXPANDED)) || \
+ (((ac) && ((ac)->spacetype == SPACE_GRAPH)) && ((agrp)->flag & AGRP_EXPANDED_G)))
+#define SEL_AGRP(agrp) (((agrp)->flag & AGRP_SELECTED) || ((agrp)->flag & AGRP_ACTIVE))
/* F-Curve Channels */
#define EDITABLE_FCU(fcu) ((fcu->flag & FCURVE_PROTECTED) == 0)
#define SEL_FCU(fcu) (fcu->flag & FCURVE_SELECTED)
@@ -433,7 +436,8 @@ typedef enum eAnimFilter_Flags {
#define NLACHANNEL_FIRST_TOP(ac) \
(UI_view2d_scale_get_y(&(ac)->region->v2d) * -UI_TIME_SCRUB_MARGIN_Y - NLACHANNEL_SKIP)
#define NLACHANNEL_HEIGHT(snla) \
- ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit))
+ (((snla) && ((snla)->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : \
+ (1.2f * U.widget_unit))
#define NLACHANNEL_SKIP (0.1f * U.widget_unit)
#define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP)
/* Additional offset to give some room at the end. */
@@ -648,9 +652,6 @@ enum eAnimEditDraw_CurrentFrame {
/* main call to draw current-frame indicator in an Animation Editor */
void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
-/* main call to draw "number box" in scrollbar for current frame indicator */
-void ANIM_draw_cfra_number(const struct bContext *C, struct View2D *v2d, short flag);
-
/* ------------- Preview Range Drawing -------------- */
/* main call to draw preview range curtains */
@@ -840,7 +841,7 @@ void ED_animedit_unlink_action(struct bContext *C,
bool force_delete);
/* Drivers Editor - Utility to set up UI correctly */
-void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
+void ED_drivers_editor_init(struct bContext *C, struct ScrArea *area);
/* ************************************************ */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 40f5cade0d5..ac9eb415b23 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -120,13 +120,11 @@ typedef struct EditBone {
} temp;
} EditBone;
-#define BONESEL_ROOT (1 << 28)
-#define BONESEL_TIP (1 << 29)
-#define BONESEL_BONE (1 << 30)
+#define BONESEL_ROOT (2 << 29u)
+#define BONESEL_TIP (1 << 30u)
+#define BONESEL_BONE (1 << 31u)
#define BONESEL_ANY (BONESEL_TIP | BONESEL_ROOT | BONESEL_BONE)
-#define BONESEL_NOSEL (1u << 31u)
-
/* useful macros */
#define EBONE_VISIBLE(arm, ebone) \
(CHECK_TYPE_INLINE(arm, bArmature *), \
@@ -134,7 +132,7 @@ typedef struct EditBone {
(((arm)->layer & (ebone)->layer) && !((ebone)->flag & BONE_HIDDEN_A)))
#define EBONE_SELECTABLE(arm, ebone) \
- (EBONE_VISIBLE(arm, ebone) && !(ebone->flag & BONE_UNSELECTABLE))
+ (EBONE_VISIBLE(arm, ebone) && !((ebone)->flag & BONE_UNSELECTABLE))
#define EBONE_EDITABLE(ebone) \
(CHECK_TYPE_INLINE(ebone, EditBone *), \
@@ -187,6 +185,10 @@ struct Object *ED_armature_object_and_ebone_from_select_buffer(struct Object **o
uint objects_len,
int hit,
struct EditBone **r_ebone);
+struct Base *ED_armature_base_and_pchan_from_select_buffer(struct Base **bases,
+ uint bases_len,
+ int hit,
+ struct bPoseChannel **r_pchan);
struct Base *ED_armature_base_and_bone_from_select_buffer(struct Base **bases,
uint bases_len,
int hit,
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index b6f9593c261..ad1cde5406d 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -54,9 +54,6 @@ extern char datatoc_alert_icons_png[];
extern int datatoc_splash_png_size;
extern char datatoc_splash_png[];
-extern int datatoc_splash_2x_png_size;
-extern char datatoc_splash_2x_png[];
-
extern int datatoc_bfont_pfb_size;
extern char datatoc_bfont_pfb[];
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 07eade23506..a1a5d65b61d 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -40,9 +40,15 @@ void ED_gizmotypes_facemap_3d(void);
void ED_gizmotypes_preselect_3d(void);
void ED_gizmotypes_primitive_3d(void);
void ED_gizmotypes_blank_3d(void);
+void ED_gizmotypes_snap_3d(void);
-struct Object;
+struct ARegion;
struct bContext;
+struct Depsgraph;
+struct Object;
+struct SnapObjectContext;
+struct wmWindowManager;
+struct View3D;
struct wmGizmo;
/* -------------------------------------------------------------------- */
@@ -223,8 +229,9 @@ enum {
};
/* -------------------------------------------------------------------- */
-/* Gizmo Drawing Functions */
+/* Specific gizmos utils */
+/* dial3d_gizmo.c */
struct Dial3dParams {
int draw_options;
float angle_ofs;
@@ -241,6 +248,33 @@ void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4],
const bool select,
struct Dial3dParams *params);
+/* snap3d_gizmo.c */
+#define USE_SNAP_DETECT_FROM_KEYMAP_HACK
+void ED_gizmotypes_snap_3d_draw_util(struct RegionView3D *rv3d,
+ const float loc_prev[3],
+ const float loc_curr[3],
+ const float normal[3],
+ const uchar color_line[4],
+ const uchar color_point[4],
+ const short snap_elem_type);
+struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *scene,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ struct wmGizmo *gz);
+
+bool ED_gizmotypes_snap_3d_invert_snap_get(struct wmGizmo *gz);
+void ED_gizmotypes_snap_3d_toggle_set(struct wmGizmo *gz, bool enable);
+void ED_gizmotypes_snap_3d_toggle_clear(struct wmGizmo *gz);
+
+short ED_gizmotypes_snap_3d_update(struct wmGizmo *gz,
+ struct Depsgraph *depsgraph,
+ const struct ARegion *region,
+ const struct View3D *v3d,
+ const struct wmWindowManager *wm,
+ const float mval_fl[2],
+ float r_loc[3],
+ float r_nor[3]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 66aa301f08c..58364e69679 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -34,6 +34,7 @@ struct PointerRNA;
struct Brush;
struct GP_SpaceConversion;
+struct GpRandomSettings;
struct bGPDframe;
struct bGPDlayer;
struct bGPDspoint;
@@ -48,6 +49,7 @@ struct RegionView3D;
struct ReportList;
struct Scene;
struct ScrArea;
+struct SnapObjectContext;
struct ToolSettings;
struct View3D;
struct ViewLayer;
@@ -69,14 +71,15 @@ struct wmOperator;
* Used as part of the 'stroke cache' used during drawing of new strokes
*/
typedef struct tGPspoint {
- float x, y; /* x and y coordinates of cursor (in relative to area) */
- float pressure; /* pressure of tablet at this point */
- float strength; /* pressure of tablet at this point for alpha factor */
- float time; /* Time relative to stroke start (used when converting to path) */
- float uv_fac; /* factor of uv along the stroke */
- float uv_rot; /* uv rotation for dor mode */
- float rnd[3]; /* rnd value */
- bool rnd_dirty; /* rnd flag */
+ float x, y; /* x and y coordinates of cursor (in relative to area) */
+ float pressure; /* pressure of tablet at this point */
+ float strength; /* pressure of tablet at this point for alpha factor */
+ float time; /* Time relative to stroke start (used when converting to path) */
+ float uv_fac; /* factor of uv along the stroke */
+ float uv_rot; /* uv rotation for dor mode */
+ float rnd[3]; /* rnd value */
+ bool rnd_dirty; /* rnd flag */
+ float vert_color[4]; /* Point vertex color. */
} tGPspoint;
/* ----------- Grease Pencil Tools/Context ------------- */
@@ -88,20 +91,20 @@ struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
struct bGPdata *ED_gpencil_data_get_active_evaluated(const struct bContext *C);
/* Context independent (i.e. each required part is passed in instead) */
-struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *sa,
+struct bGPdata **ED_gpencil_data_get_pointers_direct(struct ScrArea *area,
struct Object *ob,
struct PointerRNA *r_ptr);
-struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *sa, struct Object *ob);
+struct bGPdata *ED_gpencil_data_get_active_direct(struct ScrArea *area, struct Object *ob);
struct bGPdata *ED_annotation_data_get_active(const struct bContext *C);
struct bGPdata **ED_annotation_data_get_pointers(const struct bContext *C,
struct PointerRNA *r_ptr);
struct bGPdata **ED_annotation_data_get_pointers_direct(struct ID *screen_id,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct Scene *scene,
struct PointerRNA *r_ptr);
struct bGPdata *ED_annotation_data_get_active_direct(struct ID *screen_id,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct Scene *scene);
bool ED_gpencil_data_owner_is_annotation(struct PointerRNA *owner_ptr);
@@ -111,7 +114,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr
/* ----------- Stroke Editing Utilities ---------------- */
-bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *area, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
bool ED_gpencil_stroke_color_use(struct Object *ob,
const struct bGPDlayer *gpl,
@@ -178,7 +181,11 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod
int ED_gpencil_session_active(void);
int ED_undo_gpencil_step(struct bContext *C, int step, const char *name);
-/* ------------ Grease-Pencil Armature weights ------------------ */
+/* ------------ Grease-Pencil Armature ------------------ */
+bool ED_gpencil_add_armature(const struct bContext *C,
+ struct ReportList *reports,
+ struct Object *ob,
+ struct Object *ob_arm);
bool ED_gpencil_add_armature_weights(const struct bContext *C,
struct ReportList *reports,
struct Object *ob,
@@ -233,7 +240,6 @@ void ED_gp_project_point_to_plane(const struct Scene *scene,
struct bGPDspoint *pt);
void ED_gpencil_drawing_reference_get(const struct Scene *scene,
const struct Object *ob,
- struct bGPDlayer *gpl,
char align_flag,
float vec[3]);
void ED_gpencil_project_stroke_to_view(struct bContext *C,
@@ -293,12 +299,18 @@ void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts,
struct bGPDstroke *gps);
void ED_gpencil_point_vertex_color_set(struct ToolSettings *ts,
struct Brush *brush,
- struct bGPDspoint *pt);
+ struct bGPDspoint *pt,
+ struct tGPspoint *tpt);
void ED_gpencil_sbuffer_vertex_color_set(struct Depsgraph *depsgraph,
struct Object *ob,
struct ToolSettings *ts,
struct Brush *brush,
- struct Material *material);
+ struct Material *material,
+ float random_color[3],
+ float pen_pressure);
+void ED_gpencil_init_random_settings(struct Brush *brush,
+ const int mval[2],
+ struct GpRandomSettings *random_settings);
bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc,
struct bGPDstroke *gps,
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 910cf362a37..a8476e3d1ca 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -69,7 +69,7 @@ void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_heigh
void ED_space_image_get_size_fl(struct SpaceImage *sima, float r_size[2]);
void ED_space_image_get_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
void ED_space_image_get_zoom(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
float *r_zoomx,
float *r_zoomy);
void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy);
@@ -88,14 +88,18 @@ void ED_image_get_uv_aspect(struct Image *ima,
float *r_aspx,
float *r_aspy);
void ED_image_mouse_pos(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const int mval[2],
float co[2]);
void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y);
-void ED_image_point_pos(
- struct SpaceImage *sima, struct ARegion *region, float x, float y, float *r_x, float *r_y);
+void ED_image_point_pos(struct SpaceImage *sima,
+ const struct ARegion *region,
+ float x,
+ float y,
+ float *r_x,
+ float *r_y);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
- struct ARegion *region,
+ const struct ARegion *region,
const float co[2],
float r_co[2]);
bool ED_image_slot_cycle(struct Image *image, int direction);
diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h
index 82662a6b118..1146c49bef2 100644
--- a/source/blender/editors/include/ED_info.h
+++ b/source/blender/editors/include/ED_info.h
@@ -31,9 +31,9 @@ struct Main;
/* info_stats.c */
void ED_info_stats_clear(struct ViewLayer *view_layer);
-const char *ED_info_stats_string(struct Main *bmain,
- struct Scene *scene,
- struct ViewLayer *view_layer);
+const char *ED_info_footer_string(struct ViewLayer *view_layer);
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height);
#ifdef __cplusplus
}
diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h
index 3ae0c254000..28bc0b22790 100644
--- a/source/blender/editors/include/ED_keyframes_edit.h
+++ b/source/blender/editors/include/ED_keyframes_edit.h
@@ -24,12 +24,12 @@
#ifndef __ED_KEYFRAMES_EDIT_H__
#define __ED_KEYFRAMES_EDIT_H__
+#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */
-
struct BezTriple;
struct FCurve;
struct Scene;
@@ -106,8 +106,8 @@ typedef enum eEditKeyframes_Mirror {
typedef struct KeyframeEdit_LassoData {
rctf *rectf_scaled;
const rctf *rectf_view;
- const int (*mcords)[2];
- int mcords_tot;
+ const int (*mcoords)[2];
+ int mcoords_len;
} KeyframeEdit_LassoData;
/* use with BEZT_OK_REGION_CIRCLE */
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 6cac3e60531..5635ef2800a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -24,6 +24,9 @@
#ifndef __ED_KEYFRAMING_H__
#define __ED_KEYFRAMING_H__
+#include "DNA_anim_types.h"
+#include "RNA_types.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -50,9 +53,6 @@ struct PropertyRNA;
struct NlaKeyframingContext;
-#include "DNA_anim_types.h"
-#include "RNA_types.h"
-
/* ************ Keyframing Management **************** */
/* Get the active settings for keyframing settings from context (specifically the given scene)
@@ -198,7 +198,7 @@ typedef struct KeyingSetInfo {
cbKeyingSet_Generate generate;
/* RNA integration */
- struct ExtensionRNA ext;
+ struct ExtensionRNA rna_ext;
} KeyingSetInfo;
/* -------- */
@@ -430,14 +430,14 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
/* Auto-Keying macros for use by various tools */
/* check if auto-keyframing is enabled (per scene takes precedence) */
#define IS_AUTOKEY_ON(scene) \
- ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
+ ((scene) ? ((scene)->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
/* check the mode for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_MODE(scene, mode) \
- ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
+ ((scene) ? ((scene)->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : \
(U.autokey_mode == AUTOKEY_MODE_##mode))
/* check if a flag is set for auto-keyframing (per scene takes precedence) */
#define IS_AUTOKEY_FLAG(scene, flag) \
- ((scene) ? ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
+ ((scene) ? (((scene)->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || \
(U.autokey_flag & AUTOKEY_FLAG_##flag)) : \
(U.autokey_flag & AUTOKEY_FLAG_##flag))
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index 7d314c0c462..5aafc0702da 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -43,22 +43,25 @@ void ED_keymap_mask(struct wmKeyConfig *keyconf);
void ED_operatormacros_mask(void);
/* mask_query.c */
-void ED_mask_get_size(struct ScrArea *sa, int *width, int *height);
-void ED_mask_zoom(struct ScrArea *sa, struct ARegion *region, float *zoomx, float *zoomy);
-void ED_mask_get_aspect(struct ScrArea *sa, struct ARegion *region, float *aspx, float *aspy);
+void ED_mask_get_size(struct ScrArea *area, int *width, int *height);
+void ED_mask_zoom(struct ScrArea *area, struct ARegion *region, float *zoomx, float *zoomy);
+void ED_mask_get_aspect(struct ScrArea *area, struct ARegion *region, float *aspx, float *aspy);
-void ED_mask_pixelspace_factor(struct ScrArea *sa,
+void ED_mask_pixelspace_factor(struct ScrArea *area,
struct ARegion *region,
float *scalex,
float *scaley);
-void ED_mask_mouse_pos(struct ScrArea *sa, struct ARegion *region, const int mval[2], float co[2]);
+void ED_mask_mouse_pos(struct ScrArea *area,
+ struct ARegion *region,
+ const int mval[2],
+ float co[2]);
void ED_mask_point_pos(
- struct ScrArea *sa, struct ARegion *region, float x, float y, float *xr, float *yr);
+ struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
void ED_mask_point_pos__reverse(
- struct ScrArea *sa, struct ARegion *region, float x, float y, float *xr, float *yr);
+ struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr);
-void ED_mask_cursor_location_get(struct ScrArea *sa, float cursor[2]);
+void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]);
bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]);
/* mask_draw.c */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index 6d3396bb393..20e54df1ccb 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -139,6 +139,12 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
struct View3D *v3d,
struct Object *obedit);
+void EDBM_project_snap_verts(struct bContext *C,
+ struct Depsgraph *depsgraph,
+ struct ARegion *region,
+ struct Object *obedit,
+ struct BMEditMesh *em);
+
/* editmesh_automerge.c */
void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist);
void EDBM_automerge_and_split(struct Object *ob,
@@ -293,13 +299,6 @@ void ED_operatortypes_mesh(void);
void ED_operatormacros_mesh(void);
void ED_keymap_mesh(struct wmKeyConfig *keyconf);
-/* editmesh_tools.c (could be moved) */
-void EDBM_project_snap_verts(struct bContext *C,
- struct Depsgraph *depsgraph,
- struct ARegion *region,
- struct Object *obedit,
- struct BMEditMesh *em);
-
/* editface.c */
void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag);
bool paintface_mouse_select(struct bContext *C,
@@ -450,9 +449,19 @@ int join_mesh_exec(struct bContext *C, struct wmOperator *op);
int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
/* mirror lookup api */
-int ED_mesh_mirror_spatial_table(
- struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval, const float co[3], char mode);
-int ED_mesh_mirror_topo_table(struct Object *ob, struct Mesh *me_eval, char mode);
+/* Spatial Mirror */
+void ED_mesh_mirror_spatial_table_begin(struct Object *ob,
+ struct BMEditMesh *em,
+ struct Mesh *me_eval);
+void ED_mesh_mirror_spatial_table_end(struct Object *ob);
+int ED_mesh_mirror_spatial_table_lookup(struct Object *ob,
+ struct BMEditMesh *em,
+ struct Mesh *me_eval,
+ const float co[3]);
+
+/* Topology Mirror */
+void ED_mesh_mirror_topo_table_begin(struct Object *ob, struct Mesh *me_eval);
+void ED_mesh_mirror_topo_table_end(struct Object *ob);
/* retrieves mirrored cache vert, or NULL if there isn't one.
* note: calling this without ensuring the mirror cache state
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ae2b4989069..3471f9dcce9 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -37,6 +37,7 @@ struct Tex;
struct View2D;
struct bContext;
struct bNode;
+struct bNodeSocket;
struct bNodeSocketType;
struct bNodeTree;
struct bNodeTree;
@@ -79,6 +80,10 @@ void ED_node_draw_snap(
struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos);
/* node_draw.c */
+void ED_node_socket_draw(struct bNodeSocket *sock,
+ const struct rcti *rect,
+ const float color[4],
+ float scale);
void ED_node_tree_update(const struct bContext *C);
void ED_node_tag_update_id(struct ID *id);
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
@@ -86,14 +91,15 @@ void ED_node_sort(struct bNodeTree *ntree);
float ED_node_grid_size(void);
/* node_relationships.c */
-void ED_node_link_intersect_test(struct ScrArea *sa, int test);
-void ED_node_link_insert(struct Main *bmain, struct ScrArea *sa);
+void ED_node_link_intersect_test(struct ScrArea *area, int test);
+void ED_node_link_insert(struct Main *bmain, struct ScrArea *area);
/* node_edit.c */
void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typeinfo);
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
+bool ED_node_is_simulation(struct SpaceNode *snode);
void ED_node_shader_default(const struct bContext *C, struct ID *id);
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
@@ -101,7 +107,10 @@ void ED_node_texture_default(const struct bContext *C, struct Tex *tex);
bool ED_node_select_check(ListBase *lb);
void ED_node_select_all(ListBase *lb, int action);
void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree);
-void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node);
+void ED_node_set_active(struct Main *bmain,
+ struct bNodeTree *ntree,
+ struct bNode *node,
+ bool *r_active_texture_changed);
void ED_node_composite_job(const struct bContext *C,
struct bNodeTree *nodetree,
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 3b38969d6bf..e027efce1d3 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -24,6 +24,9 @@
#ifndef __ED_OBJECT_H__
#define __ED_OBJECT_H__
+#include "BLI_compiler_attrs.h"
+#include "DNA_object_enums.h"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -54,9 +57,6 @@ struct wmOperator;
struct wmOperatorType;
struct wmWindowManager;
-#include "BLI_compiler_attrs.h"
-#include "DNA_object_enums.h"
-
/* object_edit.c */
/* context.object */
struct Object *ED_object_context(struct bContext *C);
@@ -212,13 +212,11 @@ bool ED_object_editmode_load(struct Main *bmain, struct Object *obedit);
void ED_object_vpaintmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
- struct wmWindowManager *wm,
struct Scene *scene,
struct Object *ob);
void ED_object_vpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_wpaintmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
- struct wmWindowManager *wm,
struct Scene *scene,
struct Object *ob);
void ED_object_wpaintmode_enter(struct bContext *C, struct Depsgraph *depsgraph);
@@ -228,6 +226,20 @@ void ED_object_vpaintmode_exit(struct bContext *C);
void ED_object_wpaintmode_exit_ex(struct Object *ob);
void ED_object_wpaintmode_exit(struct bContext *C);
+void ED_object_texture_paint_mode_enter_ex(struct Main *bmain, struct Scene *scene, Object *ob);
+void ED_object_texture_paint_mode_enter(struct bContext *C);
+
+void ED_object_texture_paint_mode_exit_ex(struct Main *bmain, struct Scene *scene, Object *ob);
+void ED_object_texture_paint_mode_exit(struct bContext *C);
+
+void ED_object_particle_edit_mode_enter_ex(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *ob);
+void ED_object_particle_edit_mode_enter(struct bContext *C);
+
+void ED_object_particle_edit_mode_exit_ex(struct Scene *scene, Object *ob);
+void ED_object_particle_edit_mode_exit(struct bContext *C);
+
void ED_object_sculptmode_enter_ex(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
@@ -246,7 +258,7 @@ void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis);
void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
-void ED_object_base_init_transform_on_add(struct Object *obejct,
+void ED_object_base_init_transform_on_add(struct Object *object,
const float loc[3],
const float rot[3]);
float ED_object_new_primitive_matrix(struct bContext *C,
@@ -260,6 +272,7 @@ float ED_object_new_primitive_matrix(struct bContext *C,
#define OBJECT_ADD_SIZE_MAXF 1.0e12f
void ED_object_add_unit_props_size(struct wmOperatorType *ot);
+void ED_object_add_unit_props_radius_ex(struct wmOperatorType *ot, float default_value);
void ED_object_add_unit_props_radius(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
void ED_object_add_mesh_props(struct wmOperatorType *ot);
@@ -268,6 +281,7 @@ bool ED_object_add_generic_get_opts(struct bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
unsigned short *local_view_bits,
bool *is_view_aligned);
@@ -302,15 +316,15 @@ void ED_objects_recalculate_paths(struct bContext *C,
eObjectPathCalcRange range);
/* constraints */
-struct ListBase *get_active_constraints(struct Object *ob);
-struct ListBase *get_constraint_lb(struct Object *ob,
- struct bConstraint *con,
- struct bPoseChannel **r_pchan);
-struct bConstraint *get_active_constraint(struct Object *ob);
+struct ListBase *ED_object_constraint_list_from_context(struct Object *ob);
+struct ListBase *ED_object_constraint_list_from_constraint(struct Object *ob,
+ struct bConstraint *con,
+ struct bPoseChannel **r_pchan);
+struct bConstraint *ED_object_constraint_active_get(struct Object *ob);
void object_test_constraints(struct Main *bmain, struct Object *ob);
-void ED_object_constraint_set_active(struct Object *ob, struct bConstraint *con);
+void ED_object_constraint_active_set(struct Object *ob, struct bConstraint *con);
void ED_object_constraint_update(struct Main *bmain, struct Object *ob);
void ED_object_constraint_dependency_update(struct Main *bmain, struct Object *ob);
@@ -327,11 +341,12 @@ bool ED_object_mode_compat_set(struct bContext *C,
struct Object *ob,
eObjectMode mode,
struct ReportList *reports);
-void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
-void ED_object_mode_set(struct bContext *C, eObjectMode mode);
-void ED_object_mode_exit(struct bContext *C, struct Depsgraph *depsgraph);
+bool ED_object_mode_set_ex(struct bContext *C,
+ eObjectMode mode,
+ bool use_undo,
+ struct ReportList *reports);
+bool ED_object_mode_set(struct bContext *C, eObjectMode mode);
-bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode);
void ED_object_mode_generic_exit(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h
index be1ee786a75..0325ad9fdba 100644
--- a/source/blender/editors/include/ED_outliner.h
+++ b/source/blender/editors/include/ED_outliner.h
@@ -27,14 +27,16 @@
extern "C" {
#endif
+struct Base;
struct ListBase;
+struct SpaceOutliner;
struct bContext;
bool ED_outliner_collections_editor_poll(struct bContext *C);
void ED_outliner_selected_objects_get(const struct bContext *C, struct ListBase *objects);
-Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
+struct Base *ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_outliner_select_sync_from_object_tag(struct bContext *C);
void ED_outliner_select_sync_from_edit_bone_tag(struct bContext *C);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index c8a4dc5b49d..789db5ae56e 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -71,8 +71,8 @@ bool PE_mouse_particles(
bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op);
bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad);
int PE_lasso_select(struct bContext *C,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const int sel_op);
bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit);
bool PE_deselect_all_visible(struct bContext *C);
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 0645b256a15..f03739c74c4 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -48,8 +48,8 @@ void ED_operatortypes_render(void);
/* render_update.c */
void ED_render_engine_changed(struct Main *bmain);
-void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa);
-void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *sc);
+void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area);
+void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen);
/* Callbacks handling data update events coming from depsgraph. */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 0785b0e97f7..bc6a4b23609 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -63,14 +63,14 @@ struct wmWindowManager;
/* regions */
void ED_region_do_listen(struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmNotifier *note,
const Scene *scene);
void ED_region_do_layout(struct bContext *C, struct ARegion *region);
void ED_region_do_draw(struct bContext *C, struct ARegion *region);
void ED_region_exit(struct bContext *C, struct ARegion *region);
-void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *region);
+void ED_region_remove(struct bContext *C, struct ScrArea *area, struct ARegion *region);
void ED_region_pixelspace(struct ARegion *region);
void ED_region_update_rect(struct ARegion *region);
void ED_region_floating_initialize(struct ARegion *region);
@@ -104,14 +104,14 @@ void ED_region_header(const struct bContext *C, struct ARegion *region);
void ED_region_header_layout(const struct bContext *C, struct ARegion *region);
void ED_region_header_draw(const struct bContext *C, struct ARegion *region);
-void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *sa, struct ARegion *region);
+void ED_region_cursor_set(struct wmWindow *win, struct ScrArea *area, struct ARegion *region);
void ED_region_toggle_hidden(struct bContext *C, struct ARegion *region);
void ED_region_visibility_change_update(struct bContext *C,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region);
/* screen_ops.c */
void ED_region_visibility_change_update_animated(struct bContext *C,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region);
void ED_region_info_draw(struct ARegion *region,
@@ -146,14 +146,14 @@ void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
void ED_area_do_mgs_subscribe_for_tool_ui(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -162,7 +162,7 @@ void ED_region_message_subscribe(struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
@@ -171,21 +171,21 @@ void ED_spacetypes_keymap(struct wmKeyConfig *keyconf);
int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco);
/* areas */
-void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
-void ED_area_exit(struct bContext *C, struct ScrArea *sa);
+void ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *area);
+void ED_area_exit(struct bContext *C, struct ScrArea *area);
int ED_screen_area_active(const struct bContext *C);
void ED_screen_global_areas_refresh(struct wmWindow *win);
void ED_screen_global_areas_sync(struct wmWindow *win);
-void ED_area_do_listen(struct wmWindow *win, ScrArea *sa, struct wmNotifier *note, Scene *scene);
-void ED_area_tag_redraw(ScrArea *sa);
-void ED_area_tag_redraw_no_rebuild(ScrArea *sa);
-void ED_area_tag_redraw_regiontype(ScrArea *sa, int type);
-void ED_area_tag_refresh(ScrArea *sa);
-void ED_area_do_refresh(struct bContext *C, ScrArea *sa);
-struct AZone *ED_area_azones_update(ScrArea *sa, const int mouse_xy[]);
-void ED_area_status_text(ScrArea *sa, const char *str);
-void ED_area_newspace(struct bContext *C, ScrArea *sa, int type, const bool skip_ar_exit);
-void ED_area_prevspace(struct bContext *C, ScrArea *sa);
+void ED_area_do_listen(struct wmWindow *win, ScrArea *area, struct wmNotifier *note, Scene *scene);
+void ED_area_tag_redraw(ScrArea *area);
+void ED_area_tag_redraw_no_rebuild(ScrArea *area);
+void ED_area_tag_redraw_regiontype(ScrArea *area, int type);
+void ED_area_tag_refresh(ScrArea *area);
+void ED_area_do_refresh(struct bContext *C, ScrArea *area);
+struct AZone *ED_area_azones_update(ScrArea *area, const int mouse_xy[]);
+void ED_area_status_text(ScrArea *area, const char *str);
+void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit);
+void ED_area_prevspace(struct bContext *C, ScrArea *area);
void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
int ED_area_headersize(void);
int ED_area_header_alignment_or_fallback(const ScrArea *area, int fallback);
@@ -215,7 +215,7 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
#define ED_screen_verts_iter(win, screen, vert_name) \
for (ScrVert *vert_name = (win)->global_areas.vertbase.first ? \
(win)->global_areas.vertbase.first : \
- screen->vertbase.first; \
+ (screen)->vertbase.first; \
vert_name != NULL; \
vert_name = (vert_name == (win)->global_areas.vertbase.last) ? (screen)->vertbase.first : \
vert_name->next)
@@ -224,25 +224,25 @@ ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area);
void ED_screens_initialize(struct Main *bmain, struct wmWindowManager *wm);
void ED_screen_draw_edges(struct wmWindow *win);
void ED_screen_draw_join_shape(struct ScrArea *sa1, struct ScrArea *sa2);
-void ED_screen_draw_split_preview(struct ScrArea *sa, const int dir, const float fac);
+void ED_screen_draw_split_preview(struct ScrArea *area, const int dir, const float fac);
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);
-bool ED_screen_change(struct bContext *C, struct bScreen *sc);
+bool ED_screen_change(struct bContext *C, struct bScreen *screen);
void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene);
void ED_screen_set_active_region(struct bContext *C, struct wmWindow *win, const int xy[2]);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws);
-void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
-ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
-void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
-void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
+void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area);
+ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type);
+void ED_screen_full_prevspace(struct bContext *C, ScrArea *area);
+void ED_screen_full_restore(struct bContext *C, ScrArea *area);
struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
const short state);
ScrArea *ED_screen_temp_space_open(struct bContext *C,
const char *title,
@@ -347,6 +347,7 @@ bool ED_operator_info_active(struct bContext *C);
bool ED_operator_console_active(struct bContext *C);
bool ED_operator_object_active(struct bContext *C);
+bool ED_operator_object_active_editable_ex(struct bContext *C, const Object *ob);
bool ED_operator_object_active_editable(struct bContext *C);
bool ED_operator_object_active_editable_mesh(struct bContext *C);
bool ED_operator_object_active_editable_font(struct bContext *C);
@@ -422,7 +423,7 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus);
int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis);
@@ -442,15 +443,15 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
const int event_xy[2],
const int margin);
-bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar_gutter);
+bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter);
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
/* interface_region_hud.c */
struct ARegionType *ED_area_type_hud(int space_type);
-void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *sa_keep);
-void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *sa);
+void ED_area_type_hud_clear(struct wmWindowManager *wm, ScrArea *area_keep);
+void ED_area_type_hud_ensure(struct bContext *C, struct ScrArea *area);
/* default keymaps, bitflags (matches order of evaluation). */
enum {
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index 06c2c3039f5..51f3eea74fa 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -34,11 +34,11 @@ extern "C" {
typedef struct ScreenAnimData {
ARegion *region; /* do not read from this, only for comparing if region exists */
short redraws;
- short flag; /* flags for playback */
- int sfra; /* frame that playback was started from */
- int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
- double last_duration; /* used for frame dropping */
- bool from_anim_edit; /* playback was invoked from animation editor */
+ short flag; /* flags for playback */
+ int sfra; /* frame that playback was started from */
+ int nextfra; /* next frame to go to (when ANIMPLAY_FLAG_USE_NEXT_FRAME is set) */
+ double lagging_frame_count; /* used for frame dropping */
+ bool from_anim_edit; /* playback was invoked from animation editor */
} ScreenAnimData;
/* for animplayer */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 26871cf8dd0..e61c7be5216 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -54,6 +54,11 @@ void ED_sculpt_undosys_type(struct UndoType *ut);
void ED_sculpt_undo_geometry_begin(struct Object *ob, const char *name);
void ED_sculpt_undo_geometry_end(struct Object *ob);
+/* Undo for changes happening on a base mesh for multires sculpting.
+ * if there is no multires sculpt active regular undo is used. */
+void ED_sculpt_undo_push_multires_mesh_begin(struct bContext *C, const char *str);
+void ED_sculpt_undo_push_multires_mesh_end(struct bContext *C, const char *str);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 2a5803cbc4d..a62deb9d69f 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -123,7 +123,7 @@ struct bContext;
void BIF_clearTransformOrientation(struct bContext *C);
void BIF_removeTransformOrientation(struct bContext *C, struct TransformOrientation *ts);
void BIF_removeTransformOrientationIndex(struct bContext *C, int index);
-void BIF_createTransformOrientation(struct bContext *C,
+bool BIF_createTransformOrientation(struct bContext *C,
struct ReportList *reports,
const char *name,
const bool use_view,
@@ -157,9 +157,24 @@ int BIF_countTransformOrientation(const struct bContext *C);
#define P_GPENCIL_EDIT (1 << 13)
#define P_CURSOR_EDIT (1 << 14)
#define P_CLNOR_INVALIDATE (1 << 15)
+/* For properties performed when confirming the transformation. */
+#define P_POST_TRANSFORM (1 << 19)
void Transform_Properties(struct wmOperatorType *ot, int flags);
+/* *** transform_orientations.c *** */
+void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
+short ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
+ float r_mat[3][3],
+ /* extra args */
+ struct Scene *scene,
+ struct RegionView3D *rv3d,
+ struct Object *ob,
+ struct Object *obedit,
+ const short orientation_type,
+ int orientation_index_custom,
+ const int pivot_point);
+
/* transform gizmos */
void VIEW3D_GGT_xform_gizmo(struct wmGizmoGroupType *gzgt);
@@ -178,18 +193,6 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt);
#define SNAP_INCREMENTAL_ANGLE DEG2RAD(5.0)
-void ED_transform_calc_orientation_from_type(const struct bContext *C, float r_mat[3][3]);
-void ED_transform_calc_orientation_from_type_ex(const struct bContext *C,
- float r_mat[3][3],
- /* extra args */
- struct Scene *scene,
- struct RegionView3D *rv3d,
- struct Object *ob,
- struct Object *obedit,
- const short orientation_type,
- int orientation_index_custom,
- const int pivot_point);
-
struct TransformBounds {
float center[3]; /* Center for transform widget. */
float min[3], max[3]; /* Boundbox of selection for transform widget. */
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 b998ac87819..8feb73436a6 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -77,11 +77,8 @@ struct SnapObjectParams {
};
typedef struct SnapObjectContext SnapObjectContext;
-SnapObjectContext *ED_transform_snap_object_context_create(struct Main *bmain,
- struct Scene *scene,
- int flag);
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Main *bmain,
- struct Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create(struct Scene *scene, int flag);
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(struct Scene *scene,
int flag,
/* extra args for view3d */
const struct ARegion *region,
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 8b4829446c3..1f2706957a7 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -48,7 +48,7 @@ bool ED_editors_flush_edits_for_object(struct Main *bmain, struct Object *ob);
bool ED_editors_flush_edits_ex(struct Main *bmain, bool for_render, bool check_needs_flush);
bool ED_editors_flush_edits(struct Main *bmain);
-void ED_spacedata_id_remap(struct ScrArea *sa,
+void ED_spacedata_id_remap(struct ScrArea *area,
struct SpaceLink *sl,
struct ID *old_id,
struct ID *new_id);
diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h
new file mode 100644
index 00000000000..76171383b49
--- /dev/null
+++ b/source/blender/editors/include/ED_util_imbuf.h
@@ -0,0 +1,52 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup editors
+ */
+
+#ifndef __ED_UTIL_IMBUF_H__
+#define __ED_UTIL_IMBUF_H__
+
+#include "BLI_compiler_attrs.h"
+#include "BLI_sys_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ARegion;
+struct Main;
+struct bContext;
+struct wmEvent;
+struct wmOperator;
+
+/* ed_util_imbuf.c */
+void ED_imbuf_sample_draw(const struct bContext *C, struct ARegion *region, void *arg_info);
+void ED_imbuf_sample_exit(struct bContext *C, struct wmOperator *op);
+int ED_imbuf_sample_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+int ED_imbuf_sample_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
+void ED_imbuf_sample_cancel(struct bContext *C, struct wmOperator *op);
+bool ED_imbuf_sample_poll(struct bContext *C);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ED_UTIL_IMBUF_H__ */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 8c565536c71..f656aaf9c07 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -50,20 +50,17 @@ void ED_operatortypes_uvedit(void);
void ED_keymap_uvedit(struct wmKeyConfig *keyconf);
bool ED_uvedit_minmax(const struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
float min[2],
float max[2]);
void ED_uvedit_select_all(struct BMesh *bm);
bool ED_uvedit_minmax_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_min[2],
float r_max[2]);
bool ED_uvedit_center_multi(const struct Scene *scene,
- Image *ima,
struct Object **objects_edit,
uint objects_len,
float r_cent[2],
@@ -95,11 +92,7 @@ void ED_object_assign_active_image(struct Main *bmain,
bool ED_uvedit_test(struct Object *obedit);
/* visibility and selection */
-bool uvedit_face_visible_nolocal_ex(const struct ToolSettings *ts, struct BMFace *efa);
-bool uvedit_face_visible_test_ex(const struct ToolSettings *ts,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa);
bool uvedit_face_select_test_ex(const struct ToolSettings *ts,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -110,11 +103,7 @@ bool uvedit_uv_select_test_ex(const struct ToolSettings *ts,
struct BMLoop *l,
const int cd_loop_uv_offset);
-bool uvedit_face_visible_nolocal(const struct Scene *scene, struct BMFace *efa);
-bool uvedit_face_visible_test(const struct Scene *scene,
- struct Object *obedit,
- struct Image *ima,
- struct BMFace *efa);
+bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa);
bool uvedit_face_select_test(const struct Scene *scene,
struct BMFace *efa,
const int cd_loop_uv_offset);
@@ -175,12 +164,10 @@ void uvedit_uv_select_disable(struct BMEditMesh *em,
bool ED_uvedit_nearest_uv(const struct Scene *scene,
struct Object *obedit,
- struct Image *ima,
const float co[2],
float *dist_sq,
float r_uv[2]);
bool ED_uvedit_nearest_uv_multi(const struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index bb065ee0008..beca517f0a6 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -129,6 +129,9 @@ enum eV3DCursorOrient {
void ED_view3d_background_color_get(const struct Scene *scene,
const struct View3D *v3d,
float r_color[3]);
+bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene,
+ const struct Object *ob,
+ const struct View3D *v3d);
void ED_view3d_cursor3d_position(struct bContext *C,
const int mval[2],
const bool use_depth,
@@ -246,6 +249,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc,
struct BPoint *bp,
struct BezTriple *bezt,
int beztindex,
+ bool handle_visible,
const float screen_co[2]),
void *userData,
const eV3DProjTest clip_flag);
@@ -560,10 +564,10 @@ bool edge_inside_circle(const float cent[2],
struct RegionView3D *ED_view3d_context_rv3d(struct bContext *C);
bool ED_view3d_context_user_region(struct bContext *C,
struct View3D **r_v3d,
- struct ARegion **r_ar);
-bool ED_view3d_area_user_region(const struct ScrArea *sa,
+ struct ARegion **r_region);
+bool ED_view3d_area_user_region(const struct ScrArea *area,
const struct View3D *v3d,
- struct ARegion **r_ar);
+ struct ARegion **r_region);
bool ED_operator_rv3d_user_region_poll(struct bContext *C);
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d);
@@ -600,7 +604,7 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
-void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *region, bool do_clip);
+void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
const struct Scene *scene,
struct View3D *v3d,
@@ -702,7 +706,7 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op,
/* render */
void ED_view3d_stop_render_preview(struct wmWindowManager *wm, struct ARegion *region);
-void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
+void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *area);
#define XRAY_ALPHA(v3d) \
(((v3d)->shading.type == OB_WIRE) ? (v3d)->shading.xray_alpha_wire : (v3d)->shading.xray_alpha)
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 6fdef4a06e0..452a1fca111 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -428,7 +428,7 @@ DEF_ICON(FORCE_CURVE)
DEF_ICON(FORCE_BOID)
DEF_ICON(FORCE_TURBULENCE)
DEF_ICON(FORCE_DRAG)
-DEF_ICON(FORCE_SMOKEFLOW)
+DEF_ICON(FORCE_FLUIDFLOW)
DEF_ICON_BLANK(673)
DEF_ICON_BLANK(674)
DEF_ICON(RIGID_BODY)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index e9027fe571f..7632d14bfb6 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -49,6 +49,7 @@ struct PanelType;
struct PointerRNA;
struct PropertyRNA;
struct ReportList;
+struct ResultBLF;
struct ScrArea;
struct bContext;
struct bContextStore;
@@ -239,6 +240,8 @@ enum {
#define UI_PANEL_CATEGORY_MARGIN_WIDTH (U.widget_unit * 1.0f)
+#define UI_PANEL_BOX_STYLE_MARGIN (U.widget_unit * 0.2f)
+
/* but->drawflag - these flags should only affect how the button is drawn. */
/* Note: currently, these flags _are not passed_ to the widget's state() or draw() functions
* (except for the 'align' ones)!
@@ -250,6 +253,8 @@ enum {
UI_BUT_TEXT_RIGHT = 1 << 3,
/** Prevent the button to show any tooltip. */
UI_BUT_NO_TOOLTIP = 1 << 4,
+ /** Do not add the usual horizontal padding for text drawing. */
+ UI_BUT_NO_TEXT_PADDING = 1 << 5,
/* Button align flag, for drawing groups together.
* Used in 'uiBlock.flag', take care! */
@@ -500,15 +505,24 @@ typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origs
typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
-typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C,
- struct ARegion *butregion,
- uiBut *but);
-typedef void (*uiButSearchFunc)(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items);
-typedef void (*uiButSearchArgFreeFunc)(void *arg);
+/* Search types. */
+typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items);
+typedef void (*uiButSearchArgFreeFn)(void *arg);
+typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
+ void *arg,
+ void *active,
+ const struct wmEvent *event);
+typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C,
+ struct ARegion *region,
+ void *arg,
+ void *active);
/* Must return allocated string. */
typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
@@ -619,8 +633,7 @@ void UI_popup_block_invoke_ex(struct bContext *C,
uiBlockCreateFunc func,
void *arg,
void (*arg_free)(void *arg),
- const char *opname,
- int opcontext);
+ bool can_refresh);
void UI_popup_block_ex(struct bContext *C,
uiBlockCreateFunc func,
uiBlockHandleFunc popup_func,
@@ -1567,20 +1580,25 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
/* use inside searchfunc to add items */
bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state);
-/* bfunc gets search item *poin as arg2, or if NULL the old string */
void UI_but_func_search_set(uiBut *but,
- uiButSearchCreateFunc cfunc,
- uiButSearchFunc sfunc,
+ uiButSearchCreateFn search_create_fn,
+ uiButSearchUpdateFn search_update_fn,
void *arg,
- uiButSearchArgFreeFunc search_arg_free_func,
- uiButHandleFunc bfunc,
+ uiButSearchArgFreeFn search_arg_free_fn,
+ uiButHandleFunc search_exec_fn,
void *active);
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
+void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
+void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
+
/* height in pixels, it's using hardcoded values still */
int UI_searchbox_size_y(void);
int UI_searchbox_size_x(void);
/* check if a string is in an existing search box */
int UI_search_items_find_index(uiSearchItems *items, const char *name);
+void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
+
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
@@ -1648,22 +1666,24 @@ void UI_panels_end(const struct bContext *C, struct ARegion *region, int *r_x, i
void UI_panels_draw(const struct bContext *C, struct ARegion *region);
struct Panel *UI_panel_find_by_type(struct ListBase *lb, struct PanelType *pt);
-struct Panel *UI_panel_begin(struct ScrArea *sa,
+struct Panel *UI_panel_begin(struct ScrArea *area,
struct ARegion *region,
struct ListBase *lb,
uiBlock *block,
struct PanelType *pt,
- struct Panel *pa,
+ struct Panel *panel,
bool *r_open);
-void UI_panel_end(const struct ScrArea *sa,
+void UI_panel_end(const struct ScrArea *area,
const struct ARegion *region,
uiBlock *block,
int width,
int height,
bool open);
+
void UI_panels_scale(struct ARegion *region, float new_width);
void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
-int UI_panel_size_y(const struct Panel *pa);
+int UI_panel_size_y(const struct Panel *panel);
+bool UI_panel_is_dragging(const struct Panel *panel);
bool UI_panel_category_is_visible(const struct ARegion *region);
void UI_panel_category_add(struct ARegion *region, const char *name);
@@ -1683,6 +1703,24 @@ void UI_panel_category_draw_all(struct ARegion *region, const char *category_id_
struct PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname);
+/* Polyinstantiated panels for representing a list of data. */
+struct Panel *UI_panel_add_instanced(struct ScrArea *area,
+ struct ARegion *region,
+ struct ListBase *panels,
+ char *panel_idname,
+ int list_index);
+void UI_panels_free_instanced(struct bContext *C, struct ARegion *region);
+
+#define LIST_PANEL_UNIQUE_STR_LEN 4
+void UI_list_panel_unique_str(struct Panel *panel, char *r_name);
+
+void UI_panel_set_expand_from_list_data(const struct bContext *C, struct Panel *panel);
+
+typedef void (*uiListPanelIDFromDataFunc)(void *data_link, char *r_idname);
+bool UI_panel_list_matches_data(struct ARegion *region,
+ struct ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func);
+
/* Handlers
*
* Handlers that can be registered in regions, areas and windows for
@@ -1768,6 +1806,10 @@ enum {
UI_ITEM_O_DEPRESS = 1 << 10,
UI_ITEM_R_COMPACT = 1 << 11,
UI_ITEM_R_CHECKBOX_INVERT = 1 << 12,
+ /** Don't add a real decorator item, just blank space. */
+ UI_ITEM_R_FORCE_BLANK_DECORATE = 1 << 13,
+ /* Even create the property split layout if there's no name to show there. */
+ UI_ITEM_R_SPLIT_EMPTY_NAME = 1 << 14,
};
#define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
@@ -1778,6 +1820,9 @@ enum {
UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = 1 << 1,
UI_TEMPLATE_OP_PROPS_COMPACT = 1 << 2,
UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = 1 << 3,
+ /* Disable property split for the default layout (custom ui callbacks still have full control
+ * over the layout and can enable it). */
+ UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT = 1 << 4,
};
/* used for transp checkers */
@@ -1865,7 +1910,9 @@ bool uiLayoutGetPropDecorate(uiLayout *layout);
/* layout specifiers */
uiLayout *uiLayoutRow(uiLayout *layout, bool align);
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
uiLayout *uiLayoutGridFlow(uiLayout *layout,
bool row_major,
@@ -1889,7 +1936,7 @@ uiLayout *uiLayoutRadial(uiLayout *layout);
/* templates */
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
void uiTemplateID(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
const char *propname,
const char *newop,
@@ -2040,11 +2087,11 @@ void uiTemplateOperatorSearch(uiLayout *layout);
void UI_but_func_menu_search(uiBut *but);
void uiTemplateMenuSearch(uiLayout *layout);
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const struct bContext *C,
- uiLayout *layout,
- struct wmOperator *op,
- const eButLabelAlign label_align,
- const short flag);
+void uiTemplateOperatorPropertyButs(const struct bContext *C,
+ uiLayout *layout,
+ struct wmOperator *op,
+ eButLabelAlign label_align,
+ short flag);
void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
@@ -2062,7 +2109,7 @@ void uiTemplateComponentMenu(uiLayout *layout,
const char *name);
void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float *color);
void uiTemplateCacheFile(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
const char *propname);
@@ -2084,6 +2131,7 @@ void uiTemplateList(uiLayout *layout,
bool sort_reverse,
bool sort_lock);
void uiTemplateNodeLink(uiLayout *layout,
+ struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
struct bNodeSocket *input);
@@ -2094,7 +2142,7 @@ void uiTemplateNodeView(uiLayout *layout,
struct bNodeSocket *input);
void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
void uiTemplateTextureShow(uiLayout *layout,
- struct bContext *C,
+ const struct bContext *C,
struct PointerRNA *ptr,
struct PropertyRNA *prop);
@@ -2293,6 +2341,14 @@ void uiItemsFullEnumO_items(uiLayout *layout,
const EnumPropertyItem *item_array,
int totitem);
+typedef struct uiPropertySplitWrapper {
+ uiLayout *label_column;
+ uiLayout *property_row;
+ uiLayout *decorate_column;
+} uiPropertySplitWrapper;
+
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
+
void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
void uiItemL_ex(
uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
@@ -2304,6 +2360,9 @@ void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int ic
void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
/* menu contents */
void uiItemMContents(uiLayout *layout, const char *menuname);
+/* Decorators */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index);
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index);
/* value */
void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
/* separator */
@@ -2378,11 +2437,14 @@ bool UI_context_copy_to_selected_list(struct bContext *C,
/* Helpers for Operators */
uiBut *UI_context_active_but_get(const struct bContext *C);
+uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
uiBut *UI_context_active_but_prop_get(const struct bContext *C,
struct PointerRNA *r_ptr,
struct PropertyRNA **r_prop,
int *r_index);
void UI_context_active_but_prop_handle(struct bContext *C);
+void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
+
struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
void UI_context_update_anim_flag(const struct bContext *C);
void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
@@ -2420,8 +2482,9 @@ void UI_fontstyle_draw_ex(const struct uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
size_t len,
- float *r_xofs,
- float *r_yofs);
+ int *r_xofs,
+ int *r_yofs,
+ struct ResultBLF *r_info);
void UI_fontstyle_draw(const struct uiFontStyle *fs,
const struct rcti *rect,
const char *str,
@@ -2475,7 +2538,7 @@ struct ARegion *UI_tooltip_create_from_button(struct bContext *C,
uiBut *but,
bool is_label);
struct ARegion *UI_tooltip_create_from_gizmo(struct bContext *C, struct wmGizmo *gz);
-void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *region);
+void UI_tooltip_free(struct bContext *C, struct bScreen *screen, struct ARegion *region);
/* How long before a tool-tip shows. */
#define UI_TOOLTIP_DELAY 0.5
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index b0995250979..c5c4ca79f14 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -26,10 +26,6 @@
#include "BLI_sys_types.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Define icon enum. */
#define DEF_ICON(name) ICON_##name,
#define DEF_ICON_VECTOR(name) ICON_##name,
@@ -47,6 +43,10 @@ typedef enum {
/* use to denote intentionally unset theme color */
#define TH_UNDEFINED -1
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef enum ThemeColorID {
TH_REDALERT,
diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h
index ff9719d4674..ffc06e94a90 100644
--- a/source/blender/editors/include/UI_view2d.h
+++ b/source/blender/editors/include/UI_view2d.h
@@ -119,7 +119,7 @@ void UI_view2d_region_reinit(struct View2D *v2d, short type, int winx, int winy)
void UI_view2d_curRect_validate(struct View2D *v2d);
void UI_view2d_curRect_reset(struct View2D *v2d);
-void UI_view2d_sync(struct bScreen *screen, struct ScrArea *sa, struct View2D *v2dcur, int flag);
+void UI_view2d_sync(struct bScreen *screen, struct ScrArea *area, struct View2D *v2dcur, int flag);
void UI_view2d_totRect_set(struct View2D *v2d, int width, int height);
void UI_view2d_totRect_set_resize(struct View2D *v2d, int width, int height, bool resize);
@@ -137,9 +137,9 @@ void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, con
void UI_view2d_view_restore(const struct bContext *C);
/* grid drawing */
-void UI_view2d_constant_grid_draw(struct View2D *v2d, float step);
+void UI_view2d_constant_grid_draw(const struct View2D *v2d, float step);
void UI_view2d_multi_grid_draw(
- struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
+ const struct View2D *v2d, int colorid, float step, int level_size, int totlevels);
void UI_view2d_draw_lines_y__values(const struct View2D *v2d);
void UI_view2d_draw_lines_x__values(const struct View2D *v2d);
@@ -209,14 +209,17 @@ 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();
void UI_view2d_view_to_region(
- struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_fl(
- struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL();
-void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
-void UI_view2d_view_to_region_rcti(struct View2D *v2d,
+ const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_fl(const struct View2D *v2d,
+ float x,
+ float y,
+ float *r_region_x,
+ float *r_region_y) ATTR_NONNULL();
+void UI_view2d_view_to_region_m4(const struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL();
+void UI_view2d_view_to_region_rcti(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
-bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d,
+bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d,
const struct rctf *rect_src,
struct rcti *rect_dst) ATTR_NONNULL();
@@ -228,9 +231,9 @@ void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_
void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
-void UI_view2d_scale_get_inverse(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y);
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_center_set(struct View2D *v2d, float x, float y);
void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index d33023c69a1..e4fb0631f06 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -68,7 +68,10 @@ set(SRC
interface_region_tooltip.c
interface_regions.c
interface_style.c
+ interface_template_search_menu.c
+ interface_template_search_operator.c
interface_templates.c
+ interface_undo.c
interface_utils.c
interface_widgets.c
resources.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 41b7683dff7..04c259ab092 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -44,7 +44,6 @@
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -262,7 +261,7 @@ void ui_region_to_window(const ARegion *region, int *x, int *y)
static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
{
int sepr_flex_len = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_SEPR_SPACER) {
sepr_flex_len++;
}
@@ -284,7 +283,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
/* We could get rid of this loop if we agree on a max number of spacer */
int *spacers_pos = alloca(sizeof(*spacers_pos) * (size_t)sepr_flex_len);
int i = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->type == UI_BTYPE_SEPR_SPACER) {
ui_but_to_pixelrect(&rect, region, block, but);
spacers_pos[i] = rect.xmax + UI_HEADER_OFFSET;
@@ -295,7 +294,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block)
const float segment_width = region_width / (float)sepr_flex_len;
float offset = 0, remaining_space = region_width - buttons_width;
i = 0;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
BLI_rctf_translate(&but->rect, offset, 0);
if (but->type == UI_BTYPE_SEPR_SPACER) {
/* How much the next block overlap with the current segment */
@@ -642,6 +641,26 @@ static int ui_but_calc_float_precision(uiBut *but, double value)
/* ************** BLOCK ENDING FUNCTION ************* */
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b)
+{
+ return ui_but_rna_equals_ex(a, &b->rnapoin, b->rnaprop, b->rnaindex);
+}
+
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index)
+{
+ if (but->rnapoin.data != ptr->data) {
+ return false;
+ }
+ if (but->rnaprop != prop || but->rnaindex != index) {
+ return false;
+ }
+
+ return true;
+}
+
/* NOTE: if but->poin is allocated memory for every defbut, things fail... */
static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
{
@@ -650,10 +669,7 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
if (but->retval != oldbut->retval) {
return false;
}
- if (but->rnapoin.data != oldbut->rnapoin.data) {
- return false;
- }
- if (but->rnaprop != oldbut->rnaprop || but->rnaindex != oldbut->rnaindex) {
+ if (!ui_but_rna_equals(but, oldbut)) {
return false;
}
if (but->func != oldbut->func) {
@@ -791,6 +807,8 @@ static bool ui_but_update_from_old_block(const bContext *C,
SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons);
+ SWAP(struct uiButSearchData *, oldbut->search, but->search);
+
/* copy hardmin for list rows to prevent 'sticking' highlight to mouse position
* when scrolling without moving mouse (see [#28432]) */
if (ELEM(oldbut->type, UI_BTYPE_ROW, UI_BTYPE_LISTROW)) {
@@ -899,7 +917,7 @@ bool UI_but_active_only(const bContext *C, ARegion *region, uiBlock *block, uiBu
bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, uiBlock *block)
{
bool done = false;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->flag & UI_BUT_ACTIVATE_ON_INIT) {
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
if (ui_but_is_editable(but)) {
@@ -914,7 +932,7 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *region, ui
if (done) {
/* Run this in a second pass since it's possible activating the button
* removes the buttons being looped over. */
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->flag &= ~UI_BUT_ACTIVATE_ON_INIT;
}
}
@@ -971,13 +989,15 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
/* 2 Passes, on for first letter only, second for any letter if first fails
* fun first pass on all buttons so first word chars always get first priority */
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (!ELEM(but->type,
UI_BTYPE_BUT,
UI_BTYPE_BUT_MENU,
UI_BTYPE_MENU,
UI_BTYPE_BLOCK,
- UI_BTYPE_PULLDOWN) ||
+ UI_BTYPE_PULLDOWN,
+ /* For PIE-menus. */
+ UI_BTYPE_ROW) ||
(but->flag & UI_HIDDEN)) {
/* pass */
}
@@ -1297,9 +1317,8 @@ static bool ui_but_event_property_operator_string(const bContext *C,
}
else if (GS(id->name) == ID_SCE) {
if (RNA_struct_is_a(ptr->type, &RNA_ToolSettings)) {
- /* toolsettings property
- * NOTE: toolsettings is usually accessed directly (i.e. not through scene)
- */
+ /* Tool-settings property:
+ * NOTE: tool-settings is usually accessed directly (i.e. not through scene). */
data_path = RNA_path_from_ID_to_property(ptr, prop);
}
else {
@@ -1664,7 +1683,7 @@ static void ui_but_predefined_extra_operator_icons_add(uiBut *but)
}
if (optype) {
- for (uiButExtraOpIcon *op_icon = but->extra_op_icons.first; op_icon; op_icon = op_icon->next) {
+ LISTBASE_FOREACH (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
if ((op_icon->optype_params->optype == optype) && (op_icon->icon == icon)) {
/* Don't add the same operator icon twice (happens if button is kept alive while active).
*/
@@ -1935,7 +1954,7 @@ static void ui_block_message_subscribe(ARegion *region, struct wmMsgBus *mbus, u
{
uiBut *but_prev = NULL;
/* possibly we should keep the region this block is contained in? */
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->rnapoin.type && but->rnaprop) {
/* quick check to avoid adding buttons representing a vector, multiple times. */
if ((but_prev && (but_prev->rnaprop == but->rnaprop) &&
@@ -1960,7 +1979,7 @@ static void ui_block_message_subscribe(ARegion *region, struct wmMsgBus *mbus, u
void UI_region_message_subscribe(ARegion *region, struct wmMsgBus *mbus)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
ui_block_message_subscribe(region, mbus, block);
}
}
@@ -3207,9 +3226,12 @@ static void ui_but_free(const bContext *C, uiBut *but)
MEM_freeN(but->hold_argN);
}
- if (but->search_arg_free_func) {
- but->search_arg_free_func(but->search_arg);
- but->search_arg = NULL;
+ if (but->search != NULL) {
+ if (but->search->arg_free_fn) {
+ but->search->arg_free_fn(but->search->arg);
+ but->search->arg = NULL;
+ }
+ MEM_freeN(but->search);
}
if (but->active) {
@@ -3275,7 +3297,7 @@ void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
ARegion *region = CTX_wm_region(C);
wmWindow *window = CTX_wm_window(C);
- for (uiBlock *block = lb->first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, lb) {
if (block->active) {
ui_update_window_matrix(window, region, block);
}
@@ -3284,7 +3306,7 @@ void UI_blocklist_update_window_matrix(const bContext *C, const ListBase *lb)
void UI_blocklist_draw(const bContext *C, const ListBase *lb)
{
- for (uiBlock *block = lb->first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, lb) {
if (block->active) {
UI_block_draw(C, block);
}
@@ -6329,36 +6351,51 @@ uiBut *uiDefSearchBut(uiBlock *block,
}
/**
- * \param search_func, bfunc: both get it as \a arg.
- * \param arg: user value,
- * \param active: when set, button opens with this item visible and selected.
+ * \note The item-pointer (referred to below) is a per search item user pointer
+ * passed to #UI_search_item_add (stored in #uiSearchItems.pointers).
+ *
+ * \param search_create_fn: Function to create the menu.
+ * \param search_update_fn: Function to refresh search content after the search text has changed.
+ * \param arg: user value.
+ * \param search_arg_free_fn: When non-null, use this function to free \a arg.
+ * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument.
+ * The second argument as the active item-pointer
+ * \param active: When non-null, this item-pointer item will be visible and selected,
+ * otherwise the first item will be selected.
*/
void UI_but_func_search_set(uiBut *but,
- uiButSearchCreateFunc search_create_func,
- uiButSearchFunc search_func,
+ uiButSearchCreateFn search_create_fn,
+ uiButSearchUpdateFn search_update_fn,
void *arg,
- uiButSearchArgFreeFunc search_arg_free_func,
- uiButHandleFunc bfunc,
+ uiButSearchArgFreeFn search_arg_free_fn,
+ uiButHandleFunc search_exec_fn,
void *active)
{
/* needed since callers don't have access to internal functions
* (as an alternative we could expose it) */
- if (search_create_func == NULL) {
- search_create_func = ui_searchbox_create_generic;
+ if (search_create_fn == NULL) {
+ search_create_fn = ui_searchbox_create_generic;
}
- if (but->search_arg_free_func != NULL) {
- but->search_arg_free_func(but->search_arg);
- but->search_arg = NULL;
+ struct uiButSearchData *search = but->search;
+ if (search != NULL) {
+ if (search->arg_free_fn != NULL) {
+ search->arg_free_fn(but->search->arg);
+ search->arg = NULL;
+ }
+ }
+ else {
+ search = MEM_callocN(sizeof(*but->search), __func__);
+ but->search = search;
}
- but->search_create_func = search_create_func;
- but->search_func = search_func;
+ search->create_fn = search_create_fn;
+ search->update_fn = search_update_fn;
- but->search_arg = arg;
- but->search_arg_free_func = search_arg_free_func;
+ search->arg = arg;
+ search->arg_free_fn = search_arg_free_fn;
- if (bfunc) {
+ if (search_exec_fn) {
#ifdef DEBUG
if (but->func) {
/* watch this, can be cause of much confusion, see: T47691 */
@@ -6366,7 +6403,7 @@ void UI_but_func_search_set(uiBut *but,
__func__);
}
#endif
- UI_but_func_set(but, bfunc, arg, active);
+ UI_but_func_set(but, search_exec_fn, search->arg, active);
}
/* search buttons show red-alert if item doesn't exist, not for menus */
@@ -6378,11 +6415,33 @@ void UI_but_func_search_set(uiBut *but,
}
}
+void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn)
+{
+ struct uiButSearchData *search = but->search;
+ search->context_menu_fn = context_menu_fn;
+}
+
+/**
+ * \param separator_string: when not NULL, this string is used as a separator,
+ * showing the icon and highlighted text after the last instance of this string.
+ */
+void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string)
+{
+ struct uiButSearchData *search = but->search;
+ search->sep_string = search_sep_string;
+}
+
+void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn)
+{
+ struct uiButSearchData *search = but->search;
+ search->tooltip_fn = tooltip_fn;
+}
+
/* Callbacks for operator search button. */
-static void operator_enum_search_cb(const struct bContext *C,
- void *but,
- const char *str,
- uiSearchItems *items)
+static void operator_enum_search_update_fn(const struct bContext *C,
+ void *but,
+ const char *str,
+ uiSearchItems *items)
{
wmOperatorType *ot = ((uiBut *)but)->optype;
PropertyRNA *prop = ot->prop;
@@ -6419,7 +6478,7 @@ static void operator_enum_search_cb(const struct bContext *C,
}
}
-static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *arg2)
+static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but, void *arg2)
{
wmOperatorType *ot = ((uiBut *)but)->optype;
PointerRNA *opptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */
@@ -6462,10 +6521,10 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip);
UI_but_func_search_set(but,
ui_searchbox_create_generic,
- operator_enum_search_cb,
+ operator_enum_search_update_fn,
but,
NULL,
- operator_enum_call_cb,
+ operator_enum_search_exec_fn,
NULL);
but->optype = ot;
@@ -6480,6 +6539,13 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block,
return but;
}
+void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4])
+{
+ but->flag |= UI_BUT_NODE_LINK;
+ but->custom_data = socket;
+ rgba_float_to_uchar(but->col, draw_color);
+}
+
/**
* push a new event onto event queue to activate the given button
* (usually a text-field) upon entering a popup
@@ -6608,8 +6674,8 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
}
else {
/* Not all menus are from Python. */
- if (mt->ext.srna) {
- const char *t = RNA_struct_ui_description(mt->ext.srna);
+ if (mt->rna_ext.srna) {
+ const char *t = RNA_struct_ui_description(mt->rna_ext.srna);
if (t && t[0]) {
tmp = BLI_strdup(t);
}
@@ -6626,7 +6692,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
}
else {
/* Not all panels are from Python. */
- if (pt->ext.srna) {
+ if (pt->rna_ext.srna) {
/* Panels don't yet have descriptions, this may be added. */
}
}
@@ -6645,7 +6711,7 @@ void UI_but_string_info_get(bContext *C, uiBut *but, ...)
else if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_PULLDOWN)) {
MenuType *mt = UI_but_menutype_get(but);
if (mt) {
- _tmp = RNA_struct_translation_context(mt->ext.srna);
+ _tmp = RNA_struct_translation_context(mt->rna_ext.srna);
}
}
if (BLT_is_default_context(_tmp)) {
diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c
index 09811fab52d..32cae609395 100644
--- a/source/blender/editors/interface/interface_align.c
+++ b/source/blender/editors/interface/interface_align.c
@@ -124,7 +124,11 @@ bool ui_but_can_align(const uiBut *but)
int ui_but_align_opposite_to_area_align_get(const ARegion *region)
{
- switch (RGN_ALIGN_ENUM_FROM_MASK(region->alignment)) {
+ const ARegion *align_region = (region->alignment & RGN_SPLIT_PREV && region->prev) ?
+ region->prev :
+ region;
+
+ switch (RGN_ALIGN_ENUM_FROM_MASK(align_region->alignment)) {
case RGN_ALIGN_TOP:
return UI_BUT_ALIGN_DOWN;
case RGN_ALIGN_BOTTOM:
@@ -502,7 +506,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
butal->but->drawflag |= align;
butal_other->but->drawflag |= align_opp;
- if (butal->dists[side]) {
+ if (!IS_EQF(butal->dists[side], 0.0f)) {
float *delta = &butal->dists[side];
if (*butal->borders[side] < *butal_other->borders[side_opp]) {
@@ -513,7 +517,7 @@ void ui_block_align_calc(uiBlock *block, const ARegion *region)
}
co = (*butal->borders[side] += *delta);
- if (butal_other->dists[side_opp]) {
+ if (!IS_EQF(butal_other->dists[side_opp], 0.0f)) {
BLI_assert(butal_other->dists[side_opp] * 0.5f == fabsf(*delta));
*butal_other->borders[side_opp] = co;
butal_other->dists[side_opp] = 0.0f;
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 15fc23bc539..5bf2147aff5 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -28,12 +28,14 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_nla.h"
@@ -59,7 +61,7 @@ static FCurve *ui_but_get_fcurve(
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve_context_ui(
+ return BKE_fcurve_find_by_rna_context_ui(
but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, adt, action, r_driven, r_special);
}
@@ -114,10 +116,40 @@ void ui_but_anim_flag(uiBut *but, float cfra)
}
}
+static uiBut *ui_but_anim_decorate_find_attached_button(uiBut *but_decorate)
+{
+ uiBut *but_iter = NULL;
+
+ BLI_assert(UI_but_is_decorator(but_decorate));
+ BLI_assert(but_decorate->rnasearchpoin.data && but_decorate->rnasearchprop);
+
+ LISTBASE_CIRCULAR_BACKWARD_BEGIN (&but_decorate->block->buttons, but_iter, but_decorate->prev) {
+ if (but_iter != but_decorate &&
+ ui_but_rna_equals_ex(but_iter,
+ &but_decorate->rnasearchpoin,
+ but_decorate->rnasearchprop,
+ POINTER_AS_INT(but_decorate->custom_data))) {
+ return but_iter;
+ }
+ }
+ LISTBASE_CIRCULAR_BACKWARD_END(&but_decorate->block->buttons, but_iter, but_decorate->prev);
+
+ return NULL;
+}
+
void ui_but_anim_decorate_update_from_flag(uiBut *but)
{
- BLI_assert(UI_but_is_decorator(but) && but->prev);
- int flag = but->prev->flag;
+ const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but);
+
+ if (!but_anim) {
+ printf("Could not find button with matching property to decorate (%s.%s)\n",
+ RNA_struct_identifier(but->rnasearchpoin.type),
+ RNA_property_identifier(but->rnasearchprop));
+ return;
+ }
+
+ int flag = but_anim->flag;
+
if (flag & UI_BUT_DRIVEN) {
but->icon = ICON_DECORATE_DRIVER;
}
@@ -289,22 +321,26 @@ void ui_but_anim_paste_driver(bContext *C)
void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy))
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiBut *but = arg_but;
- but = but->prev;
+ uiBut *but_decorate = 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. */
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth++;
- if (but->flag & UI_BUT_DRIVEN) {
+ if (but_anim->flag & UI_BUT_DRIVEN) {
/* pass */
/* TODO: report? */
}
- else if (but->flag & UI_BUT_ANIMATED_KEY) {
+ else if (but_anim->flag & UI_BUT_ANIMATED_KEY) {
PointerRNA props_ptr;
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->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
@@ -312,11 +348,11 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)
PointerRNA props_ptr;
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->rnaindex == -1);
+ RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1);
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
}
- SWAP(struct uiHandleButtonData *, but->active, but->next->active);
+ SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active);
wm->op_undo_depth--;
}
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 76107d190ba..cc370113422 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -962,7 +962,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
const PropertyType prop_type = RNA_property_type(but->rnaprop);
if (((prop_type == PROP_POINTER) ||
(prop_type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU &&
- but->search_func == ui_rna_collection_search_cb)) &&
+ but->search->update_fn == ui_rna_collection_search_update_fn)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
@@ -1231,9 +1231,9 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
/**
* menu to show when right clicking on the panel header
*/
-void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *pa)
+void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
const bool has_panel_category = UI_panel_category_is_visible(region);
const bool any_item_visible = has_panel_category;
PointerRNA ptr;
@@ -1243,11 +1243,11 @@ void ui_popup_context_menu_for_panel(bContext *C, ARegion *region, Panel *pa)
if (!any_item_visible) {
return;
}
- if (pa->type->parent != NULL) {
+ if (panel->type->parent != NULL) {
return;
}
- RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_Panel, panel, &ptr);
pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE);
layout = UI_popup_menu_layout(pup);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index f69dbb94f19..817cb44db29 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -54,14 +54,14 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Eyedropper Modal Map");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Eyedropper Modal Map", modal_items);
/* assign to operators */
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorramp");
@@ -84,12 +84,12 @@ wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorRamp PointSampling Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Eyedropper ColorRamp PointSampling Map");
if (keymap && keymap->modal_items) {
return keymap;
}
- keymap = WM_modalkeymap_add(
+ keymap = WM_modalkeymap_ensure(
keyconf, "Eyedropper ColorRamp PointSampling Map", modal_items_point);
/* assign to operators */
@@ -139,8 +139,8 @@ void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *region
uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->x, event->y);
uiBut *but = ui_but_find_mouse_over(region, event);
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 372fd841bc1..c917ffb3f3e 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -82,11 +82,13 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
eye->use_accum = RNA_boolean_get(op->ptr, "use_accumulate");
uiBut *but = UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
+ const enum PropertySubType prop_subtype = eye->prop ? RNA_property_subtype(eye->prop) : 0;
if ((eye->ptr.data == NULL) || (eye->prop == NULL) ||
(RNA_property_editable(&eye->ptr, eye->prop) == false) ||
(RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
- (RNA_property_type(eye->prop) != PROP_FLOAT)) {
+ (RNA_property_type(eye->prop) != PROP_FLOAT) ||
+ (ELEM(prop_subtype, PROP_COLOR, PROP_COLOR_GAMMA) == 0)) {
MEM_freeN(eye);
return false;
}
@@ -96,7 +98,7 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
float col[4];
RNA_property_float_get_array(&eye->ptr, eye->prop, col);
- if (RNA_property_subtype(eye->prop) != PROP_COLOR) {
+ if (prop_subtype != PROP_COLOR) {
Scene *scene = CTX_data_scene(C);
const char *display_device;
@@ -136,16 +138,31 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
{
/* we could use some clever */
Main *bmain = CTX_data_main(C);
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ wmWindowManager *wm = CTX_wm_manager(C);
const char *display_device = CTX_data_scene(C)->display_settings.display_device;
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
- if (sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ if (area == NULL) {
+ int mval[2] = {mx, my};
+ if (WM_window_find_under_cursor(wm, NULL, win, mval, &win, mval)) {
+ mx = mval[0];
+ my = mval[1];
+ screen = WM_window_get_active_screen(win);
+ area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ }
+ else {
+ win = NULL;
+ }
+ }
+
+ if (area) {
+ if (area->spacetype == SPACE_IMAGE) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_image_color_sample(sima, region, mval, r_col)) {
@@ -153,10 +170,10 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
}
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ else if (area->spacetype == SPACE_NODE) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_node_color_sample(bmain, snode, region, mval, r_col)) {
@@ -164,10 +181,10 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
}
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ else if (area->spacetype == SPACE_CLIP) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
if (ED_space_clip_color_sample(sc, region, mval, r_col)) {
@@ -177,12 +194,15 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
}
}
- /* fallback to simple opengl picker */
- glReadBuffer(GL_FRONT);
- glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
- glReadBuffer(GL_BACK);
-
- IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+ if (win) {
+ /* Fallback to simple opengl picker. */
+ int mval[2] = {mx, my};
+ WM_window_pixel_sample_read(wm, win, mval, r_col);
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+ }
+ else {
+ zero_v3(r_col);
+ }
}
/* sets the sample color RGB, maintaining A */
@@ -290,7 +310,10 @@ static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(
{
/* init */
if (eyedropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index be23eacafff..24d06361c54 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,10 @@ static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEven
{
/* init */
if (eyedropper_colorband_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
index 93599b8727a..f2217db9b7d 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -152,27 +152,27 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- if (sa) {
- if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (area) {
+ if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
Base *base;
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
/* grr, always draw else we leave stale text */
ED_region_tag_redraw(region);
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (area->spacetype == SPACE_VIEW3D) {
base = ED_view3d_give_base_under_cursor(C, mval);
}
else {
@@ -208,7 +208,7 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
}
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
/* sets the ID, returns success */
@@ -250,11 +250,11 @@ static void datadropper_set_draw_callback_region(bContext *C,
const int my)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
- if (sa) {
+ if (area) {
/* If spacetype changed */
- if (sa->spacetype != ddr->cursor_area->spacetype) {
+ if (area->spacetype != ddr->cursor_area->spacetype) {
/* Remove old callback */
ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
@@ -263,9 +263,9 @@ static void datadropper_set_draw_callback_region(bContext *C,
ED_region_tag_redraw(region);
/* Set draw callback in new region */
- ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_WINDOW);
+ ARegionType *art = BKE_regiontype_from_id(area->type, RGN_TYPE_WINDOW);
- ddr->cursor_area = sa;
+ ddr->cursor_area = area;
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(
art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
@@ -316,7 +316,10 @@ static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED
{
/* init */
if (datadropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
index a5e60adec55..5c85edc94a1 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -156,27 +156,27 @@ static void depthdropper_depth_sample_pt(
{
/* we could use some clever */
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
Scene *scene = CTX_data_scene(C);
ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (area) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my);
if (region) {
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
/* weak, we could pass in some reference point */
const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
float co[3];
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
/* grr, always draw else we leave stale text */
@@ -209,7 +209,7 @@ static void depthdropper_depth_sample_pt(
}
CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
}
/* sets the sample depth RGB, maintaining A */
@@ -311,7 +311,10 @@ static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
{
/* init */
if (depthdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
index 89c087855bc..276cc70f2b5 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,10 @@ static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
{
/* init */
if (driverdropper_init(C, op)) {
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ wmWindow *win = CTX_wm_window(C);
+ /* Workaround for de-activating the button clearing the cursor, see T76794 */
+ UI_context_active_but_clear(C, win, CTX_wm_region(C));
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
diff --git a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
index 2944186c701..3d32ede60c2 100644
--- a/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLT_translation.h"
@@ -211,7 +212,7 @@ static void eyedropper_add_palette_color(bContext *C, float col_conv[4])
}
/* Check if the color exist already. */
Palette *palette = paint->palette;
- for (PaletteColor *palcolor = palette->colors.first; palcolor; palcolor = palcolor->next) {
+ LISTBASE_FOREACH (PaletteColor *, palcolor, &palette->colors) {
if (compare_v3v3(palcolor->rgb, col_conv, 0.01f)) {
return;
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 98d9418c3f5..a62130b9b13 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -335,12 +335,7 @@ typedef struct uiHandleButtonData {
int maxlen;
/* Button text selection:
* extension direction, selextend, inside ui_do_but_TEX */
- enum {
- EXTEND_NONE = 0,
- EXTEND_LEFT = 1,
- EXTEND_RIGHT = 2,
- } selextend;
- float selstartx;
+ int sel_pos_init;
/* allow to realloc str/editstr and use 'maxlen' to track alloc size (maxlen + 1) */
bool is_str_dynamic;
@@ -386,6 +381,9 @@ typedef struct uiHandleButtonData {
uiSelectContextStore select_others;
#endif
+ /* Text field undo. */
+ struct uiUndoStack_Text *undo_stack_text;
+
/* post activate */
uiButtonActivateType posttype;
uiBut *postbut;
@@ -422,7 +420,7 @@ typedef struct uiAfterFunc {
PropertyRNA *rnaprop;
void *search_arg;
- uiButSearchArgFreeFunc search_arg_free_func;
+ uiButSearchArgFreeFn search_arg_free_fn;
bContextStore *context;
@@ -758,10 +756,12 @@ static void ui_apply_but_func(bContext *C, uiBut *but)
after->rnapoin = but->rnapoin;
after->rnaprop = but->rnaprop;
- after->search_arg_free_func = but->search_arg_free_func;
- after->search_arg = but->search_arg;
- but->search_arg_free_func = NULL;
- but->search_arg = NULL;
+ if (but->search != NULL) {
+ after->search_arg_free_fn = but->search->arg_free_fn;
+ after->search_arg = but->search->arg;
+ but->search->arg_free_fn = NULL;
+ but->search->arg = NULL;
+ }
if (but->context) {
after->context = CTX_store_copy(but->context);
@@ -929,8 +929,8 @@ static void ui_apply_but_funcs_after(bContext *C)
MEM_freeN(after.rename_orig);
}
- if (after.search_arg_free_func) {
- after.search_arg_free_func(after.search_arg);
+ if (after.search_arg_free_fn) {
+ after.search_arg_free_fn(after.search_arg);
}
ui_afterfunc_update_preferences_dirty(&after);
@@ -1272,7 +1272,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
data->multi_data.bs_mbuts = UI_butstore_create(but_active->block);
- for (uiBut *but = but_active->block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &but_active->block->buttons) {
if (but->flag & UI_BUT_DRAG_MULTI) {
ui_multibut_add(data, but);
}
@@ -1282,7 +1282,7 @@ static void ui_multibut_states_create(uiBut *but_active, uiHandleButtonData *dat
* note: if we mix buttons which are proportional and others which are not,
* this may work a bit strangely */
if ((but_active->rnaprop && (RNA_property_flag(but_active->rnaprop) & PROP_PROPORTIONAL)) ||
- ELEM(but_active->unit_type, PROP_UNIT_LENGTH)) {
+ ELEM(but_active->unit_type, RNA_SUBTYPE_UNIT_VALUE(PROP_UNIT_LENGTH))) {
if (data->origvalue != 0.0) {
data->multi_data.is_proportional = true;
}
@@ -1874,7 +1874,7 @@ static bool ui_but_drag_init(bContext *C,
#ifdef USE_DRAG_TOGGLE
if (ui_drag_toggle_but_is_supported(but)) {
uiDragToggleHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
- ARegion *ar_prev;
+ ARegion *region_prev;
/* call here because regular mouse-up event wont run,
* typically 'button_activate_exit()' handles this */
@@ -1887,7 +1887,7 @@ static bool ui_but_drag_init(bContext *C,
copy_v2_v2_int(drag_info->xy_last, &event->x);
/* needed for toggle drag on popups */
- ar_prev = CTX_wm_region(C);
+ region_prev = CTX_wm_region(C);
CTX_wm_region_set(C, data->region);
WM_event_add_ui_handler(C,
@@ -1897,7 +1897,7 @@ static bool ui_but_drag_init(bContext *C,
drag_info,
WM_HANDLER_BLOCKING);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
/* Initialize alignment for single row/column regions,
* otherwise we use the relative position of the first other button dragged over. */
@@ -1906,13 +1906,13 @@ static bool ui_but_drag_init(bContext *C,
RGN_TYPE_HEADER,
RGN_TYPE_TOOL_HEADER,
RGN_TYPE_FOOTER)) {
- const int ar_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
+ const int region_alignment = RGN_ALIGN_ENUM_FROM_MASK(data->region->alignment);
int lock_axis = -1;
- if (ELEM(ar_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ if (ELEM(region_alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
lock_axis = 0;
}
- else if (ELEM(ar_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ else if (ELEM(region_alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
lock_axis = 1;
}
if (lock_axis != -1) {
@@ -2837,6 +2837,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
return changed;
}
+static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int UNUSED(glyph_bearing[2]),
+ void *user_data)
+{
+ int *cursor_data = user_data;
+ float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f);
+ if (cursor_data[0] < center) {
+ cursor_data[1] = str_step_ofs;
+ return false;
+ }
+ return true;
+}
+
/**
* \param x: Screen space cursor location - #wmEvent.x
*
@@ -2872,8 +2889,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
- /* But this extra .05 makes clicks in between characters feel nicer. */
- startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
+ startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
/* mouse dragged outside the widget to the left */
if (x < startx) {
@@ -2896,48 +2912,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
but->pos = but->ofs;
}
/* mouse inside the widget, mouse coords mapped in widget space */
- else { /* (x >= startx) */
- int pos_i;
-
- /* keep track of previous distance from the cursor to the char */
- float cdist, cdist_prev = 0.0f;
- short pos_prev;
-
- str_last = &str[strlen(str)];
-
- but->pos = pos_prev = ((str_last - str) - but->ofs);
-
- while (true) {
- cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs);
-
- /* check if position is found */
- if (cdist < x) {
- /* check is previous location was in fact closer */
- if ((x - cdist) > (cdist_prev - x)) {
- but->pos = pos_prev;
- }
- break;
- }
- cdist_prev = cdist;
- pos_prev = but->pos;
- /* done with tricky distance checks */
-
- pos_i = but->pos;
- if (but->pos <= 0) {
- break;
- }
- if (BLI_str_cursor_step_prev_utf8(str, but->ofs, &pos_i)) {
- but->pos = pos_i;
- str_last = &str[but->pos + but->ofs];
- }
- else {
- break; /* unlikely but possible */
- }
- }
- but->pos += but->ofs;
- if (but->pos < 0) {
- but->pos = 0;
- }
+ else {
+ str_last = &str[but->ofs];
+ const int str_last_len = strlen(str_last);
+ int x_pos = (int)(x - startx);
+ int glyph_data[2] = {
+ x_pos, /* horizontal position to test. */
+ -1, /* Write the character offset here. */
+ };
+ BLF_boundbox_foreach_glyph(fstyle.uifont_id,
+ str + but->ofs,
+ INT_MAX,
+ ui_textedit_set_cursor_pos_foreach_glyph,
+ glyph_data);
+ /* If value untouched then we are to the right. */
+ if (glyph_data[1] == -1) {
+ glyph_data[1] = str_last_len;
+ }
+ but->pos = glyph_data[1] + but->ofs;
}
if (fstyle.kerning == 1) {
@@ -2949,20 +2941,12 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
static void ui_textedit_set_cursor_select(uiBut *but, uiHandleButtonData *data, const float x)
{
- if (x > data->selstartx) {
- data->selextend = EXTEND_RIGHT;
- }
- else if (x < data->selstartx) {
- data->selextend = EXTEND_LEFT;
- }
-
ui_textedit_set_cursor_pos(but, data, x);
- if (data->selextend == EXTEND_RIGHT) {
- but->selend = but->pos;
- }
- else if (data->selextend == EXTEND_LEFT) {
- but->selsta = but->pos;
+ but->selsta = but->pos;
+ but->selend = data->sel_pos_init;
+ if (but->selend < but->selsta) {
+ SWAP(short, but->selsta, but->selend);
}
ui_but_update(but);
@@ -3058,7 +3042,7 @@ static void ui_textedit_move(uiBut *but,
but->pos = but->selend = but->selsta;
}
}
- data->selextend = EXTEND_NONE;
+ data->sel_pos_init = but->pos;
}
else {
int pos_i = but->pos;
@@ -3066,48 +3050,14 @@ static void ui_textedit_move(uiBut *but,
but->pos = pos_i;
if (select) {
- /* existing selection */
- if (has_sel) {
-
- if (data->selextend == EXTEND_NONE) {
- data->selextend = EXTEND_RIGHT;
- }
-
- if (direction) {
- if (data->selextend == EXTEND_RIGHT) {
- but->selend = but->pos;
- }
- else {
- but->selsta = but->pos;
- }
- }
- else {
- if (data->selextend == EXTEND_LEFT) {
- but->selsta = but->pos;
- }
- else {
- but->selend = but->pos;
- }
- }
-
- if (but->selend < but->selsta) {
- SWAP(short, but->selsta, but->selend);
- data->selextend = (data->selextend == EXTEND_RIGHT) ? EXTEND_LEFT : EXTEND_RIGHT;
- }
-
- } /* new selection */
- else {
- if (direction) {
- data->selextend = EXTEND_RIGHT;
- but->selend = but->pos;
- but->selsta = pos_prev;
- }
- else {
- data->selextend = EXTEND_LEFT;
- but->selend = pos_prev;
- but->selsta = but->pos;
- }
+ if (has_sel == false) {
+ data->sel_pos_init = pos_prev;
}
+ but->selsta = but->pos;
+ but->selend = data->sel_pos_init;
+ }
+ if (but->selend < but->selsta) {
+ SWAP(short, but->selsta, but->selend);
}
}
}
@@ -3337,8 +3287,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
len = strlen(data->str);
data->origstr = BLI_strdupn(data->str, len);
- data->selextend = EXTEND_NONE;
- data->selstartx = 0.0f;
+ data->sel_pos_init = 0;
/* set cursor pos to the end of the text */
but->editstr = data->str;
@@ -3346,9 +3295,13 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
but->selsta = 0;
but->selend = len;
+ /* Initialize undo history tracking. */
+ data->undo_stack_text = ui_textedit_undo_stack_create();
+ ui_textedit_undo_push(data->undo_stack_text, but->editstr, but->pos);
+
/* optional searchbox */
if (but->type == UI_BTYPE_SEARCH_MENU) {
- data->searchbox = but->search_create_func(C, data->region, but);
+ data->searchbox = but->search->create_fn(C, data->region, but);
ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
}
@@ -3388,6 +3341,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
/* ensure menu (popup) too is closed! */
data->escapecancel = true;
+
+ WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr);
+ WM_report_banner_show();
}
}
@@ -3401,6 +3357,10 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
WM_cursor_modal_restore(win);
+ /* Free text undo history text blocks. */
+ ui_textedit_undo_stack_destroy(data->undo_stack_text);
+ data->undo_stack_text = NULL;
+
#ifdef WITH_INPUT_IME
if (win->ime_data) {
ui_textedit_ime_end(win, but);
@@ -3480,7 +3440,7 @@ static void ui_do_but_textedit(
bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
int retval = WM_UI_HANDLER_CONTINUE;
- bool changed = false, inbox = false, update = false;
+ bool changed = false, inbox = false, update = false, skip_undo_push = false;
#ifdef WITH_INPUT_IME
wmWindow *win = CTX_wm_window(C);
@@ -3500,7 +3460,7 @@ static void ui_do_but_textedit(
/* pass */
}
else {
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
}
#else
ui_searchbox_event(C, data->searchbox, but, event);
@@ -3511,6 +3471,16 @@ static void ui_do_but_textedit(
case RIGHTMOUSE:
case EVT_ESCKEY:
if (event->val == KM_PRESS) {
+ /* Support search context menu. */
+ if (event->type == RIGHTMOUSE) {
+ if (data->searchbox) {
+ if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) {
+ /* Only break if the event was handled. */
+ break;
+ }
+ }
+ }
+
#ifdef WITH_INPUT_IME
/* skips button handling since it is not wanted */
if (is_ime_composing) {
@@ -3544,7 +3514,7 @@ static void ui_do_but_textedit(
if (ui_but_contains_pt(but, mx, my)) {
ui_textedit_set_cursor_pos(but, data, event->x);
but->selsta = but->selend = but->pos;
- data->selstartx = event->x;
+ data->sel_pos_init = but->pos;
button_activate_state(C, but, BUTTON_STATE_TEXT_SELECTING);
retval = WM_UI_HANDLER_BREAK;
@@ -3619,7 +3589,7 @@ static void ui_do_but_textedit(
#ifdef USE_KEYNAV_LIMIT
ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
#endif
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
break;
}
if (event->type == WHEELDOWNMOUSE) {
@@ -3636,7 +3606,7 @@ static void ui_do_but_textedit(
#ifdef USE_KEYNAV_LIMIT
ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
#endif
- ui_searchbox_event(C, data->searchbox, but, event);
+ ui_searchbox_event(C, data->searchbox, but, data->region, event);
break;
}
if (event->type == WHEELUPMOUSE) {
@@ -3702,6 +3672,32 @@ static void ui_do_but_textedit(
}
retval = WM_UI_HANDLER_BREAK;
break;
+ case EVT_ZKEY: {
+ /* Ctrl-Z or Ctrl-Shift-Z: Undo/Redo (allowing for OS-Key on Apple). */
+
+ const bool is_redo = (event->shift != 0);
+ if (
+#if defined(__APPLE__)
+ (event->oskey && !IS_EVENT_MOD(event, alt, ctrl)) ||
+#endif
+ (event->ctrl && !IS_EVENT_MOD(event, alt, oskey))) {
+ int undo_pos;
+ const char *undo_str = ui_textedit_undo(
+ data->undo_stack_text, is_redo ? 1 : -1, &undo_pos);
+ if (undo_str != NULL) {
+ ui_textedit_string_set(but, data, undo_str);
+
+ /* Set the cursor & clear selection. */
+ but->pos = undo_pos;
+ but->selsta = but->pos;
+ but->selend = but->pos;
+ changed = true;
+ }
+ retval = WM_UI_HANDLER_BREAK;
+ skip_undo_push = true;
+ }
+ break;
+ }
}
if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
@@ -3723,12 +3719,7 @@ static void ui_do_but_textedit(
if (utf8_buf && utf8_buf[0]) {
int utf8_buf_len = BLI_str_utf8_size(utf8_buf);
- /* keep this printf until utf8 is well tested */
- if (utf8_buf_len != 1) {
- printf("%s: utf8 char '%.*s'\n", __func__, utf8_buf_len, utf8_buf);
- }
-
- // strcpy(utf8_buf, "12345");
+ BLI_assert(utf8_buf_len != -1);
changed = ui_textedit_insert_buf(but, data, event->utf8_buf, utf8_buf_len);
}
else {
@@ -3760,6 +3751,11 @@ static void ui_do_but_textedit(
#endif
if (changed) {
+ /* The undo stack may be NULL if an event exits editing. */
+ if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) {
+ ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos);
+ }
+
/* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
if (update && data->interactive) {
ui_apply_but(C, block, but, data, true);
@@ -4434,7 +4430,8 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
do_activate = (event->val == KM_RELEASE);
}
else {
- do_activate = (event->val == KM_PRESS);
+ /* Also use double-clicks to prevent fast clicks to leak to other handlers (T76481). */
+ do_activate = ELEM(event->val, KM_PRESS, KM_DBL_CLICK);
}
}
@@ -5546,7 +5543,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
else if (but->type == UI_BTYPE_MENU) {
if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->ctrl) {
- const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
+ const int direction = (event->type == WHEELDOWNMOUSE) ? 1 : -1;
data->value = ui_but_menu_step(but, direction);
@@ -7691,8 +7688,8 @@ void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
uiHandleButtonData *data = but->active;
if (data) {
- bScreen *sc = WM_window_get_active_screen(data->window);
- if (sc->tool_tip && sc->tool_tip->region) {
+ bScreen *screen = WM_window_get_active_screen(data->window);
+ if (screen->tool_tip && screen->tool_tip->region) {
WM_tooltip_refresh(C, data->window);
}
}
@@ -7752,9 +7749,9 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
WM_tooltip_timer_init_ex(
C, data->window, data->area, data->region, ui_but_tooltip_init, delay);
if (is_label) {
- bScreen *sc = WM_window_get_active_screen(data->window);
- if (sc->tool_tip) {
- sc->tool_tip->pass = 1;
+ bScreen *screen = WM_window_get_active_screen(data->window);
+ if (screen->tool_tip) {
+ screen->tool_tip->pass = 1;
}
}
}
@@ -8040,11 +8037,11 @@ static void button_activate_init(bContext *C,
if (UI_but_has_tooltip_label(but)) {
/* Show a label for this button. */
- bScreen *sc = WM_window_get_active_screen(data->window);
+ bScreen *screen = WM_window_get_active_screen(data->window);
if ((PIL_check_seconds_timer() - WM_tooltip_time_closed()) < 0.1) {
WM_tooltip_immediate_init(C, CTX_wm_window(C), data->area, region, ui_but_tooltip_init);
- if (sc->tool_tip) {
- sc->tool_tip->pass = 1;
+ if (screen->tool_tip) {
+ screen->tool_tip->pass = 1;
}
}
}
@@ -8245,11 +8242,22 @@ static uiBut *ui_context_rna_button_active(const bContext *C)
return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
}
-uiBut *UI_context_active_but_get(const struct bContext *C)
+uiBut *UI_context_active_but_get(const bContext *C)
{
return ui_context_button_active(CTX_wm_region(C), NULL);
}
+/*
+ * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
+ * if set. Does not traverse into parent menus, which may be wanted in some
+ * cases.
+ */
+uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
+{
+ ARegion *ar_menu = CTX_wm_menu(C);
+ return ui_context_button_active(ar_menu ? ar_menu : CTX_wm_region(C), NULL);
+}
+
uiBut *UI_region_active_but_get(ARegion *region)
{
return ui_context_button_active(region, NULL);
@@ -8308,18 +8316,23 @@ void UI_context_active_but_prop_handle(bContext *C)
}
}
+void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
+{
+ wm_event_handler_ui_cancel_ex(C, win, region, false);
+}
+
wmOperator *UI_context_active_operator_get(const struct bContext *C)
{
- ARegion *ar_ctx = CTX_wm_region(C);
+ ARegion *region_ctx = CTX_wm_region(C);
uiBlock *block;
/* background mode */
- if (ar_ctx == NULL) {
+ if (region_ctx == NULL) {
return NULL;
}
/* scan active regions ui */
- for (block = ar_ctx->uiblocks.first; block; block = block->next) {
+ for (block = region_ctx->uiblocks.first; block; block = block->next) {
if (block->ui_operator) {
return block->ui_operator;
}
@@ -8327,11 +8340,11 @@ wmOperator *UI_context_active_operator_get(const struct bContext *C)
/* scan popups */
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ARegion *region;
- for (region = sc->regionbase.first; region; region = region->next) {
- if (region == ar_ctx) {
+ for (region = screen->regionbase.first; region; region = region->next) {
+ if (region == region_ctx) {
continue;
}
for (block = region->uiblocks.first; block; block = block->next) {
@@ -8454,10 +8467,10 @@ void ui_but_activate_event(bContext *C, ARegion *region, uiBut *but)
event.customdata = but;
event.customdatafree = false;
- ARegion *ar_ctx = CTX_wm_region(C);
+ ARegion *region_ctx = CTX_wm_region(C);
CTX_wm_region_set(C, region);
ui_do_button(C, but->block, but, &event);
- CTX_wm_region_set(C, ar_ctx);
+ CTX_wm_region_set(C, region_ctx);
}
/**
@@ -8839,14 +8852,14 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
if (post_but) {
button_activate_init(C, region, post_but, post_type);
}
- else {
+ else if (!((event->type == EVT_BUT_CANCEL) && (event->val == 1))) {
/* XXX issue is because WM_event_add_mousemove(wm) is a bad hack and not reliable,
* if that gets coded better this bypass can go away too.
*
* This is needed to make sure if a button was active,
* it stays active while the mouse is over it.
* This avoids adding mousemoves, see: [#33466] */
- if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) {
+ if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT, BUTTON_STATE_WAIT_DRAG)) {
if (ui_but_find_mouse_over(region, event) == but) {
button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
}
@@ -9225,7 +9238,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
if (dy < 0.0f) {
/* Stop at top item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
float ymax = -FLT_MAX;
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ymax = max_ff(ymax, bt->rect.ymax);
}
if (ymax + dy - UI_UNIT_Y * 0.5f < block->rect.ymax - UI_MENU_SCROLL_PAD) {
@@ -9235,7 +9248,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
else {
/* Stop at bottom item, extra 0.5 UI_UNIT_Y makes it snap nicer. */
float ymin = FLT_MAX;
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ymin = min_ff(ymin, bt->rect.ymin);
}
if (ymin + dy + UI_UNIT_Y * 0.5f > block->rect.ymin + UI_MENU_SCROLL_PAD) {
@@ -9248,7 +9261,7 @@ static void ui_menu_scroll_apply_offset_y(ARegion *region, uiBlock *block, float
block->handle->scrolloffset += dy;
/* apply scroll offset */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
bt->rect.ymin += dy;
bt->rect.ymax += dy;
}
@@ -9329,7 +9342,7 @@ static bool ui_menu_scroll_step(ARegion *region, uiBlock *block, const int scrol
static void ui_region_auto_open_clear(ARegion *region)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
block->auto_open = false;
}
}
@@ -9371,6 +9384,11 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
if (event->val == KM_RELEASE) {
/* pass, needed so we can exit active menu-items when click-dragging out of them */
}
+ else if (but->type == UI_BTYPE_SEARCH_MENU) {
+ /* Pass, needed so search popup can have RMB context menu.
+ * This may be useful for other interactions which happen in the search popup
+ * without being directly over the search button. */
+ }
else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
/* pass, skip for dialogs */
}
@@ -9783,7 +9801,11 @@ static int ui_handle_menu_event(bContext *C,
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
+ if (!ELEM(but->type,
+ UI_BTYPE_LABEL,
+ UI_BTYPE_SEPR,
+ UI_BTYPE_SEPR_LINE,
+ UI_BTYPE_IMAGE)) {
count++;
}
@@ -10624,7 +10646,7 @@ static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(use
static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
{
- bScreen *sc;
+ bScreen *screen;
ARegion *region;
region = CTX_wm_region(C);
@@ -10634,15 +10656,15 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
UI_blocklist_free(C, &region->uiblocks);
- sc = CTX_wm_screen(C);
- if (sc == NULL) {
+ screen = CTX_wm_screen(C);
+ if (screen == NULL) {
return;
}
/* delayed apply callbacks, but not for screen level regions, those
* we rather do at the very end after closing them all, which will
* be done in ui_region_handler/window */
- if (BLI_findindex(&sc->regionbase, region) == -1) {
+ if (BLI_findindex(&screen->regionbase, region) == -1) {
ui_apply_but_funcs_after(C);
}
}
@@ -10800,9 +10822,6 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata)
if (temp.popup_func) {
temp.popup_func(C, temp.popup_arg, temp.retvalue);
}
- if (temp.optype) {
- WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL);
- }
}
else if (temp.cancel_func) {
temp.cancel_func(C, temp.popup_arg);
@@ -10966,9 +10985,8 @@ void UI_screen_free_active_but(const bContext *C, bScreen *screen)
{
wmWindow *win = CTX_wm_window(C);
- ED_screen_areas_iter(win, screen, area)
- {
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
uiBut *but = ui_region_find_active_but(region);
if (but) {
uiHandleButtonData *data = but->active;
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index edc5087c8dd..deea3028354 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -45,10 +45,8 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "RNA_access.h"
-#include "RNA_enum_types.h"
#include "BKE_appdir.h"
#include "BKE_context.h"
@@ -63,10 +61,6 @@
#include "BIF_glutil.h"
-#include "DEG_depsgraph.h"
-
-#include "DRW_engine.h"
-
#include "ED_datafiles.h"
#include "ED_keyframes_draw.h"
#include "ED_render.h"
@@ -759,11 +753,11 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
// blur alpha channel
const int write_offset = by * (ICON_GRID_W + 2 * ICON_MONO_BORDER_OUTSET) + bx;
float alpha_accum = 0.0;
- unsigned int alpha_samples = 0;
+ uint alpha_samples = 0;
for (int ax = asx; ax < aex; ax++) {
for (int ay = asy; ay < aey; ay++) {
const int offset_read = (sy + ay) * buf->x + (sx + ax);
- unsigned int color_read = buf->rect[offset_read];
+ uint color_read = buf->rect[offset_read];
const float alpha_read = ((color_read & 0xff000000) >> 24) / 255.0;
alpha_accum += alpha_read;
alpha_samples += 1;
@@ -782,8 +776,8 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
const float border_srgb[4] = {
0, 0, 0, MIN2(1.0, blurred_alpha * border_sharpness) * border_intensity};
- const unsigned int color_read = buf->rect[offset_write];
- const unsigned char *orig_color = (unsigned char *)&color_read;
+ const uint color_read = buf->rect[offset_write];
+ const uchar *orig_color = (uchar *)&color_read;
float border_rgba[4];
float orig_rgba[4];
@@ -795,8 +789,8 @@ static ImBuf *create_mono_icon_with_border(ImBuf *buf,
blend_color_interpolate_float(dest_rgba, orig_rgba, border_rgba, 1.0 - orig_rgba[3]);
linearrgb_to_srgb_v4(dest_srgb, dest_rgba);
- unsigned int alpha_mask = ((unsigned int)(dest_srgb[3] * 255)) << 24;
- unsigned int cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask;
+ uint alpha_mask = ((uint)(dest_srgb[3] * 255)) << 24;
+ uint cpack = rgb_to_cpack(dest_srgb[0], dest_srgb[1], dest_srgb[2]) | alpha_mask;
result->rect[offset_write] = cpack;
}
}
@@ -1129,8 +1123,8 @@ void UI_icons_free(void)
#ifndef WITH_HEADLESS
free_icons_textures();
free_iconfile_list(&iconfilelist);
- BKE_icons_free();
#endif
+ BKE_icons_free();
}
void UI_icons_free_drawinfo(void *drawinfo)
@@ -1609,8 +1603,8 @@ static void icon_draw_cache_texture_flush_ex(GLuint texture,
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
GPU_shader_bind(shader);
- int img_loc = GPU_shader_get_uniform_ensure(shader, "image");
- int data_loc = GPU_shader_get_uniform_ensure(shader, "calls_data[0]");
+ int img_loc = GPU_shader_get_uniform(shader, "image");
+ int data_loc = GPU_shader_get_uniform(shader, "calls_data");
glUniform1i(img_loc, 0);
glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache);
@@ -1756,9 +1750,9 @@ static void icon_draw_texture(float x,
GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
}
- glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), x1, y1, x2, y2);
- glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), x, y, x + w, y + h);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), x1, y1, x2, y2);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), x, y, x + w, y + h);
GPU_draw_primitive(GPU_PRIM_TRI_STRIP, 4);
@@ -1892,7 +1886,7 @@ static void icon_draw_size(float x,
mul_v4_fl(color, alpha);
float border_outset = 0.0;
- unsigned int border_texel = 0;
+ uint border_texel = 0;
#ifndef WITH_HEADLESS
if (with_border) {
const float scale = (float)ICON_GRID_W / (float)ICON_DEFAULT_WIDTH;
@@ -2015,8 +2009,8 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
Object *ob = CTX_data_active_object(C);
const EnumPropertyItem *items = NULL;
ePaintMode paint_mode = PAINT_MODE_INVALID;
- ScrArea *sa = CTX_wm_area(C);
- char space_type = sa->spacetype;
+ ScrArea *area = CTX_wm_area(C);
+ char space_type = area->spacetype;
/* Fallback to 3D view. */
if (space_type == SPACE_PROPERTIES) {
space_type = SPACE_VIEW3D;
@@ -2041,8 +2035,8 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
}
}
else if (space_type == SPACE_IMAGE) {
- if (sa->spacetype == space_type) {
- const SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == space_type) {
+ const SpaceImage *sima = area->spacedata.first;
if (sima->mode == SI_MODE_PAINT) {
paint_mode = PAINT_MODE_TEXTURE_2D;
}
@@ -2326,6 +2320,9 @@ int UI_idcode_icon_get(const int idcode)
return ICON_WORLD_DATA;
case ID_WS:
return ICON_WORKSPACE;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ return ICON_PHYSICS;
default:
return ICON_NONE;
}
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index d22338e94fc..2f2297fc8bc 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -25,6 +25,8 @@
#define __INTERFACE_INTERN_H__
#include "BLI_compiler_attrs.h"
+#include "BLI_rect.h"
+
#include "DNA_listBase.h"
#include "RNA_types.h"
#include "UI_interface.h"
@@ -39,6 +41,7 @@ struct bContextStore;
struct uiHandleButtonData;
struct uiLayout;
struct uiStyle;
+struct uiUndoStack_Text;
struct uiWidgetColors;
struct wmEvent;
struct wmKeyConfig;
@@ -102,7 +105,6 @@ extern const char ui_radial_dir_to_numpad[8];
extern const short ui_radial_dir_to_angle[8];
/* internal panel drawing defines */
-#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */
/* bit button defines */
@@ -145,6 +147,17 @@ enum {
/* max amount of items a radial menu (pie menu) can contain */
#define PIE_MAX_ITEMS 8
+struct uiButSearchData {
+ uiButSearchCreateFn create_fn;
+ uiButSearchUpdateFn update_fn;
+ void *arg;
+ uiButSearchArgFreeFn arg_free_fn;
+ uiButSearchContextMenuFn context_menu_fn;
+ uiButSearchTooltipFn tooltip_fn;
+
+ const char *sep_string;
+};
+
struct uiBut {
struct uiBut *next, *prev;
int flag, drawflag;
@@ -201,10 +214,7 @@ struct uiBut {
uiButCompleteFunc autocomplete_func;
void *autofunc_arg;
- uiButSearchCreateFunc search_create_func;
- uiButSearchFunc search_func;
- void *search_arg;
- uiButSearchArgFreeFunc search_arg_free_func;
+ struct uiButSearchData *search;
uiButHandleRenameFunc rename_func;
void *rename_arg1;
@@ -344,7 +354,7 @@ struct uiBlock {
uiBlock *next, *prev;
ListBase buttons;
- Panel *panel;
+ struct Panel *panel;
uiBlock *oldblock;
ListBase butstore; /* UI_butstore_* runtime function */
@@ -476,8 +486,10 @@ extern void ui_window_to_block_rctf(const struct ARegion *region,
uiBlock *block,
rctf *rct_dst,
const rctf *rct_src);
-extern void ui_window_to_region(const ARegion *region, int *x, int *y);
-extern void ui_window_to_region_rcti(const ARegion *region, rcti *rect_dst, const rcti *rct_src);
+extern void ui_window_to_region(const struct ARegion *region, int *x, int *y);
+extern void ui_window_to_region_rcti(const struct ARegion *region,
+ rcti *rect_dst,
+ const rcti *rct_src);
extern void ui_region_to_window(const struct ARegion *region, int *x, int *y);
extern void ui_region_winrct_get_no_margin(const struct ARegion *region, struct rcti *r_rect);
@@ -565,7 +577,7 @@ struct uiPopupBlockCreate {
int event_xy[2];
/* when popup is initialized from a button */
- ARegion *butregion;
+ struct ARegion *butregion;
uiBut *but;
};
@@ -596,10 +608,8 @@ struct uiPopupBlockHandle {
/* for operator popups */
struct wmOperator *popup_op;
- struct wmOperatorType *optype;
- ScrArea *ctx_area;
- ARegion *ctx_region;
- int opcontext;
+ struct ScrArea *ctx_area;
+ struct ARegion *ctx_region;
/* return values */
int butretval;
@@ -647,17 +657,24 @@ ColorPicker *ui_block_colorpicker_create(struct uiBlock *block);
/* interface_region_search.c */
/* Searchbox for string button */
-ARegion *ui_searchbox_create_generic(struct bContext *C, struct ARegion *butregion, uiBut *but);
-ARegion *ui_searchbox_create_operator(struct bContext *C, struct ARegion *butregion, uiBut *but);
-ARegion *ui_searchbox_create_menu(struct bContext *C, struct ARegion *butregion, uiBut *but);
+struct ARegion *ui_searchbox_create_generic(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+struct ARegion *ui_searchbox_create_operator(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
+struct ARegion *ui_searchbox_create_menu(struct bContext *C,
+ struct ARegion *butregion,
+ uiBut *but);
bool ui_searchbox_inside(struct ARegion *region, int x, int y);
int ui_searchbox_find_index(struct ARegion *region, const char *name);
void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset);
int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str);
-void ui_searchbox_event(struct bContext *C,
+bool ui_searchbox_event(struct bContext *C,
struct ARegion *region,
uiBut *but,
+ struct ARegion *butregion,
const struct wmEvent *event);
bool ui_searchbox_apply(uiBut *but, struct ARegion *region);
void ui_searchbox_free(struct bContext *C, struct ARegion *region);
@@ -671,7 +688,7 @@ void ui_popup_menu_memory_set(uiBlock *block, struct uiBut *but);
uiBlock *ui_popup_block_refresh(struct bContext *C,
uiPopupBlockHandle *handle,
- ARegion *butregion,
+ struct ARegion *butregion,
uiBut *but);
uiPopupBlockHandle *ui_popup_block_create(struct bContext *C,
@@ -698,7 +715,7 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C,
void ui_pie_menu_level_create(uiBlock *block,
struct wmOperatorType *ot,
const char *propname,
- IDProperty *properties,
+ struct IDProperty *properties,
const EnumPropertyItem *items,
int totitem,
int context,
@@ -732,37 +749,47 @@ void ui_draw_but_TAB_outline(const rcti *rect,
float rad,
uchar highlight[3],
uchar highlight_fade[3]);
-void ui_draw_but_HISTOGRAM(ARegion *region,
+void ui_draw_but_HISTOGRAM(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_WAVEFORM(ARegion *region,
+void ui_draw_but_WAVEFORM(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_VECTORSCOPE(ARegion *region,
+void ui_draw_but_VECTORSCOPE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect);
-void ui_draw_but_CURVE(ARegion *region,
+void ui_draw_but_CURVE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_CURVEPROFILE(ARegion *region,
+void ui_draw_but_CURVEPROFILE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_IMAGE(ARegion *region,
+void ui_draw_but_IMAGE(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
-void ui_draw_but_TRACKPREVIEW(ARegion *region,
+void ui_draw_but_TRACKPREVIEW(struct ARegion *region,
uiBut *but,
const struct uiWidgetColors *wcol,
const rcti *rect);
+/* interface_undo.c */
+struct uiUndoStack_Text *ui_textedit_undo_stack_create(void);
+void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack);
+void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack,
+ const char *text,
+ int cursor_index);
+const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack,
+ int direction,
+ int *r_cursor_index);
+
/* interface_handlers.c */
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot,
int opcontext,
@@ -790,6 +817,11 @@ void ui_but_set_text(struct bContext *C, uiBut *but, char *text);
void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip);
void ui_but_clipboard_free(void);
+bool ui_but_rna_equals(const uiBut *a, const uiBut *b);
+bool ui_but_rna_equals_ex(const uiBut *but,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ int index);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
@@ -836,7 +868,11 @@ struct GPUBatch *ui_batch_roundbox_shadow_get(void);
void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4]);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
-void ui_draw_popover_back(ARegion *region, struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_box_opaque(rcti *rect, int roundboxalign);
+void ui_draw_popover_back(struct ARegion *region,
+ struct uiStyle *style,
+ uiBlock *block,
+ rcti *rect);
void ui_draw_pie_center(uiBlock *block);
const struct uiWidgetColors *ui_tooltip_get_theme(void);
@@ -844,15 +880,19 @@ void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const flo
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow);
void ui_draw_tooltip_background(const struct uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
-extern void ui_draw_but(
- const struct bContext *C, ARegion *region, struct uiStyle *style, uiBut *but, rcti *rect);
+extern void ui_draw_but(const struct bContext *C,
+ struct ARegion *region,
+ struct uiStyle *style,
+ uiBut *but,
+ rcti *rect);
void ui_draw_menu_item(const struct uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
- bool use_sep);
+ bool use_sep,
+ int *r_xmax);
void ui_draw_preview_item(
const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state);
@@ -894,8 +934,8 @@ void ui_item_paneltype_func(struct bContext *C, struct uiLayout *layout, void *a
/* interface_align.c */
bool ui_but_can_align(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
-int ui_but_align_opposite_to_area_align_get(const ARegion *region) ATTR_WARN_UNUSED_RESULT;
-void ui_block_align_calc(uiBlock *block, const ARegion *region);
+int ui_but_align_opposite_to_area_align_get(const struct ARegion *region) ATTR_WARN_UNUSED_RESULT;
+void ui_block_align_calc(uiBlock *block, const struct ARegion *region);
/* interface_anim.c */
void ui_but_anim_flag(uiBut *but, float cfra);
@@ -916,6 +956,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT;
bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
+int ui_but_icon(const uiBut *but);
void ui_but_pie_dir(RadialDirection dir, float vec[2]);
bool ui_but_is_cursor_warp(const uiBut *but) ATTR_WARN_UNUSED_RESULT;
@@ -971,12 +1012,15 @@ bool ui_region_contains_point_px(const struct ARegion *region,
int y) ATTR_WARN_UNUSED_RESULT;
bool ui_region_contains_rect_px(const struct ARegion *region, const rcti *rect_px);
-ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y);
-ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const struct wmEvent *event);
+struct ARegion *ui_screen_region_find_mouse_over_ex(struct bScreen *screen, int x, int y);
+struct ARegion *ui_screen_region_find_mouse_over(struct bScreen *screen,
+ const struct wmEvent *event);
/* interface_context_menu.c */
bool ui_popup_context_menu_for_button(struct bContext *C, uiBut *but);
-void ui_popup_context_menu_for_panel(struct bContext *C, struct ARegion *region, struct Panel *pa);
+void ui_popup_context_menu_for_panel(struct bContext *C,
+ struct ARegion *region,
+ struct Panel *panel);
/* interface_eyedropper.c */
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
@@ -1002,9 +1046,10 @@ void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
/* interface_util.c */
+bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len);
/**
- * For use with #ui_rna_collection_search_cb.
+ * For use with #ui_rna_collection_search_update_fn.
*/
typedef struct uiRNACollectionSearch {
PointerRNA target_ptr;
@@ -1013,12 +1058,16 @@ typedef struct uiRNACollectionSearch {
PointerRNA search_ptr;
PropertyRNA *search_prop;
- bool *but_changed; /* pointer to uiBut.changed */
+ uiBut *search_but;
+ /* Let UI_butstore_ API update search_but pointer above over redraws. */
+ uiButStore *butstore;
+ /* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */
+ uiBlock *butstore_block;
} uiRNACollectionSearch;
-void ui_rna_collection_search_cb(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items);
+void ui_rna_collection_search_update_fn(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items);
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index fed35ccff59..884e43b4026 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -39,7 +39,7 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -75,7 +75,7 @@
} \
(void)0
-#define UI_ITEM_PROP_SEP_DIVIDE 0.5f
+#define UI_ITEM_PROP_SEP_DIVIDE 0.4f
/* uiLayoutRoot */
@@ -135,10 +135,11 @@ enum {
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
+ UI_ITEM_INSIDE_PROP_SEP = 1 << 4,
/* Show an icon button next to each property (to set keyframes, show status).
* Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */
- UI_ITEM_PROP_DECORATE = 1 << 4,
- UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5,
+ UI_ITEM_PROP_DECORATE = 1 << 5,
+ UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6,
};
typedef struct uiButtonItem {
@@ -151,8 +152,11 @@ struct uiLayout {
uiLayoutRoot *root;
bContextStore *context;
+ uiLayout *parent;
ListBase items;
+ char heading[UI_MAX_NAME_STR];
+
/** Sub layout to add child items, if not the layout itself. */
uiLayout *child_items_layout;
@@ -945,19 +949,25 @@ static uiBut *ui_item_with_label(uiLayout *layout,
PropertyType type;
PropertySubType subtype;
int prop_but_width = w_hint;
+#ifdef UI_PROP_DECORATE
+ uiLayout *layout_prop_decorate = NULL;
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
+#endif
/* Always align item with label since text is already given enough space not to overlap. */
sub = uiLayoutRow(layout, true);
UI_block_layout_set_current(block, sub);
+#ifdef UI_PROP_DECORATE
if (name[0]) {
- int w_label;
-
if (use_prop_sep) {
- w_label = (int)((w_hint * 2) * UI_ITEM_PROP_SEP_DIVIDE);
+ layout_prop_decorate = uiItemL_respect_property_split(layout, name, 0);
}
- else {
+ else
+#endif
+ {
+ int w_label;
+
if (ui_layout_variable_size(layout)) {
/* w_hint is width for label in this case.
* Use a default width for property button(s) */
@@ -967,13 +977,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
else {
w_label = w_hint / 3;
}
- }
-
- uiBut *but_label = uiDefBut(
- block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
- if (use_prop_sep) {
- but_label->drawflag |= UI_BUT_TEXT_RIGHT;
- but_label->drawflag &= ~UI_BUT_TEXT_LEFT;
+ uiDefBut(block, UI_BTYPE_LABEL, 0, name, x, y, w_label, h, NULL, 0.0, 0.0, 0, 0, "");
}
}
@@ -1053,7 +1057,7 @@ static uiBut *ui_item_with_label(uiLayout *layout,
if (layout->item.flag & UI_ITEM_PROP_SEP) {
if ((layout->item.flag & UI_ITEM_PROP_DECORATE) &&
(layout->item.flag & UI_ITEM_PROP_DECORATE_NO_PAD) == 0) {
- uiItemL(sub, NULL, ICON_BLANK1);
+ uiItemL(layout_prop_decorate ? layout_prop_decorate : sub, NULL, ICON_BLANK1);
}
}
#endif /* UI_PROP_DECORATE */
@@ -1780,6 +1784,7 @@ static void ui_item_rna_size(uiLayout *layout,
PropertyType type;
PropertySubType subtype;
int len, w = 0, h;
+ bool is_checkbox_only = false;
/* arbitrary extended width by type */
type = RNA_property_type(prop);
@@ -1791,6 +1796,10 @@ static void ui_item_rna_size(uiLayout *layout,
name = "non-empty text";
}
else if (type == PROP_BOOLEAN) {
+ if (icon == ICON_NONE) {
+ /* Exception for checkboxes, they need a little less space to align nicely. */
+ is_checkbox_only = true;
+ }
icon = ICON_DOT;
}
else if (type == PROP_ENUM) {
@@ -1850,6 +1859,9 @@ static void ui_item_rna_size(uiLayout *layout,
if (type == PROP_BOOLEAN && name[0]) {
w += UI_UNIT_X / 5;
}
+ else if (is_checkbox_only) {
+ w -= UI_UNIT_X / 4;
+ }
else if (type == PROP_ENUM && !icon_only) {
w += UI_UNIT_X / 4;
}
@@ -1862,6 +1874,78 @@ static void ui_item_rna_size(uiLayout *layout,
*r_h = h;
}
+static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag)
+{
+ const bool is_array = RNA_property_array_check(prop);
+ const int subtype = RNA_property_subtype(prop);
+ return is_array && (index == RNA_NO_INDEX) &&
+ ((item_flag & UI_ITEM_R_EXPAND) ||
+ !ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION));
+}
+
+/**
+ * Find first layout ancestor (or self) with a heading set.
+ *
+ * \returns the layout to add the heading to as fallback (i.e. if it can't be placed in a split
+ * layout). Its #uiLayout.heading member can be cleared to mark the heading as added (so
+ * it's not added multiple times). Returns a pointer to the heading
+ */
+static uiLayout *ui_layout_heading_find(uiLayout *cur_layout)
+{
+ for (uiLayout *parent = cur_layout; parent; parent = parent->parent) {
+ if (parent->heading[0]) {
+ return parent;
+ }
+ }
+
+ return NULL;
+}
+
+static void ui_layout_heading_label_add(uiLayout *layout,
+ uiLayout *heading_layout,
+ bool right_align,
+ bool respect_prop_split)
+{
+ const int prev_alignment = layout->alignment;
+
+ if (right_align) {
+ uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT);
+ }
+
+ if (respect_prop_split) {
+ uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE);
+ }
+ else {
+ uiItemL(layout, heading_layout->heading, ICON_NONE);
+ }
+ /* After adding the heading label, we have to mark it somehow as added, so it's not added again
+ * for other items in this layout. For now just clear it. */
+ heading_layout->heading[0] = '\0';
+
+ layout->alignment = prev_alignment;
+}
+
+/**
+ * Hack to add further items in a row into the second part of the split layout, so the label part
+ * keeps a fixed size.
+ * \return The layout to place further items in for the split layout.
+ */
+static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split)
+{
+ /* Tag item as using property split layout, this is inherited to children so they can get special
+ * treatment if needed. */
+ layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP;
+
+ if (layout_parent->item.type == ITEM_LAYOUT_ROW) {
+ /* Prevent further splits within the row. */
+ uiLayoutSetPropSep(layout_parent, false);
+
+ layout_parent->child_items_layout = uiLayoutRow(layout_split, true);
+ return layout_parent->child_items_layout;
+ }
+ return layout_split;
+}
+
void uiItemFullR(uiLayout *layout,
PointerRNA *ptr,
PropertyRNA *prop,
@@ -1874,13 +1958,18 @@ void uiItemFullR(uiLayout *layout,
uiBlock *block = layout->root->block;
char namestr[UI_MAX_NAME_STR];
const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0);
-
- /* By default 'use_prop_sep' uses a separate column for labels.
- * This is an exception for check-boxes otherwise only the small checkbox region is clickable.
+ const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0);
+ /* Columns can define a heading to insert. If the first item added to a split layout doesn't have
+ * a label to display in the first column, the heading is inserted there. Otherwise it's inserted
+ * as a new row before the first item. */
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
+ /* Although checkboxes use the split layout, they are an exception and should only place their
+ * label in the second column, to not make that almost empty.
*
* Keep using 'use_prop_sep' instead of disabling it entirely because
* we need the ability to have decorators still. */
bool use_prop_sep_split_label = use_prop_sep;
+ bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME);
#ifdef UI_PROP_DECORATE
struct {
@@ -1991,6 +2080,9 @@ void uiItemFullR(uiLayout *layout,
if (use_prop_sep) {
if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) {
use_prop_sep_split_label = false;
+ /* For check-boxes we make an exception: We allow showing them in a split row even without
+ * label. It typically relates to its neighbor items, so no need for an extra label. */
+ use_split_empty_name = true;
}
}
#endif
@@ -2017,6 +2109,7 @@ void uiItemFullR(uiLayout *layout,
/* Split the label / property. */
uiLayout *layout_parent = layout;
+
if (use_prop_sep) {
uiLayout *layout_row = NULL;
#ifdef UI_PROP_DECORATE
@@ -2027,21 +2120,26 @@ void uiItemFullR(uiLayout *layout,
}
#endif /* UI_PROP_DECORATE */
- if ((name[0] == '\0') || (use_prop_sep_split_label == false)) {
+ if ((name[0] == '\0') && !use_split_empty_name) {
/* Ensure we get a column when text is not set. */
layout = uiLayoutColumn(layout_row ? layout_row : layout, true);
layout->space = 0;
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, false, false);
+ }
}
else {
- const PropertySubType subtype = RNA_property_subtype(prop);
uiLayout *layout_split = uiLayoutSplit(
layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true);
+ bool label_added = false;
layout_split->space = 0;
uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
layout_sub->space = 0;
- if ((index == RNA_NO_INDEX && is_array) &&
- ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0)) {
+ if (!use_prop_sep_split_label) {
+ /* Pass */
+ }
+ else if (ui_item_rna_is_expand(prop, index, flag)) {
char name_with_suffix[UI_MAX_DRAW_STR + 2];
char str[2] = {'\0'};
for (int a = 0; a < len; a++) {
@@ -2070,6 +2168,8 @@ void uiItemFullR(uiLayout *layout,
"");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
else {
@@ -2078,16 +2178,17 @@ void uiItemFullR(uiLayout *layout,
block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
but->drawflag |= UI_BUT_TEXT_RIGHT;
but->drawflag &= ~UI_BUT_TEXT_LEFT;
+
+ label_added = true;
}
}
- /* Hack to add further items in a row into the second part of
- * the split layout, so the label part keeps a fixed size. */
- if (layout_parent && layout_parent->item.type == ITEM_LAYOUT_ROW) {
- layout_split = uiLayoutRow(layout_split, true);
- layout_parent->child_items_layout = layout_split;
+ if (!label_added && heading_layout) {
+ ui_layout_heading_label_add(layout_sub, heading_layout, true, false);
}
+ layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split);
+
/* Watch out! We can only write into the new layout now. */
if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) {
/* Expanded enums each have their own name. */
@@ -2102,7 +2203,9 @@ void uiItemFullR(uiLayout *layout,
}
}
else {
- name = "";
+ if (use_prop_sep_split_label) {
+ name = "";
+ }
layout = uiLayoutColumn(layout_split, true);
}
layout->space = 0;
@@ -2121,9 +2224,20 @@ void uiItemFullR(uiLayout *layout,
#endif /* UI_PROP_DECORATE */
}
/* End split. */
+ else if (heading_layout) {
+ /* Could not add heading to split layout, fallback to inserting it to the layout with the
+ * heading itself. */
+ ui_layout_heading_label_add(heading_layout, heading_layout, false, false);
+ }
/* array property */
if (index == RNA_NO_INDEX && is_array) {
+ if (inside_prop_sep) {
+ /* Within a split row, add array items to a column so they match the column layout of
+ * previous items (e.g. transform vector with lock icon for each item). */
+ layout = uiLayoutColumn(layout, true);
+ }
+
ui_item_array(layout,
block,
name,
@@ -2203,12 +2317,6 @@ void uiItemFullR(uiLayout *layout,
if (layout->activate_init) {
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
}
-
- if (use_prop_sep && (use_prop_sep_split_label == false)) {
- /* When the button uses it's own text right align it. */
- but->drawflag |= UI_BUT_TEXT_RIGHT;
- but->drawflag &= ~UI_BUT_TEXT_LEFT;
- }
}
/* The resulting button may have the icon set since boolean button drawing
@@ -2231,50 +2339,21 @@ void uiItemFullR(uiLayout *layout,
#ifdef UI_PROP_DECORATE
if (ui_decorate.use_prop_decorate) {
- const bool is_anim = RNA_property_animateable(ptr, prop);
uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first;
+ const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE);
uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false);
layout_col->space = 0;
layout_col->emboss = UI_EMBOSS_NONE;
+
int i;
for (i = 0; i < ui_decorate.len && but_decorate; i++) {
+ PointerRNA *ptr_dec = use_blank_decorator ? NULL : &but_decorate->rnapoin;
+ PropertyRNA *prop_dec = use_blank_decorator ? NULL : but_decorate->rnaprop;
+
/* The icons are set in 'ui_but_anim_flag' */
- if (is_anim) {
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_DOT,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Animate property"));
- UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
- but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
- }
- else {
- /* We may show other information here in future, for now use empty space. */
- but = uiDefIconBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_BLANK1,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- "");
- but->flag |= UI_BUT_DISABLED;
- }
+ uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex);
+ but = block->buttons.last;
+
/* Order the decorator after the button we decorate, this is used so we can always
* do a quick lookup. */
BLI_remlink(&block->buttons, but);
@@ -2566,6 +2645,13 @@ static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRN
RNA_STRUCT_END;
}
+static void ui_rna_collection_search_arg_free_fn(void *ptr)
+{
+ uiRNACollectionSearch *coll_search = ptr;
+ UI_butstore_free(coll_search->butstore_block, coll_search->butstore);
+ MEM_freeN(ptr);
+}
+
void ui_but_add_search(
uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *searchptr, PropertyRNA *searchprop)
{
@@ -2598,7 +2684,10 @@ void ui_but_add_search(
coll_search->target_prop = prop;
coll_search->search_ptr = *searchptr;
coll_search->search_prop = searchprop;
- coll_search->but_changed = &but->changed;
+ coll_search->search_but = but;
+ coll_search->butstore_block = but->block;
+ coll_search->butstore = UI_butstore_create(coll_search->butstore_block);
+ UI_butstore_register(coll_search->butstore, &coll_search->search_but);
if (RNA_property_type(prop) == PROP_ENUM) {
/* XXX, this will have a menu string,
@@ -2608,9 +2697,9 @@ void ui_but_add_search(
UI_but_func_search_set(but,
ui_searchbox_create_generic,
- ui_rna_collection_search_cb,
+ ui_rna_collection_search_update_fn,
coll_search,
- MEM_freeN,
+ ui_rna_collection_search_arg_free_fn,
NULL,
NULL);
}
@@ -2737,6 +2826,7 @@ static uiBut *ui_item_menu(uiLayout *layout,
bool force_menu)
{
uiBlock *block = layout->root->block;
+ uiLayout *heading_layout = ui_layout_heading_find(layout);
uiBut *but;
int w, h;
@@ -2766,12 +2856,16 @@ static uiBut *ui_item_menu(uiLayout *layout,
}
}
+ if (heading_layout) {
+ ui_layout_heading_label_add(layout, heading_layout, true, true);
+ }
+
if (name[0] && icon) {
but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip);
}
else if (icon) {
but = uiDefIconMenuBut(block, func, arg, icon, 0, 0, w, h, tip);
- if (force_menu) {
+ if (force_menu && name[0]) {
UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
}
}
@@ -2839,6 +2933,91 @@ void uiItemMContents(uiLayout *layout, const char *menuname)
UI_menutype_draw(C, mt, layout);
}
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop.
+ */
+void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index)
+{
+ uiBlock *block = layout->root->block;
+ uiBut *but = NULL;
+
+ uiLayout *col;
+ UI_block_layout_set_current(block, layout);
+ col = uiLayoutColumn(layout, false);
+ col->space = 0;
+ col->emboss = UI_EMBOSS_NONE;
+
+ if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_BLANK1,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ "");
+ but->flag |= UI_BUT_DISABLED;
+ return;
+ }
+
+ const bool is_expand = ui_item_rna_is_expand(prop, index, 0);
+ const bool is_array = RNA_property_array_check(prop);
+
+ /* Loop for the array-case, but only do in case of an expanded array. */
+ for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) {
+ but = uiDefIconBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_DOT,
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Animate property"));
+ UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL);
+ but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK;
+ /* Reusing RNA search members, setting actual RNA data has many side-effects. */
+ but->rnasearchpoin = *ptr;
+ but->rnasearchprop = prop;
+ /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */
+ but->custom_data = POINTER_FROM_INT((!is_array || is_expand) ? i : index);
+ }
+}
+
+/**
+ * Insert a decorator item for a button with the same property as \a prop.
+ * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname.
+ */
+void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index)
+{
+ PropertyRNA *prop = NULL;
+
+ if (ptr && propname) {
+ /* validate arguments */
+ prop = RNA_struct_find_property(ptr, propname);
+ if (!prop) {
+ ui_item_disabled(layout, propname);
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+ }
+
+ /* ptr and prop are allowed to be NULL here. */
+ uiItemDecoratorR_prop(layout, ptr, prop, index);
+}
+
/* popover */
void uiItemPopoverPanel_ptr(
uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon)
@@ -2897,7 +3076,7 @@ void uiItemPopoverPanelFromGroup(uiLayout *layout,
return;
}
- for (PanelType *pt = art->paneltypes.first; pt; pt = pt->next) {
+ LISTBASE_FOREACH (PanelType *, pt, &art->paneltypes) {
/* Causes too many panels, check context. */
if (pt->parent_id[0] == '\0') {
if (/* (*context == '\0') || */ STREQ(pt->context, context)) {
@@ -2982,28 +3161,40 @@ void uiItemL(uiLayout *layout, const char *name, int icon)
}
/**
- * Helper to add a label, which handles logic for split property layout if needed.
- *
- * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where we may
- * want to use the logic. For those this helper was added, although it will likely have to be
- * extended to support more cases.
- * Ideally, #uiItemFullR() could just call this, but it currently has too many special needs.
- *
- * \return the layout to place the item(s) associated to the label in.
+ * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the
+ * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many
+ * special needs.
+ */
+uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout)
+{
+ uiPropertySplitWrapper split_wrapper = {NULL};
+
+ uiLayout *layout_row = uiLayoutRow(parent_layout, true);
+ uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true);
+
+ layout_split->space = 0;
+ split_wrapper.label_column = uiLayoutColumn(layout_split, true);
+ split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT;
+ split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split);
+ split_wrapper.decorate_column = uiLayoutColumn(layout_row, true);
+
+ return split_wrapper;
+}
+
+/*
+ * Helper to add a label and creates a property split layout if needed.
*/
uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon)
{
if (layout->item.flag & UI_ITEM_PROP_SEP) {
- uiLayout *layout_split = uiLayoutSplit(layout, UI_ITEM_PROP_SEP_DIVIDE, true);
- uiLayout *layout_sub = uiLayoutColumn(layout_split, true);
-
- layout_split->space = layout_sub->space = layout->space = 0;
- layout_sub->alignment = UI_LAYOUT_ALIGN_RIGHT;
+ uiBlock *block = uiLayoutGetBlock(layout);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout);
+ /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */
- uiItemL_(layout_sub, text, icon);
+ uiItemL_(split_wrapper.label_column, text, icon);
+ UI_block_layout_set_current(block, split_wrapper.property_row);
- /* Give caller a new sub-row to place items in. */
- return uiLayoutRow(layout_split, true);
+ return split_wrapper.decorate_column;
}
else {
char namestr[UI_MAX_NAME_STR];
@@ -4444,13 +4635,24 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali
litem->redalert = layout->redalert;
litem->w = layout->w;
litem->emboss = layout->emboss;
- litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE));
+ litem->item.flag = (layout->item.flag &
+ (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE | UI_ITEM_INSIDE_PROP_SEP));
if (layout->child_items_layout) {
BLI_addtail(&layout->child_items_layout->items, litem);
+ litem->parent = layout->child_items_layout;
}
else {
BLI_addtail(&layout->items, litem);
+ litem->parent = layout;
+ }
+}
+
+static void ui_layout_heading_set(uiLayout *layout, const char *heading)
+{
+ BLI_assert(layout->heading[0] == '\0');
+ if (heading) {
+ STRNCPY(layout->heading, heading);
}
}
@@ -4470,6 +4672,16 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align)
return litem;
}
+/**
+ * See #uiLayoutColumnWithHeading().
+ */
+uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutRow(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
{
uiLayout *litem;
@@ -4485,6 +4697,19 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align)
return litem;
}
+/**
+ * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is
+ * added through #uiItemFullR(). If split layout is used and the item has no string to add to the
+ * first split-column, the heading is added there instead. Otherwise the heading inserted with a
+ * new row.
+ */
+uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading)
+{
+ uiLayout *litem = uiLayoutColumn(layout, align);
+ ui_layout_heading_set(litem, heading);
+ return litem;
+}
+
uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align)
{
uiLayoutItemFlow *flow;
@@ -5352,7 +5577,7 @@ static void ui_paneltype_draw_impl(bContext *C, PanelType *pt, uiLayout *layout,
MEM_freeN(panel);
/* Draw child panels. */
- for (LinkData *link = pt->children.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
if (child_pt->poll == NULL || child_pt->poll(C, child_pt)) {
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 3e3ca307cb3..6dc90bffe59 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -807,6 +807,9 @@ bool UI_context_copy_to_selected_list(bContext *C,
else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) {
*r_lb = CTX_data_collection_get(C, "selected_editable_fcurves");
}
+ else if (RNA_struct_is_a(ptr->type, &RNA_NlaStrip)) {
+ *r_lb = CTX_data_collection_get(C, "selected_nla_strips");
+ }
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) {
@@ -1132,8 +1135,9 @@ static bool jump_to_target_button(bContext *C, bool poll)
else if (type == PROP_STRING) {
const uiBut *but = UI_context_active_but_get(C);
- if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) {
- uiRNACollectionSearch *coll_search = but->search_arg;
+ if (but->type == UI_BTYPE_SEARCH_MENU && but->search &&
+ but->search->update_fn == ui_rna_collection_search_update_fn) {
+ uiRNACollectionSearch *coll_search = but->search->arg;
char str_buf[MAXBONENAME];
char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL);
@@ -1305,9 +1309,9 @@ static int editsource_text_edit(bContext *C,
else {
/* naughty!, find text area to set, not good behavior
* but since this is a dev tool lets allow it - campbell */
- ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
- if (sa) {
- SpaceText *st = sa->spacedata.first;
+ ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TEXT, 0);
+ if (area) {
+ SpaceText *st = area->spacedata.first;
st->text = text;
}
else {
@@ -1617,13 +1621,14 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed");
- ARegion *ar_prev = CTX_wm_region(C);
- ARegion *region = sc ? BKE_screen_find_region_xy(sc, RGN_TYPE_ANY, event->x, event->y) : NULL;
+ ARegion *region_prev = CTX_wm_region(C);
+ ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->x, event->y) :
+ NULL;
if (region == NULL) {
- region = ar_prev;
+ region = region_prev;
}
if (region == NULL) {
@@ -1632,7 +1637,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev
CTX_wm_region_set(C, region);
uiBut *but = UI_context_active_but_get(C);
- CTX_wm_region_set(C, ar_prev);
+ CTX_wm_region_set(C, region_prev);
if (but == NULL) {
return OPERATOR_PASS_THROUGH;
@@ -1674,7 +1679,7 @@ static void UI_OT_button_execute(wmOperatorType *ot)
static int button_string_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
- uiBut *but = UI_context_active_but_get(C);
+ uiBut *but = UI_context_active_but_get_respect_menu(C);
if (but) {
ui_but_active_string_clear_and_exit(C, but);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index d57b4d444bd..54f60a05cfd 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
@@ -56,7 +57,9 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "interface_intern.h"
@@ -100,13 +103,20 @@ typedef struct uiHandlePanelData {
double starttime;
/* dragging */
+ bool is_drag_drop;
int startx, starty;
int startofsx, startofsy;
int startsizex, startsizey;
} uiHandlePanelData;
-static int get_panel_real_size_y(const Panel *pa);
-static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state);
+typedef struct PanelSort {
+ Panel *panel, *orig;
+} PanelSort;
+
+static int get_panel_real_size_y(const Panel *panel);
+static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state);
+static int compare_panel(const void *a1, const void *a2);
+static bool panel_type_context_poll(PanelType *panel_type, const char *context);
static void panel_title_color_get(bool show_background, uchar color[4])
{
@@ -131,18 +141,18 @@ typedef enum eSpaceButtons_Align {
BUT_AUTO = 2,
} eSpaceButtons_Align;
-static int panel_aligned(const ScrArea *sa, const ARegion *region)
+static int panel_aligned(const ScrArea *area, const ARegion *region)
{
- if (sa->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
+ if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) {
+ else if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
+ else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
return BUT_VERTICAL;
}
- else if (sa->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
+ else if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
return BUT_VERTICAL;
}
else if (ELEM(region->regiontype,
@@ -160,71 +170,71 @@ static int panel_aligned(const ScrArea *sa, const ARegion *region)
static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation)
{
- for (Panel *pa = lb->first; pa; pa = pa->next) {
+ LISTBASE_FOREACH (Panel *, panel, lb) {
/* Detect panel active flag changes. */
- if (!(pa->type && pa->type->parent)) {
- if ((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE)) {
+ if (!(panel->type && panel->type->parent)) {
+ if ((panel->runtime_flag & PNL_WAS_ACTIVE) && !(panel->runtime_flag & PNL_ACTIVE)) {
return true;
}
- if (!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE)) {
+ if (!(panel->runtime_flag & PNL_WAS_ACTIVE) && (panel->runtime_flag & PNL_ACTIVE)) {
return true;
}
}
- if ((pa->runtime_flag & PNL_ACTIVE) && !(pa->flag & PNL_CLOSED)) {
- if (panel_active_animation_changed(&pa->children, pa_animation, no_animation)) {
+ if ((panel->runtime_flag & PNL_ACTIVE) && !(panel->flag & PNL_CLOSED)) {
+ if (panel_active_animation_changed(&panel->children, pa_animation, no_animation)) {
return true;
}
}
/* Detect animation. */
- if (pa->activedata) {
- uiHandlePanelData *data = pa->activedata;
+ if (panel->activedata) {
+ uiHandlePanelData *data = panel->activedata;
if (data->state == PANEL_STATE_ANIMATION) {
- *pa_animation = pa;
+ *pa_animation = panel;
}
else {
/* Don't animate while handling other interaction. */
*no_animation = true;
}
}
- if ((pa->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
- *pa_animation = pa;
+ if ((panel->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) {
+ *pa_animation = panel;
}
}
return false;
}
-static bool panels_need_realign(ScrArea *sa, ARegion *region, Panel **r_pa_animate)
+static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation)
{
- *r_pa_animate = NULL;
+ *r_panel_animation = NULL;
- if (sa->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
- SpaceProperties *sbuts = sa->spacedata.first;
+ if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) {
+ SpaceProperties *sbuts = area->spacedata.first;
if (sbuts->mainbo != sbuts->mainb) {
return true;
}
}
- else if (sa->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
+ else if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) {
return true;
}
- else if (sa->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
+ else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) {
return true;
}
/* Detect if a panel was added or removed. */
- Panel *pa_animation = NULL;
+ Panel *panel_animation = NULL;
bool no_animation = false;
- if (panel_active_animation_changed(&region->panels, &pa_animation, &no_animation)) {
+ if (panel_active_animation_changed(&region->panels, &panel_animation, &no_animation)) {
return true;
}
/* Detect panel marked for animation, if we're not already animating. */
- if (pa_animation) {
+ if (panel_animation) {
if (!no_animation) {
- *r_pa_animate = pa_animation;
+ *r_panel_animation = panel_animation;
}
return true;
}
@@ -232,144 +242,479 @@ static bool panels_need_realign(ScrArea *sa, ARegion *region, Panel **r_pa_anima
return false;
}
+/********* Functions for instanced panels. ***********/
+
+static Panel *UI_panel_add_instanced_ex(
+ ScrArea *area, ARegion *region, ListBase *panels, PanelType *panel_type, int list_index)
+{
+ Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel");
+ panel->type = panel_type;
+ BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname));
+
+ panel->runtime.list_index = list_index;
+
+ /* 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;
+ UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index);
+ }
+
+ /* Make sure the panel is added to the end of the display-order as well. This is needed for
+ * loading existing files.
+ *
+ * Note: We could use special behavior to place it after the panel that starts the list of
+ * instanced panels, but that would add complexity that isn't needed for now. */
+ int max_sortorder = 0;
+ LISTBASE_FOREACH (Panel *, existing_panel, panels) {
+ if (existing_panel->sortorder > max_sortorder) {
+ max_sortorder = existing_panel->sortorder;
+ }
+ }
+ panel->sortorder = max_sortorder + 1;
+
+ BLI_addtail(panels, panel);
+
+ return panel;
+}
+
+/**
+ * Called in situations where panels need to be added dynamically rather than having only one panel
+ * corresponding to each PanelType.
+ */
+Panel *UI_panel_add_instanced(
+ ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, int list_index)
+{
+ ARegionType *region_type = region->type;
+
+ PanelType *panel_type = BLI_findstring(
+ &region_type->paneltypes, panel_idname, offsetof(PanelType, idname));
+
+ if (panel_type == NULL) {
+ printf("Panel type '%s' not found.\n", panel_idname);
+ return NULL;
+ }
+
+ return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index);
+}
+
+/**
+ * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for
+ * instanced panels, where there can be multiple with the same type and idname.
+ */
+void UI_list_panel_unique_str(Panel *panel, char *r_name)
+{
+ snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index);
+}
+
+/**
+ * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store
+ * a reference to their corresponding #uiBlock.
+ */
+static void panel_free_block(ARegion *region, Panel *panel)
+{
+ BLI_assert(panel->type);
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME);
+ char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ if (STREQ(block->name, block_name)) {
+ BLI_remlink(&region->uiblocks, block);
+ UI_block_free(NULL, block);
+ break; /* Only delete one block for this panel. */
+ }
+ }
+}
+
+/**
+ * Free a panel and it's children.
+ *
+ * \note The only panels that should need to be deleted at runtime are panels with the
+ * #PNL_INSTANCED flag set.
+ */
+static void panel_delete(ARegion *region, ListBase *panels, Panel *panel)
+{
+ /* Recursively delete children. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) {
+ panel_delete(region, &panel->children, child);
+ }
+ BLI_freelistN(&panel->children);
+
+ panel_free_block(region, panel);
+
+ BLI_remlink(panels, panel);
+ if (panel->activedata) {
+ MEM_freeN(panel->activedata);
+ }
+ MEM_freeN(panel);
+}
+
+void UI_panels_free_instanced(bContext *C, ARegion *region)
+{
+ /* Delete panels with the instanced flag. */
+ LISTBASE_FOREACH_MUTABLE (Panel *, panel, &region->panels) {
+ if ((panel->type != NULL) && (panel->type->flag & PNL_INSTANCED)) {
+ /* Make sure the panel's handler is removed before deleting it. */
+ if (panel->activedata != NULL) {
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ }
+ panel_delete(region, &region->panels, panel);
+ }
+ }
+}
+
+/**
+ * Check if the instanced panels in the region's panels correspond to the list of data the panels
+ * represent. Returns false if the panels have been reordered or if the types from the list data
+ * don't match in any way.
+ *
+ * \param data: The list of data to check against the instanced panels.
+ * \param panel_idname_func: Function to find the panel type idname for each item in the data list.
+ * For a readability and generality, this lookup happens separately for each type of panel list.
+ */
+bool UI_panel_list_matches_data(ARegion *region,
+ ListBase *data,
+ uiListPanelIDFromDataFunc panel_idname_func)
+{
+ int data_len = BLI_listbase_count(data);
+ int i = 0;
+ Link *data_link = data->first;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type != NULL && panel->type->flag & PNL_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) {
+ return false;
+ }
+
+ /* Check if the panel type matches the panel type from the data item. */
+ char panel_idname[MAX_NAME];
+ panel_idname_func(data_link, panel_idname);
+ if (!STREQ(panel_idname, panel->type->idname)) {
+ return false;
+ }
+
+ data_link = data_link->next;
+ i++;
+ }
+ }
+
+ /* If we didn't make it to the last list item, the panel list isn't complete. */
+ if (i != data_len) {
+ return false;
+ }
+
+ return true;
+}
+
+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) {
+ return;
+ }
+ /* Don't reorder if this instanced panel doesn't support drag and drop reordering. */
+ if (drag_panel->type->reorder == NULL) {
+ return;
+ }
+
+ char *context = drag_panel->type->context;
+
+ /* Find how many instanced panels with this context string. */
+ int list_panels_len = 0;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ list_panels_len++;
+ }
+ }
+ }
+ }
+
+ /* Sort the matching instanced panels by their display order. */
+ PanelSort *panel_sort = MEM_callocN(list_panels_len * sizeof(*panel_sort), "instancedpanelsort");
+ PanelSort *sort_index = panel_sort;
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type) {
+ if (panel_type_context_poll(panel->type, context)) {
+ if (panel->type->flag & PNL_INSTANCED) {
+ sort_index->panel = MEM_dupallocN(panel);
+ sort_index->orig = panel;
+ sort_index++;
+ }
+ }
+ }
+ }
+ qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel);
+
+ /* Find how many of those panels are above this panel. */
+ int move_to_index = 0;
+ for (; move_to_index < list_panels_len; move_to_index++) {
+ if (panel_sort[move_to_index].orig == drag_panel) {
+ break;
+ }
+ }
+
+ /* Free panel sort array. */
+ int i = 0;
+ for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) {
+ MEM_freeN(sort_index->panel);
+ }
+ MEM_freeN(panel_sort);
+
+ /* Don't reorder the panel didn't change order after being dropped. */
+ if (move_to_index == drag_panel->runtime.list_index) {
+ return;
+ }
+
+ /* Set the bit to tell the interface to instanced the list. */
+ drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED;
+
+ /* Finally, move this panel's list item to the new index in its list. */
+ drag_panel->type->reorder(C, drag_panel, move_to_index);
+}
+
+/**
+ * Recursive implementation for #UI_panel_set_expand_from_list_data.
+ */
+static void panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index)
+{
+ bool open = (flag & (1 << *flag_index));
+ if (open) {
+ panel->flag &= ~PNL_CLOSEDY;
+ }
+ else {
+ panel->flag |= PNL_CLOSEDY;
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ panel_set_expand_from_list_data_recursive(child, flag, flag_index);
+ }
+}
+
+/**
+ * Set the expansion of the panel and its subpanels from the flag stored by the list data
+ * corresponding to this panel. The flag has expansion stored in each bit in depth first
+ * order.
+ */
+void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel)
+{
+ BLI_assert(panel->type != NULL);
+ BLI_assert(panel->type->flag & PNL_INSTANCED);
+ if (panel->type->get_list_data_expand_flag == NULL) {
+ /* Instanced panel doesn't support loading expansion. */
+ return;
+ }
+
+ short expand_flag = panel->type->get_list_data_expand_flag(C, panel);
+ short flag_index = 0;
+ panel_set_expand_from_list_data_recursive(panel, expand_flag, &flag_index);
+}
+
+/**
+ * Recursive implementation for #set_panels_list_data_expand_flag.
+ */
+static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index)
+{
+ bool open = !(panel->flag & PNL_CLOSEDY);
+ if (open) {
+ *flag |= (1 << *flag_index);
+ }
+ else {
+ *flag &= ~(1 << *flag_index);
+ }
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ *flag_index = *flag_index + 1;
+ get_panel_expand_flag(child, flag, flag_index);
+ }
+}
+
+/**
+ * Call the callback to store the panel and subpanel expansion settings in the list item that
+ * corresponds to this panel.
+ *
+ * \note This needs to iterate through all of the regions panels because the panel with changed
+ * expansion could have been the subpanel of a instanced panel, meaning it might not know
+ * which list item it corresponds to.
+ */
+static void set_panels_list_data_expand_flag(const bContext *C, ARegion *region)
+{
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ PanelType *panel_type = panel->type;
+ if (panel_type == NULL) {
+ continue;
+ }
+
+ if (panel->type->flag & PNL_INSTANCED) {
+ short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */
+ short flag_index = 0;
+ get_panel_expand_flag(panel, &expand_flag, &flag_index);
+ if (panel->type->set_list_data_expand_flag) {
+ panel->type->set_list_data_expand_flag(C, panel, expand_flag);
+ }
+ }
+ }
+}
+
/****************************** panels ******************************/
-static void panels_collapse_all(ScrArea *sa, ARegion *region, const Panel *from_pa)
+static void panels_collapse_all(const bContext *C,
+ ScrArea *area,
+ 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 int flag = ((panel_aligned(sa, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY);
- const PanelType *from_pt = from_pa->type;
- Panel *pa;
+ const int flag = ((panel_aligned(area, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY);
+ const PanelType *from_pt = from_panel->type;
+ Panel *panel;
- for (pa = region->panels.first; pa; pa = pa->next) {
- PanelType *pt = pa->type;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ PanelType *pt = panel->type;
/* close panels with headers in the same context */
if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) {
if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) {
- if ((pa->flag & PNL_PIN) || !category || !pt->category[0] ||
+ if ((panel->flag & PNL_PIN) || !category || !pt->category[0] ||
STREQ(pt->category, category)) {
- pa->flag &= ~PNL_CLOSED;
- pa->flag |= flag;
+ panel->flag &= ~PNL_CLOSED;
+ panel->flag |= flag;
}
}
}
}
+ set_panels_list_data_expand_flag(C, region);
+}
+
+static bool panel_type_context_poll(PanelType *panel_type, const char *context)
+{
+ if (panel_type->context[0] && STREQ(panel_type->context, context)) {
+ return true;
+ }
+ return false;
}
Panel *UI_panel_find_by_type(ListBase *lb, PanelType *pt)
{
- Panel *pa;
+ Panel *panel;
const char *idname = pt->idname;
- for (pa = lb->first; pa; pa = pa->next) {
- if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
- return pa;
+ for (panel = lb->first; panel; panel = panel->next) {
+ if (STREQLEN(panel->panelname, idname, sizeof(panel->panelname))) {
+ return panel;
}
}
return NULL;
}
/**
- * \note \a pa should be return value from #UI_panel_find_by_type and can be NULL.
+ * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL.
*/
-Panel *UI_panel_begin(ScrArea *sa,
+Panel *UI_panel_begin(ScrArea *area,
ARegion *region,
ListBase *lb,
uiBlock *block,
PanelType *pt,
- Panel *pa,
+ Panel *panel,
bool *r_open)
{
- Panel *palast, *panext;
+ Panel *panel_last, *panel_next;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
const char *idname = pt->idname;
- const bool newpanel = (pa == NULL);
- int align = panel_aligned(sa, region);
+ const bool newpanel = (panel == NULL);
+ int align = panel_aligned(area, region);
if (!newpanel) {
- pa->type = pt;
+ panel->type = pt;
}
else {
/* new panel */
- pa = MEM_callocN(sizeof(Panel), "new panel");
- pa->type = pt;
- BLI_strncpy(pa->panelname, idname, sizeof(pa->panelname));
+ panel = MEM_callocN(sizeof(Panel), "new panel");
+ panel->type = pt;
+ BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname));
if (pt->flag & PNL_DEFAULT_CLOSED) {
if (align == BUT_VERTICAL) {
- pa->flag |= PNL_CLOSEDY;
+ panel->flag |= PNL_CLOSEDY;
}
else {
- pa->flag |= PNL_CLOSEDX;
+ panel->flag |= PNL_CLOSEDX;
}
}
- pa->ofsx = 0;
- pa->ofsy = 0;
- pa->sizex = 0;
- pa->sizey = 0;
- pa->blocksizex = 0;
- pa->blocksizey = 0;
- pa->runtime_flag |= PNL_NEW_ADDED;
+ panel->ofsx = 0;
+ panel->ofsy = 0;
+ panel->sizex = 0;
+ panel->sizey = 0;
+ panel->blocksizex = 0;
+ panel->blocksizey = 0;
+ panel->runtime_flag |= PNL_NEW_ADDED;
- BLI_addtail(lb, pa);
+ BLI_addtail(lb, panel);
}
/* Do not allow closed panels without headers! Else user could get "disappeared" UI! */
- if ((pt->flag & PNL_NO_HEADER) && (pa->flag & PNL_CLOSED)) {
- pa->flag &= ~PNL_CLOSED;
+ if ((pt->flag & PNL_NO_HEADER) && (panel->flag & PNL_CLOSED)) {
+ panel->flag &= ~PNL_CLOSED;
/* Force update of panels' positions! */
- pa->sizex = 0;
- pa->sizey = 0;
- pa->blocksizex = 0;
- pa->blocksizey = 0;
+ panel->sizex = 0;
+ panel->sizey = 0;
+ panel->blocksizex = 0;
+ panel->blocksizey = 0;
}
- BLI_strncpy(pa->drawname, drawname, sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, drawname, sizeof(panel->drawname));
/* 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 (palast = lb->first; palast; palast = palast->next) {
- if (palast->runtime_flag & PNL_LAST_ADDED) {
- BLI_remlink(lb, pa);
- BLI_insertlinkafter(lb, palast, pa);
+ for (panel_last = lb->first; panel_last; panel_last = panel_last->next) {
+ if (panel_last->runtime_flag & PNL_LAST_ADDED) {
+ BLI_remlink(lb, panel);
+ BLI_insertlinkafter(lb, panel_last, panel);
break;
}
}
if (newpanel) {
- pa->sortorder = (palast) ? palast->sortorder + 1 : 0;
+ panel->sortorder = (panel_last) ? panel_last->sortorder + 1 : 0;
- for (panext = lb->first; panext; panext = panext->next) {
- if (panext != pa && panext->sortorder >= pa->sortorder) {
- panext->sortorder++;
+ for (panel_next = lb->first; panel_next; panel_next = panel_next->next) {
+ if (panel_next != panel && panel_next->sortorder >= panel->sortorder) {
+ panel_next->sortorder++;
}
}
}
- if (palast) {
- palast->runtime_flag &= ~PNL_LAST_ADDED;
+ if (panel_last) {
+ panel_last->runtime_flag &= ~PNL_LAST_ADDED;
}
/* assign to block */
- block->panel = pa;
- pa->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
+ block->panel = panel;
+ panel->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED;
if (region->alignment == RGN_ALIGN_FLOAT) {
UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
}
*r_open = false;
- if (pa->flag & PNL_CLOSED) {
- return pa;
+ if (panel->flag & PNL_CLOSED) {
+ return panel;
}
*r_open = true;
- return pa;
+ return panel;
}
static float panel_region_offset_x_get(const ARegion *region, int align)
@@ -385,16 +730,16 @@ static float panel_region_offset_x_get(const ARegion *region, int align)
}
void UI_panel_end(
- const ScrArea *sa, const ARegion *region, uiBlock *block, int width, int height, bool open)
+ const ScrArea *area, const ARegion *region, uiBlock *block, int width, int height, bool open)
{
- Panel *pa = block->panel;
+ Panel *panel = block->panel;
/* Set panel size excluding children. */
- pa->blocksizex = width;
- pa->blocksizey = height;
+ panel->blocksizex = width;
+ panel->blocksizey = height;
/* Compute total panel size including children. */
- for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
if (pachild->runtime_flag & PNL_ACTIVE) {
width = max_ii(width, pachild->sizex);
height += get_panel_real_size_y(pachild);
@@ -402,32 +747,33 @@ void UI_panel_end(
}
/* Update total panel size. */
- if (pa->runtime_flag & PNL_NEW_ADDED) {
- pa->runtime_flag &= ~PNL_NEW_ADDED;
- pa->sizex = width;
- pa->sizey = height;
+ if (panel->runtime_flag & PNL_NEW_ADDED) {
+ panel->runtime_flag &= ~PNL_NEW_ADDED;
+ panel->sizex = width;
+ panel->sizey = height;
}
else {
- int old_sizex = pa->sizex, old_sizey = pa->sizey;
- int old_region_ofsx = pa->runtime.region_ofsx;
+ int old_sizex = panel->sizex, old_sizey = panel->sizey;
+ int old_region_ofsx = panel->runtime.region_ofsx;
/* update width/height if non-zero */
if (width != 0) {
- pa->sizex = width;
+ panel->sizex = width;
}
if (height != 0 || open) {
- pa->sizey = height;
+ panel->sizey = height;
}
/* check if we need to do an animation */
- if (pa->sizex != old_sizex || pa->sizey != old_sizey) {
- pa->runtime_flag |= PNL_ANIM_ALIGN;
- pa->ofsy += old_sizey - pa->sizey;
+ if (panel->sizex != old_sizex || panel->sizey != old_sizey) {
+ panel->runtime_flag |= PNL_ANIM_ALIGN;
+ panel->ofsy += old_sizey - panel->sizey;
}
- int align = panel_aligned(sa, region);
- if (old_region_ofsx != panel_region_offset_x_get(region, align)) {
- pa->runtime_flag |= PNL_ANIM_ALIGN;
+ int align = panel_aligned(area, region);
+ panel->runtime.region_ofsx = panel_region_offset_x_get(region, align);
+ if (old_region_ofsx != panel->runtime.region_ofsx) {
+ panel->runtime_flag |= PNL_ANIM_ALIGN;
}
}
}
@@ -441,7 +787,7 @@ static void ui_offset_panel_block(uiBlock *block)
int ofsy = block->panel->sizey - style->panelspace;
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
but->rect.ymin += ofsy;
but->rect.ymax += ofsy;
}
@@ -544,59 +890,6 @@ static void ui_draw_panel_scalewidget(uint pos, const rcti *rect)
GPU_blend(false);
}
-static void immRectf_tris_color_ex(
- uint pos, float x1, float y1, float x2, float y2, uint col, const float color[3])
-{
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y2);
-
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y1);
- immAttr4fv(col, color);
- immVertex2f(pos, x2, y2);
- immAttr4fv(col, color);
- immVertex2f(pos, x1, y2);
-}
-
-static void ui_draw_panel_dragwidget(uint pos, uint col, const rctf *rect)
-{
- float col_high[4], col_dark[4];
- const int col_tint = 84;
-
- const int px = (int)U.pixelsize;
- const int px_zoom = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 22.0f), 1);
-
- const int box_margin = max_ii(round_fl_to_int((float)(px_zoom * 2.0f)), px);
- const int box_size = max_ii(round_fl_to_int((BLI_rctf_size_y(rect) / 8.0f) - px), px);
-
- const int x_min = rect->xmin;
- const int y_min = rect->ymin;
- const int y_ofs = max_ii(round_fl_to_int(BLI_rctf_size_y(rect) / 2.5f), px);
- const int x_ofs = y_ofs;
- int i_x, i_y;
-
- UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
- UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
-
- /* draw multiple boxes */
- immBegin(GPU_PRIM_TRIS, 4 * 2 * (6 * 2));
- for (i_x = 0; i_x < 4; i_x++) {
- for (i_y = 0; i_y < 2; i_y++) {
- const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
- const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
-
- immRectf_tris_color_ex(
- pos, x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom, col, col_dark);
- immRectf_tris_color_ex(pos, x_co - box_size, y_co, x_co, y_co + box_size, col, col_high);
- }
- }
- immEnd();
-}
-
/* For button layout next to label. */
void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y)
{
@@ -617,7 +910,7 @@ static void ui_draw_aligned_panel_header(
Panel *panel = block->panel;
rcti hrect;
int pnl_icons;
- const char *activename = panel->drawname[0] ? panel->drawname : panel->panelname;
+ const char *activename = panel->drawname;
const bool is_subpanel = (panel->type && panel->type->parent);
uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle;
uchar col_title[4];
@@ -663,7 +956,6 @@ void ui_draw_aligned_panel(uiStyle *style,
const bool show_background)
{
Panel *panel = block->panel;
- rcti headrect;
rctf itemrect;
float color[4];
const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
@@ -674,11 +966,19 @@ void ui_draw_aligned_panel(uiStyle *style,
* can't be dragged. This may be changed in future. */
show_background);
const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK;
+ const bool draw_box_style = (panel->type && panel->type->flag & (PNL_DRAW_BOX));
+
+ /* Use the theme for box widgets for box-style panels. */
+ uiWidgetColors *box_wcol = NULL;
+ if (draw_box_style) {
+ bTheme *btheme = UI_GetTheme();
+ box_wcol = &btheme->tui.wcol_box;
+ }
+
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
if (show_background) {
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(panel_col);
immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
@@ -687,25 +987,47 @@ void ui_draw_aligned_panel(uiStyle *style,
return;
}
- /* calculate header rect */
- /* + 0.001f to prevent flicker due to float inaccuracy */
- headrect = *rect;
- headrect.ymin = headrect.ymax;
- headrect.ymax = headrect.ymin + floor(PNL_HEADER / block->aspect + 0.001f);
+ /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy */
+ rcti headrect = {
+ rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)};
- rcti titlerect = headrect;
- if (is_subpanel) {
- titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
- }
+ /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */
+ if (draw_box_style && !is_subpanel) {
+ /* Expand the top a tiny bit to give header buttons equal size above and below. */
+ rcti box_rect = {rect->xmin,
+ rect->xmax,
+ (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin,
+ headrect.ymax + U.pixelsize};
+ ui_draw_box_opaque(&box_rect, UI_CNR_ALL);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Mimick the border between aligned box widgets for the bottom of the header. */
+ if (!(is_closed_x || is_closed_y)) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ GPU_blend(true);
+
+ immUniformColor4ubv(box_wcol->outline);
+ immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin);
+ uchar emboss_col[4];
+ UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
+ immUniformColor4ubv(emboss_col);
+ immRectf(pos,
+ rect->xmin,
+ headrect.ymin - U.pixelsize,
+ rect->xmax,
+ headrect.ymin - U.pixelsize - 1);
+
+ GPU_blend(false);
+ immUnbindProgram();
+ }
+ }
- if (show_background && !is_subpanel) {
+ /* Draw the header backdrop. */
+ if (show_background && !is_subpanel && !draw_box_style) {
float minx = rect->xmin;
float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(true);
/* draw with background color */
@@ -723,12 +1045,10 @@ void ui_draw_aligned_panel(uiStyle *style,
immEnd();
GPU_blend(false);
+ immUnbindProgram();
}
- immUnbindProgram();
-
- /* draw optional pin icon */
-
+/* draw optional pin icon */
#ifdef USE_PIN_HIDDEN
if (show_pin && (block->panel->flag & PNL_PIN))
#else
@@ -751,34 +1071,39 @@ void ui_draw_aligned_panel(uiStyle *style,
}
/* horizontal title */
+ rcti titlerect = headrect;
+ if (is_subpanel) {
+ titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f;
+ }
if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background);
if (show_drag) {
- uint col;
- GPUVertFormat *format = immVertexFormat();
- pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
-
/* itemrect smaller */
+ const float scale = 0.7;
itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X);
itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect);
itemrect.ymin = headrect.ymin;
itemrect.ymax = headrect.ymax;
+ BLI_rctf_scale(&itemrect, scale);
- BLI_rctf_scale(&itemrect, 0.7f);
- immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
- ui_draw_panel_dragwidget(pos, col, &itemrect);
- immUnbindProgram();
+ GPU_matrix_push();
+ GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin);
- /* Restore format for the following draws. */
- pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int col_tint = 84;
+ float col_high[4], col_dark[4];
+ UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high);
+ UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark);
+
+ GPUBatch *batch = GPU_batch_preset_panel_drag_widget(
+ U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR);
+ GPU_batch_draw(batch);
+ GPU_matrix_pop();
}
}
- /* if the panel is minimized vertically:
- * (------)
- */
+ /* Draw panel backdrop. */
if (is_closed_y) {
/* skip */
}
@@ -790,12 +1115,19 @@ void ui_draw_aligned_panel(uiStyle *style,
/* an open panel */
else {
/* in some occasions, draw a border */
- if (panel->flag & PNL_SELECT) {
+ if (panel->flag & PNL_SELECT && !is_subpanel) {
+ float radius;
if (panel->control & UI_PNL_SOLID) {
UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = 8.0f;
+ }
+ else if (draw_box_style) {
+ UI_draw_roundbox_corner_set(UI_CNR_ALL);
+ radius = box_wcol->roundness * U.widget_unit;
}
else {
UI_draw_roundbox_corner_set(UI_CNR_NONE);
+ radius = 0.0f;
}
UI_GetThemeColorShade4fv(TH_BACK, -120, color);
@@ -804,18 +1136,40 @@ void ui_draw_aligned_panel(uiStyle *style,
0.5f + rect->ymin,
0.5f + rect->xmax,
0.5f + headrect.ymax + 1,
- 8,
+ radius,
color);
}
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
-
GPU_blend(true);
- if (show_background) {
- /* panel backdrop */
- immUniformThemeColor(panel_col);
- immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ /* Draw panel backdrop if it wasn't already been drawn by the single opaque round box earlier.
+ * Note: Sub-panels blend with panels, so they can't be opaque. */
+ if (show_background && !(draw_box_style && !is_subpanel)) {
+ /* Draw the bottom subpanels . */
+ if (draw_box_style) {
+ if (panel->next) {
+ immUniformThemeColor(panel_col);
+ immRectf(
+ pos, rect->xmin + U.pixelsize, rect->ymin, rect->xmax - U.pixelsize, rect->ymax);
+ }
+ else {
+ /* Change the width a little bit to line up with sides. */
+ UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
+ UI_GetThemeColor4fv(panel_col, color);
+ UI_draw_roundbox_aa(true,
+ rect->xmin + U.pixelsize,
+ rect->ymin + U.pixelsize,
+ rect->xmax - U.pixelsize,
+ rect->ymax,
+ box_wcol->roundness * U.widget_unit,
+ color);
+ }
+ }
+ else {
+ immUniformThemeColor(panel_col);
+ immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ }
}
if (panel->control & UI_PNL_SCALE) {
@@ -867,65 +1221,71 @@ void ui_draw_aligned_panel(uiStyle *style,
/************************** panel alignment *************************/
-static int get_panel_header(const Panel *pa)
+static int get_panel_header(const Panel *panel)
{
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
return 0;
}
return PNL_HEADER;
}
-static int get_panel_size_y(const Panel *pa)
+static int get_panel_size_y(const Panel *panel)
{
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
- return pa->sizey;
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
+ return panel->sizey;
}
- return PNL_HEADER + pa->sizey;
+ return PNL_HEADER + panel->sizey;
}
-static int get_panel_real_size_y(const Panel *pa)
+static int get_panel_real_size_y(const Panel *panel)
{
- int sizey = (pa->flag & PNL_CLOSED) ? 0 : pa->sizey;
+ int sizey = (panel->flag & PNL_CLOSED) ? 0 : panel->sizey;
- if (pa->type && (pa->type->flag & PNL_NO_HEADER)) {
+ if (panel->type && (panel->type->flag & PNL_NO_HEADER)) {
return sizey;
}
return PNL_HEADER + sizey;
}
-int UI_panel_size_y(const Panel *pa)
+int UI_panel_size_y(const Panel *panel)
{
- return get_panel_real_size_y(pa);
+ return get_panel_real_size_y(panel);
}
/* this function is needed because uiBlock and Panel itself don't
* change sizey or location when closed */
-static int get_panel_real_ofsy(Panel *pa)
+static int get_panel_real_ofsy(Panel *panel)
{
- if (pa->flag & PNL_CLOSEDY) {
- return pa->ofsy + pa->sizey;
+ if (panel->flag & PNL_CLOSEDY) {
+ return panel->ofsy + panel->sizey;
}
else {
- return pa->ofsy;
+ return panel->ofsy;
}
}
-static int get_panel_real_ofsx(Panel *pa)
+static int get_panel_real_ofsx(Panel *panel)
{
- if (pa->flag & PNL_CLOSEDX) {
- return pa->ofsx + get_panel_header(pa);
+ if (panel->flag & PNL_CLOSEDX) {
+ return panel->ofsx + get_panel_header(panel);
}
else {
- return pa->ofsx + pa->sizex;
+ return panel->ofsx + panel->sizex;
}
}
-typedef struct PanelSort {
- Panel *pa, *orig;
-} PanelSort;
+bool UI_panel_is_dragging(const struct Panel *panel)
+{
+ uiHandlePanelData *data = panel->activedata;
+ if (!data) {
+ return false;
+ }
+
+ return data->is_drag_drop;
+}
/**
* \note about sorting;
@@ -939,16 +1299,16 @@ static int find_leftmost_panel(const void *a1, const void *a2)
{
const PanelSort *ps1 = a1, *ps2 = a2;
- if (ps1->pa->ofsx > ps2->pa->ofsx) {
+ if (ps1->panel->ofsx > ps2->panel->ofsx) {
return 1;
}
- else if (ps1->pa->ofsx < ps2->pa->ofsx) {
+ else if (ps1->panel->ofsx < ps2->panel->ofsx) {
return -1;
}
- else if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
@@ -961,26 +1321,26 @@ static int find_highest_panel(const void *a1, const void *a2)
/* stick uppermost header-less panels to the top of the region -
* prevent them from being sorted (multiple header-less panels have to be sorted though) */
- if (ps1->pa->type->flag & PNL_NO_HEADER && ps2->pa->type->flag & PNL_NO_HEADER) {
+ if (ps1->panel->type->flag & PNL_NO_HEADER && ps2->panel->type->flag & PNL_NO_HEADER) {
/* skip and check for ofs and sortorder below */
}
- else if (ps1->pa->type->flag & PNL_NO_HEADER) {
+ else if (ps1->panel->type->flag & PNL_NO_HEADER) {
return -1;
}
- else if (ps2->pa->type->flag & PNL_NO_HEADER) {
+ else if (ps2->panel->type->flag & PNL_NO_HEADER) {
return 1;
}
- if (ps1->pa->ofsy + ps1->pa->sizey < ps2->pa->ofsy + ps2->pa->sizey) {
+ if (ps1->panel->ofsy + ps1->panel->sizey < ps2->panel->ofsy + ps2->panel->sizey) {
return 1;
}
- else if (ps1->pa->ofsy + ps1->pa->sizey > ps2->pa->ofsy + ps2->pa->sizey) {
+ else if (ps1->panel->ofsy + ps1->panel->sizey > ps2->panel->ofsy + ps2->panel->sizey) {
return -1;
}
- else if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
@@ -991,24 +1351,24 @@ static int compare_panel(const void *a1, const void *a2)
{
const PanelSort *ps1 = a1, *ps2 = a2;
- if (ps1->pa->sortorder > ps2->pa->sortorder) {
+ if (ps1->panel->sortorder > ps2->panel->sortorder) {
return 1;
}
- else if (ps1->pa->sortorder < ps2->pa->sortorder) {
+ else if (ps1->panel->sortorder < ps2->panel->sortorder) {
return -1;
}
return 0;
}
-static void align_sub_panels(Panel *pa)
+static void align_sub_panels(Panel *panel)
{
/* Position sub panels. */
- int ofsy = pa->ofsy + pa->sizey - pa->blocksizey;
+ int ofsy = panel->ofsy + panel->sizey - panel->blocksizey;
- for (Panel *pachild = pa->children.first; pachild; pachild = pachild->next) {
+ LISTBASE_FOREACH (Panel *, pachild, &panel->children) {
if (pachild->runtime_flag & PNL_ACTIVE) {
- pachild->ofsx = pa->ofsx;
+ pachild->ofsx = panel->ofsx;
pachild->ofsy = ofsy - get_panel_size_y(pachild);
ofsy -= get_panel_real_size_y(pachild);
@@ -1021,17 +1381,17 @@ static void align_sub_panels(Panel *pa)
/* this doesn't draw */
/* returns 1 when it did something */
-static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, const bool drag)
+static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, const bool drag)
{
- Panel *pa;
+ Panel *panel;
PanelSort *ps, *panelsort, *psnext;
int a, tot = 0;
bool done;
- int align = panel_aligned(sa, region);
+ int align = panel_aligned(area, region);
/* count active, not tabbed panels */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
tot++;
}
}
@@ -1041,13 +1401,13 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
}
/* extra; change close direction? */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- if ((pa->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) {
- pa->flag ^= PNL_CLOSED;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) {
+ panel->flag ^= PNL_CLOSED;
}
- else if ((pa->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) {
- pa->flag ^= PNL_CLOSED;
+ else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) {
+ panel->flag ^= PNL_CLOSED;
}
}
}
@@ -1056,10 +1416,10 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort");
ps = panelsort;
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- ps->pa = MEM_dupallocN(pa);
- ps->orig = pa;
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ ps->panel = MEM_dupallocN(panel);
+ ps->orig = panel;
ps++;
}
}
@@ -1084,21 +1444,39 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
/* no smart other default start loc! this keeps switching f5/f6/etc compatible */
ps = panelsort;
- ps->pa->runtime.region_ofsx = panel_region_offset_x_get(region, align);
- ps->pa->ofsx = 0;
- ps->pa->ofsy = -get_panel_size_y(ps->pa);
- ps->pa->ofsx += ps->pa->runtime.region_ofsx;
+ ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region, align);
+ ps->panel->ofsx = 0;
+ ps->panel->ofsy = -get_panel_size_y(ps->panel);
+ ps->panel->ofsx += ps->panel->runtime.region_ofsx;
+ /* Extra margin if the panel is a box style panel. */
+ if (ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX) {
+ ps->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ ps->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
for (a = 0; a < tot - 1; a++, ps++) {
psnext = ps + 1;
if (align == BUT_VERTICAL) {
- psnext->pa->ofsx = ps->pa->ofsx;
- psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - get_panel_size_y(psnext->pa);
+ bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX;
+ bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX;
+ psnext->panel->ofsx = ps->panel->ofsx;
+ psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel);
+ /* Extra margin for box style panels. */
+ if (use_box || use_box_next) {
+ psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ if (use_box && !use_box_next) {
+ psnext->panel->ofsx -= UI_PANEL_BOX_STYLE_MARGIN;
+ }
+ else if (!use_box && use_box_next) {
+ psnext->panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN;
+ }
}
else {
- psnext->pa->ofsx = get_panel_real_ofsx(ps->pa);
- psnext->pa->ofsy = ps->pa->ofsy + get_panel_size_y(ps->pa) - get_panel_size_y(psnext->pa);
+ psnext->panel->ofsx = get_panel_real_ofsx(ps->panel);
+ psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) -
+ get_panel_size_y(psnext->panel);
}
}
@@ -1106,11 +1484,11 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
done = false;
ps = panelsort;
for (a = 0; a < tot; a++, ps++) {
- if ((ps->pa->flag & PNL_SELECT) == 0) {
- if ((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) {
- ps->orig->ofsx = round_fl_to_int(fac * (float)ps->pa->ofsx +
+ if ((ps->panel->flag & PNL_SELECT) == 0) {
+ if ((ps->orig->ofsx != ps->panel->ofsx) || (ps->orig->ofsy != ps->panel->ofsy)) {
+ ps->orig->ofsx = round_fl_to_int(fac * (float)ps->panel->ofsx +
(1.0f - fac) * (float)ps->orig->ofsx);
- ps->orig->ofsy = round_fl_to_int(fac * (float)ps->pa->ofsy +
+ ps->orig->ofsy = round_fl_to_int(fac * (float)ps->panel->ofsy +
(1.0f - fac) * (float)ps->orig->ofsy);
done = true;
}
@@ -1118,42 +1496,42 @@ static bool uiAlignPanelStep(ScrArea *sa, ARegion *region, const float fac, cons
}
/* set locations for tabbed and sub panels */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- if (pa->children.first) {
- align_sub_panels(pa);
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ if (panel->children.first) {
+ align_sub_panels(panel);
}
}
}
/* free panelsort array */
for (ps = panelsort, a = 0; a < tot; a++, ps++) {
- MEM_freeN(ps->pa);
+ MEM_freeN(ps->panel);
}
MEM_freeN(panelsort);
return done;
}
-static void ui_panels_size(ScrArea *sa, ARegion *region, int *r_x, int *r_y)
+static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y)
{
- Panel *pa;
- int align = panel_aligned(sa, region);
+ Panel *panel;
+ int align = panel_aligned(area, region);
int sizex = 0;
int sizey = 0;
/* compute size taken up by panels, for setting in view2d */
- for (pa = region->panels.first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel = region->panels.first; panel; panel = panel->next) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
int pa_sizex, pa_sizey;
if (align == BUT_VERTICAL) {
- pa_sizex = pa->ofsx + pa->sizex;
- pa_sizey = get_panel_real_ofsy(pa);
+ pa_sizex = panel->ofsx + panel->sizex;
+ pa_sizey = get_panel_real_ofsy(panel);
}
else {
- pa_sizex = get_panel_real_ofsx(pa) + pa->sizex;
- pa_sizey = pa->ofsy + get_panel_size_y(pa);
+ pa_sizex = get_panel_real_ofsx(panel) + panel->sizex;
+ pa_sizey = panel->ofsy + get_panel_size_y(panel);
}
sizex = max_ii(sizex, pa_sizex);
@@ -1172,10 +1550,10 @@ static void ui_panels_size(ScrArea *sa, ARegion *region, int *r_x, int *r_y)
*r_y = sizey;
}
-static void ui_do_animate(const bContext *C, Panel *panel)
+static void ui_do_animate(bContext *C, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float fac;
@@ -1183,7 +1561,7 @@ static void ui_do_animate(const bContext *C, Panel *panel)
fac = min_ff(sqrtf(fac), 1.0f);
/* for max 1 second, interpolate positions */
- if (uiAlignPanelStep(sa, region, fac, false)) {
+ if (uiAlignPanelStep(area, region, fac, false)) {
ED_region_tag_redraw(region);
}
else {
@@ -1191,7 +1569,15 @@ static void ui_do_animate(const bContext *C, Panel *panel)
}
if (fac >= 1.0f) {
+ /* Store before data is freed. */
+ const bool is_drag_drop = data->is_drag_drop;
+
panel_activate_state(C, panel, PANEL_STATE_EXIT);
+ if (is_drag_drop) {
+ /* Note: doing this in #panel_activate_state would require removing const for context in many
+ * other places. */
+ reorder_instanced_panel_list(C, region, panel);
+ }
return;
}
}
@@ -1200,15 +1586,15 @@ static void panel_list_clear_active(ListBase *lb)
{
/* set all panels as inactive, so that at the end we know
* which ones were used */
- for (Panel *pa = lb->first; pa; pa = pa->next) {
- if (pa->runtime_flag & PNL_ACTIVE) {
- pa->runtime_flag = PNL_WAS_ACTIVE;
+ LISTBASE_FOREACH (Panel *, panel, lb) {
+ if (panel->runtime_flag & PNL_ACTIVE) {
+ panel->runtime_flag = PNL_WAS_ACTIVE;
}
else {
- pa->runtime_flag = 0;
+ panel->runtime_flag = 0;
}
- panel_list_clear_active(&pa->children);
+ panel_list_clear_active(&panel->children);
}
}
@@ -1220,9 +1606,9 @@ void UI_panels_begin(const bContext *UNUSED(C), ARegion *region)
/* only draws blocks with panels */
void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
uiBlock *block;
- Panel *pa, *firstpa;
+ Panel *panel, *panel_first;
/* offset contents */
for (block = region->uiblocks.first; block; block = block->next) {
@@ -1232,31 +1618,31 @@ void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y)
}
/* re-align, possibly with animation */
- if (panels_need_realign(sa, region, &pa)) {
- if (pa) {
- panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ if (panels_need_realign(area, region, &panel)) {
+ if (panel) {
+ panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
else {
- uiAlignPanelStep(sa, region, 1.0, false);
+ uiAlignPanelStep(area, region, 1.0, false);
}
}
/* tag first panel */
- firstpa = NULL;
+ panel_first = NULL;
for (block = region->uiblocks.first; block; block = block->next) {
if (block->active && block->panel) {
- if (!firstpa || block->panel->sortorder < firstpa->sortorder) {
- firstpa = block->panel;
+ if (!panel_first || block->panel->sortorder < panel_first->sortorder) {
+ panel_first = block->panel;
}
}
}
- if (firstpa) {
- firstpa->runtime_flag |= PNL_FIRST;
+ if (panel_first) {
+ panel_first->runtime_flag |= PNL_FIRST;
}
/* compute size taken up by panel */
- ui_panels_size(sa, region, r_x, r_y);
+ ui_panels_size(area, region, r_x, r_y);
}
void UI_panels_draw(const bContext *C, ARegion *region)
@@ -1305,20 +1691,20 @@ void UI_panels_scale(ARegion *region, float new_width)
static void check_panel_overlap(ARegion *region, Panel *panel)
{
- Panel *pa;
+ Panel *panel_list;
/* also called with (panel == NULL) for clear */
- for (pa = region->panels.first; pa; pa = pa->next) {
- pa->flag &= ~PNL_OVERLAP;
- if (panel && (pa != panel)) {
- if (pa->runtime_flag & PNL_ACTIVE) {
+ for (panel_list = region->panels.first; panel_list; panel_list = panel_list->next) {
+ panel_list->flag &= ~PNL_OVERLAP;
+ if (panel && (panel_list != panel)) {
+ if (panel_list->runtime_flag & PNL_ACTIVE) {
float safex = 0.2, safey = 0.2;
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel_list->flag & PNL_CLOSEDX) {
safex = 0.05;
}
- else if (pa->flag & PNL_CLOSEDY) {
+ else if (panel_list->flag & PNL_CLOSEDY) {
safey = 0.05;
}
else if (panel->flag & PNL_CLOSEDX) {
@@ -1328,11 +1714,12 @@ static void check_panel_overlap(ARegion *region, Panel *panel)
safey = 0.05;
}
- if (pa->ofsx > panel->ofsx - safex * panel->sizex) {
- if (pa->ofsx + pa->sizex < panel->ofsx + (1.0f + safex) * panel->sizex) {
- if (pa->ofsy > panel->ofsy - safey * panel->sizey) {
- if (pa->ofsy + pa->sizey < panel->ofsy + (1.0f + safey) * panel->sizey) {
- pa->flag |= PNL_OVERLAP;
+ if (panel_list->ofsx > panel->ofsx - safex * panel->sizex) {
+ if (panel_list->ofsx + panel_list->sizex < panel->ofsx + (1.0f + safex) * panel->sizex) {
+ if (panel_list->ofsy > panel->ofsy - safey * panel->sizey) {
+ if (panel_list->ofsy + panel_list->sizey <
+ panel->ofsy + (1.0f + safey) * panel->sizey) {
+ panel_list->flag |= PNL_OVERLAP;
}
}
}
@@ -1347,17 +1734,17 @@ static void check_panel_overlap(ARegion *region, Panel *panel)
static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
{
uiHandlePanelData *data = panel->activedata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- short align = panel_aligned(sa, region), dx = 0, dy = 0;
+ short align = panel_aligned(area, region), dx = 0, dy = 0;
/* first clip for window, no dragging outside */
if (!BLI_rcti_isect_pt_v(&region->winrct, &event->x)) {
return;
}
- dx = (event->x - data->startx) & ~(PNL_GRID - 1);
- dy = (event->y - data->starty) & ~(PNL_GRID - 1);
+ dx = (event->x - data->startx);
+ dy = (event->y - data->starty);
dx *= (float)BLI_rctf_size_x(&region->v2d.cur) / (float)BLI_rcti_size_x(&region->winrct);
dy *= (float)BLI_rctf_size_y(&region->v2d.cur) / (float)BLI_rcti_size_y(&region->winrct);
@@ -1381,7 +1768,7 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
check_panel_overlap(region, panel);
if (align) {
- uiAlignPanelStep(sa, region, 0.2, true);
+ uiAlignPanelStep(area, region, 0.2, true);
}
}
@@ -1391,12 +1778,12 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
- const Panel *pa,
+ const Panel *panel,
const int mx,
const int my)
{
/* open panel */
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel->flag & PNL_CLOSEDX) {
if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
return PANEL_MOUSE_INSIDE_HEADER;
}
@@ -1409,8 +1796,8 @@ static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block,
return PANEL_MOUSE_INSIDE_HEADER;
}
/* open panel */
- else if (!(pa->flag & PNL_CLOSEDY)) {
- if (pa->control & UI_PNL_SCALE) {
+ else if (!(panel->flag & PNL_CLOSEDY)) {
+ if (panel->control & UI_PNL_SCALE) {
if (block->rect.xmax - PNL_HEADER <= mx) {
if (block->rect.ymin + PNL_HEADER >= my) {
return PANEL_MOUSE_INSIDE_SCALE;
@@ -1441,22 +1828,22 @@ static void ui_panel_drag_collapse(bContext *C,
uiPanelDragCollapseHandle *dragcol_data,
const int xy_dst[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
uiBlock *block;
- Panel *pa;
+ Panel *panel;
for (block = region->uiblocks.first; block; block = block->next) {
float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
float xy_b_block[2] = {UNPACK2(xy_dst)};
rctf rect = block->rect;
int oldflag;
- const bool is_horizontal = (panel_aligned(sa, region) == BUT_HORIZONTAL);
+ const bool is_horizontal = (panel_aligned(area, region) == BUT_HORIZONTAL);
- if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ if ((panel = block->panel) == 0 || (panel->type && (panel->type->flag & PNL_NO_HEADER))) {
continue;
}
- oldflag = pa->flag;
+ oldflag = panel->flag;
/* lock one axis */
if (is_horizontal) {
@@ -1473,7 +1860,7 @@ static void ui_panel_drag_collapse(bContext *C,
/* set up rect to match header size */
rect.ymin = rect.ymax;
rect.ymax = rect.ymin + PNL_HEADER;
- if (pa->flag & PNL_CLOSEDX) {
+ if (panel->flag & PNL_CLOSEDX) {
rect.xmax = rect.xmin + PNL_HEADER;
}
@@ -1481,19 +1868,21 @@ static void ui_panel_drag_collapse(bContext *C,
if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
/* force panel to close */
if (dragcol_data->was_first_open == true) {
- pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
}
/* force panel to open */
else {
- pa->flag &= ~PNL_CLOSED;
+ panel->flag &= ~PNL_CLOSED;
}
- /* if pa->flag has changed this means a panel was opened/closed here */
- if (pa->flag != oldflag) {
- panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ /* if panel->flag has changed this means a panel was opened/closed here */
+ if (panel->flag != oldflag) {
+ panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
}
}
}
+ /* Update the instanced panel data expand flags with the changes made here. */
+ set_panels_list_data_expand_flag(C, region);
}
/**
@@ -1553,7 +1942,7 @@ static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was
static void ui_handle_panel_header(
const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
#ifdef USE_PIN_HIDDEN
const bool show_pin = UI_panel_category_is_visible(region) &&
@@ -1565,7 +1954,7 @@ static void ui_handle_panel_header(
const bool is_subpanel = (block->panel->type && block->panel->type->parent);
const bool show_drag = !is_subpanel;
- int align = panel_aligned(sa, region), button = 0;
+ int align = panel_aligned(area, region), button = 0;
rctf rect_drag, rect_pin;
float rect_leftmost;
@@ -1620,10 +2009,13 @@ static void ui_handle_panel_header(
}
else { /* collapse */
if (ctrl) {
- panels_collapse_all(sa, region, block->panel);
+ /* Only collapse all for parent panels. */
+ if (block->panel->type != NULL && block->panel->type->parent == NULL) {
+ panels_collapse_all(C, area, region, block->panel);
- /* reset the view - we don't want to display a view without content */
- UI_view2d_offset(&region->v2d, 0.0f, 1.0f);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&region->v2d, 0.0f, 1.0f);
+ }
}
if (block->panel->flag & PNL_CLOSED) {
@@ -1655,6 +2047,8 @@ static void ui_handle_panel_header(
ui_panel_drag_collapse_handler_add(C, true);
}
}
+
+ set_panels_list_data_expand_flag(C, region);
}
if (align) {
@@ -2279,7 +2673,7 @@ int ui_handler_panel_region(bContext *C,
const uiBut *active_but)
{
uiBlock *block;
- Panel *pa;
+ Panel *panel;
int retval, mx, my;
bool has_category_tabs = UI_panel_category_is_visible(region);
@@ -2325,17 +2719,17 @@ int ui_handler_panel_region(bContext *C,
ui_window_to_block(region, block, &mx, &my);
/* checks for mouse position inside */
- pa = block->panel;
+ panel = block->panel;
- if (!pa) {
+ if (!panel) {
continue;
}
/* XXX - accessed freed panels when scripts reload, need to fix. */
- if (pa->type && pa->type->flag & PNL_NO_HEADER) {
+ if (panel->type && panel->type->flag & PNL_NO_HEADER) {
continue;
}
- mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+ mouse_state = ui_panel_mouse_state_get(block, panel, mx, my);
/* XXX hardcoded key warning */
if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) &&
@@ -2343,7 +2737,7 @@ int ui_handler_panel_region(bContext *C,
if (event->type == EVT_AKEY &&
((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
- if (pa->flag & PNL_CLOSEDY) {
+ if (panel->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
}
@@ -2383,8 +2777,8 @@ int ui_handler_panel_region(bContext *C,
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
- panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(panel->flag & PNL_CLOSED)) {
+ panel_activate_state(C, panel, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
}
@@ -2400,7 +2794,7 @@ int ui_handler_panel_region(bContext *C,
/*XXX 2.50*/
#if 0
if (block->handler) {
- rem_blockhandler(sa, block->handler);
+ rem_blockhandler(area, block->handler);
ED_region_tag_redraw(region);
retval = WM_UI_HANDLER_BREAK;
}
@@ -2411,7 +2805,7 @@ int ui_handler_panel_region(bContext *C,
int zoom = 0;
/* if panel is closed, only zoom if mouse is over the header */
- if (pa->flag & (PNL_CLOSEDX | PNL_CLOSEDY)) {
+ if (panel->flag & (PNL_CLOSEDX | PNL_CLOSEDY)) {
if (inside_header) {
zoom = 1;
}
@@ -2421,11 +2815,11 @@ int ui_handler_panel_region(bContext *C,
}
if (zoom) {
- ScrArea *sa = CTX_wm_area(C);
- SpaceLink *sl = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceLink *sl = area->spacedata.first;
- if (sa->spacetype != SPACE_PROPERTIES) {
- if (!(pa->control & UI_PNL_SCALE)) {
+ if (area->spacetype != SPACE_PROPERTIES) {
+ if (!(panel->control & UI_PNL_SCALE)) {
if (event->type == PADPLUSKEY) {
sl->blockscale += 0.1;
}
@@ -2458,9 +2852,9 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
/* verify if we can stop */
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- int align = panel_aligned(sa, region);
+ int align = panel_aligned(area, region);
if (align) {
panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
@@ -2495,14 +2889,32 @@ static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata)
static void ui_handler_remove_panel(bContext *C, void *userdata)
{
- Panel *pa = userdata;
+ Panel *panel = userdata;
- panel_activate_state(C, pa, PANEL_STATE_EXIT);
+ panel_activate_state(C, panel, PANEL_STATE_EXIT);
}
-static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state)
+/**
+ * Set selection state for a panel and its subpanels. The subpanels need to know they are selected
+ * too so they can be drawn above their parent when it is dragged.
+ */
+static void set_panel_selection(Panel *panel, bool value)
{
- uiHandlePanelData *data = pa->activedata;
+ if (value) {
+ panel->flag |= PNL_SELECT;
+ }
+ else {
+ panel->flag &= ~PNL_SELECT;
+ }
+
+ LISTBASE_FOREACH (Panel *, child, &panel->children) {
+ set_panel_selection(child, value);
+ }
+}
+
+static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state)
+{
+ uiHandlePanelData *data = panel->activedata;
wmWindow *win = CTX_wm_window(C);
ARegion *region = CTX_wm_region(C);
@@ -2510,6 +2922,8 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
return;
}
+ bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG);
+
if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
if (data && data->state != PANEL_STATE_ANIMATION) {
/* XXX:
@@ -2522,10 +2936,10 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
check_panel_overlap(region, NULL); /* clears */
}
- pa->flag &= ~PNL_SELECT;
+ set_panel_selection(panel, false);
}
else {
- pa->flag |= PNL_SELECT;
+ set_panel_selection(panel, true);
}
if (data && data->animtimer) {
@@ -2535,18 +2949,18 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
if (state == PANEL_STATE_EXIT) {
MEM_freeN(data);
- pa->activedata = NULL;
+ panel->activedata = NULL;
WM_event_remove_ui_handler(
- &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false);
}
else {
if (!data) {
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
- pa->activedata = data;
+ panel->activedata = data;
WM_event_add_ui_handler(
- C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
+ C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) {
@@ -2556,11 +2970,17 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data->state = state;
data->startx = win->eventstate->x;
data->starty = win->eventstate->y;
- data->startofsx = pa->ofsx;
- data->startofsy = pa->ofsy;
- data->startsizex = pa->sizex;
- data->startsizey = pa->sizey;
+ data->startofsx = panel->ofsx;
+ data->startofsy = panel->ofsy;
+ data->startsizex = panel->sizex;
+ data->startsizey = panel->sizey;
data->starttime = PIL_check_seconds_timer();
+
+ /* Remember drag drop state even when animating to the aligned position after dragging. */
+ data->is_drag_drop = was_drag_drop;
+ if (state == PANEL_STATE_DRAG) {
+ data->is_drag_drop = true;
+ }
}
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index de68b192f67..6d05fe15f97 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -20,6 +20,7 @@
* Utilities to inspect the interface, extract information.
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -160,6 +161,21 @@ bool UI_but_has_tooltip_label(const uiBut *but)
return false;
}
+int ui_but_icon(const uiBut *but)
+{
+ if (!(but->flag & UI_HAS_ICON)) {
+ return ICON_NONE;
+ }
+
+ /* Consecutive icons can be toggle between. */
+ if (but->drawflag & UI_BUT_ICON_REVERSE) {
+ return but->icon - but->iconadd;
+ }
+ else {
+ return but->icon + but->iconadd;
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -260,7 +276,7 @@ uiBut *ui_but_find_mouse_over_ex(ARegion *region, const int x, const int y, cons
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
float mx = x, my = y;
ui_window_to_block_fl(region, block, &mx, &my);
@@ -308,7 +324,7 @@ uiBut *ui_but_find_rect_over(const struct ARegion *region, const rcti *rect_px)
BLI_rctf_rcti_copy(&rect_px_fl, rect_px);
uiBut *butover = NULL;
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
rctf rect_block;
ui_window_to_block_rctf(region, block, &rect_block, &rect_px_fl);
@@ -339,7 +355,7 @@ uiBut *ui_list_find_mouse_over_ex(ARegion *region, int x, int y)
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
float mx = x, my = y;
ui_window_to_block_fl(region, block, &mx, &my);
for (uiBut *but = block->buttons.last; but; but = but->prev) {
@@ -516,7 +532,7 @@ uiBlock *ui_block_find_mouse_over_ex(const ARegion *region,
if (!ui_region_contains_point_px(region, x, y)) {
return NULL;
}
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
if (only_clip) {
if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) {
continue;
@@ -544,8 +560,8 @@ uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, b
uiBut *ui_region_find_active_but(ARegion *region)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (but->active) {
return but;
}
@@ -557,8 +573,8 @@ uiBut *ui_region_find_active_but(ARegion *region)
uiBut *ui_region_find_first_but_test_flag(ARegion *region, int flag_include, int flag_exclude)
{
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
- for (uiBut *but = block->buttons.first; but; but = but->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
if (((but->flag & flag_include) == flag_include) && ((but->flag & flag_exclude) == 0)) {
return but;
}
@@ -632,7 +648,7 @@ bool ui_region_contains_rect_px(const ARegion *region, const rcti *rect_px)
/** Check if the cursor is over any popups. */
ARegion *ui_screen_region_find_mouse_over_ex(bScreen *screen, int x, int y)
{
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
rcti winrct;
ui_region_winrct_get_no_margin(region, &winrct);
diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c
index ecdcd575d5c..f9873f8b96f 100644
--- a/source/blender/editors/interface/interface_region_color_picker.c
+++ b/source/blender/editors/interface/interface_region_color_picker.c
@@ -332,7 +332,7 @@ static void ui_popup_close_cb(bContext *UNUSED(C), void *bt1, void *UNUSED(arg))
static void ui_colorpicker_hide_reveal(uiBlock *block, enum ePickerType colormode)
{
/* tag buttons */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
if ((bt->func == ui_colorpicker_rna_cb) && (bt->type == UI_BTYPE_NUM_SLIDER) &&
(bt->rnaindex != 3)) {
/* RGB sliders (color circle and alpha are always shown) */
diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c
index f77739b5114..1f8af7b9e6e 100644
--- a/source/blender/editors/interface/interface_region_hud.c
+++ b/source/blender/editors/interface/interface_region_hud.c
@@ -74,15 +74,15 @@ static bool last_redo_poll(const bContext *C, short region_type)
* operator call. Otherwise we would be polling the operator with the
* wrong context.
*/
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar_op = (region_type != -1) ? BKE_area_find_region_type(sa, region_type) : NULL;
- ARegion *ar_prev = CTX_wm_region(C);
- CTX_wm_region_set((bContext *)C, ar_op);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region_op = (region_type != -1) ? BKE_area_find_region_type(area, region_type) : NULL;
+ ARegion *region_prev = CTX_wm_region(C);
+ CTX_wm_region_set((bContext *)C, region_op);
if (WM_operator_repeat_check(C, op) && WM_operator_check_ui_empty(op->type) == false) {
success = WM_operator_poll((bContext *)C, op->type);
}
- CTX_wm_region_set((bContext *)C, ar_prev);
+ CTX_wm_region_set((bContext *)C, region_prev);
}
return success;
}
@@ -103,8 +103,8 @@ static void hud_region_hide(ARegion *region)
static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HUD);
if (region != NULL) {
struct HudRegionData *hrd = region->regiondata;
if (hrd != NULL) {
@@ -114,22 +114,22 @@ static bool hud_panel_operator_redo_poll(const bContext *C, PanelType *UNUSED(pt
return false;
}
-static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *pa)
+static void hud_panel_operator_redo_draw_header(const bContext *C, Panel *panel)
{
wmOperator *op = WM_operator_last_redo(C);
- BLI_strncpy(pa->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(panel->drawname));
}
-static void hud_panel_operator_redo_draw(const bContext *C, Panel *pa)
+static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
{
wmOperator *op = WM_operator_last_redo(C);
if (op == NULL) {
return;
}
if (!WM_operator_check_ui_enabled(C, op->type->name)) {
- uiLayoutSetEnabled(pa->layout, false);
+ uiLayoutSetEnabled(panel->layout, false);
}
- uiLayout *col = uiLayoutColumn(pa->layout, false);
+ uiLayout *col = uiLayoutColumn(panel->layout, false);
uiTemplateOperatorRedoProperties(col, C);
}
@@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region)
return;
}
+ ScrArea *area = CTX_wm_area(C);
int size_y = region->sizey;
ED_region_panels_layout(C, region);
- if (region->panels.first && (region->sizey != size_y)) {
+ if (region->panels.first &&
+ ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) {
int winx_new = UI_DPI_FAC * (region->sizex + 0.5f);
int winy_new = UI_DPI_FAC * (region->sizey + 0.5f);
View2D *v2d = &region->v2d;
@@ -250,25 +252,25 @@ ARegionType *ED_area_type_hud(int space_type)
return art;
}
-static ARegion *hud_region_add(ScrArea *sa)
+static ARegion *hud_region_add(ScrArea *area)
{
ARegion *region = MEM_callocN(sizeof(ARegion), "area region");
- ARegion *ar_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar_win) {
- BLI_insertlinkbefore(&sa->regionbase, ar_win, region);
+ ARegion *region_win = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region_win) {
+ BLI_insertlinkbefore(&area->regionbase, region_win, region);
}
else {
- BLI_addtail(&sa->regionbase, region);
+ BLI_addtail(&area->regionbase, region);
}
region->regiontype = RGN_TYPE_HUD;
region->alignment = RGN_ALIGN_FLOAT;
region->overlap = true;
region->flag |= RGN_FLAG_DYNAMIC_SIZE;
- if (ar_win) {
+ if (region_win) {
float x, y;
- UI_view2d_scroller_size_get(&ar_win->v2d, &x, &y);
+ UI_view2d_scroller_size_get(&region_win->v2d, &x, &y);
region->runtime.offset_x = x;
region->runtime.offset_y = y;
}
@@ -276,18 +278,18 @@ static ARegion *hud_region_add(ScrArea *sa)
return region;
}
-void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
+void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *area_keep)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa != sa_keep) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area != area_keep) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_HUD) {
if ((region->flag & RGN_FLAG_HIDDEN) == 0) {
hud_region_hide(region);
ED_region_tag_redraw(region);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
}
@@ -296,17 +298,17 @@ void ED_area_type_hud_clear(wmWindowManager *wm, ScrArea *sa_keep)
}
}
-void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
+void ED_area_type_hud_ensure(bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ED_area_type_hud_clear(wm, sa);
+ ED_area_type_hud_clear(wm, area);
- ARegionType *art = BKE_regiontype_from_id(sa->type, RGN_TYPE_HUD);
+ ARegionType *art = BKE_regiontype_from_id(area->type, RGN_TYPE_HUD);
if (art == NULL) {
return;
}
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_HUD);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_HUD);
if (region && (region->flag & RGN_FLAG_HIDDEN_BY_USER)) {
/* The region is intentionally hidden by the user, don't show it. */
@@ -316,9 +318,9 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
bool init = false;
bool was_hidden = region == NULL || region->visible == false;
- ARegion *ar_op = CTX_wm_region(C);
- BLI_assert((ar_op == NULL) || (ar_op->regiontype != RGN_TYPE_HUD));
- if (!last_redo_poll(C, ar_op ? ar_op->regiontype : -1)) {
+ ARegion *region_op = CTX_wm_region(C);
+ BLI_assert((region_op == NULL) || (region_op->regiontype != RGN_TYPE_HUD));
+ if (!last_redo_poll(C, region_op ? region_op->regiontype : -1)) {
if (region) {
ED_region_tag_redraw(region);
hud_region_hide(region);
@@ -328,18 +330,19 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
if (region == NULL) {
init = true;
- region = hud_region_add(sa);
+ region = hud_region_add(area);
region->type = art;
}
/* Let 'ED_area_update_region_sizes' do the work of placing the region.
* Otherwise we could set the 'region->winrct' & 'region->winx/winy' here. */
if (init) {
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
else {
if (region->flag & RGN_FLAG_HIDDEN) {
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ /* Also forces recalculating HUD size in hud_region_layout(). */
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
region->flag &= ~RGN_FLAG_HIDDEN;
}
@@ -350,8 +353,8 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
hrd = MEM_callocN(sizeof(*hrd), __func__);
region->regiondata = hrd;
}
- if (ar_op) {
- hrd->regionid = ar_op->regiontype;
+ if (region_op) {
+ hrd->regionid = region_op->regiontype;
}
else {
hrd->regionid = -1;
@@ -361,7 +364,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
if (init) {
/* This is needed or 'winrct' will be invalid. */
wmWindow *win = CTX_wm_window(C);
- ED_area_update_region_sizes(wm, win, sa);
+ ED_area_update_region_sizes(wm, win, area);
}
ED_region_floating_initialize(region);
@@ -380,7 +383,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
/* We shouldn't need to do this every time :S */
/* XXX, this is evil! - it also makes the menu show on first draw. :( */
if (region->visible) {
- ARegion *ar_prev = CTX_wm_region(C);
+ ARegion *region_prev = CTX_wm_region(C);
CTX_wm_region_set((bContext *)C, region);
hud_region_layout(C, region);
if (was_hidden) {
@@ -391,7 +394,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *sa)
.ymax = region->winy,
};
}
- CTX_wm_region_set((bContext *)C, ar_prev);
+ CTX_wm_region_set((bContext *)C, region_prev);
}
region->visible = !((region->flag & RGN_FLAG_HIDDEN) || (region->flag & RGN_FLAG_TOO_SMALL));
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index b3c10e8d6b8..3e34b7f3f8a 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -88,11 +88,11 @@ int ui_but_menu_step(uiBut *but, int direction)
return 0;
}
-static uint ui_popup_string_hash(const char *str)
+static uint ui_popup_string_hash(const char *str, const bool use_sep)
{
/* sometimes button contains hotkey, sometimes not, strip for proper compare */
int hash;
- const char *delimit = strrchr(str, UI_SEP_CHAR);
+ const char *delimit = use_sep ? strrchr(str, UI_SEP_CHAR) : NULL;
if (delimit) {
hash = BLI_ghashutil_strhash_n(str, delimit - str);
@@ -126,13 +126,13 @@ static uiBut *ui_popup_menu_memory__internal(uiBlock *block, uiBut *but)
if (but) {
/* set */
- mem[hash_mod] = ui_popup_string_hash(but->str);
+ mem[hash_mod] = ui_popup_string_hash(but->str, but->flag & UI_BUT_HAS_SEP_CHAR);
return NULL;
}
else {
/* get */
for (but = block->buttons.first; but; but = but->next) {
- if (ui_popup_string_hash(but->str) == mem[hash_mod]) {
+ if (mem[hash_mod] == ui_popup_string_hash(but->str, but->flag & UI_BUT_HAS_SEP_CHAR)) {
return but;
}
}
@@ -276,17 +276,17 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
else {
/* for a header menu we set the direction automatic */
if (!pup->slideout && flip) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa && region) {
+ if (area && region) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP);
UI_block_order_flip(block);
}
@@ -581,21 +581,18 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports)
/** \name Popup Block API
* \{ */
-void UI_popup_block_invoke_ex(bContext *C,
- uiBlockCreateFunc func,
- void *arg,
- void (*arg_free)(void *arg),
- const char *opname,
- int opcontext)
+void UI_popup_block_invoke_ex(
+ bContext *C, uiBlockCreateFunc func, void *arg, void (*arg_free)(void *arg), bool can_refresh)
{
wmWindow *window = CTX_wm_window(C);
uiPopupBlockHandle *handle;
handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, arg_free);
handle->popup = true;
- handle->can_refresh = true;
- handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
- handle->opcontext = opcontext;
+
+ /* It can be useful to disable refresh (even though it will work)
+ * as this exists text fields which can be disruptive if refresh isn't needed. */
+ handle->can_refresh = can_refresh;
UI_popup_handlers_add(C, &window->modalhandlers, handle, 0);
UI_block_active_only_flagged_buttons(C, handle->region, handle->region->uiblocks.first);
@@ -607,7 +604,7 @@ void UI_popup_block_invoke(bContext *C,
void *arg,
void (*arg_free)(void *arg))
{
- UI_popup_block_invoke_ex(C, func, arg, arg_free, NULL, WM_OP_INVOKE_DEFAULT);
+ UI_popup_block_invoke_ex(C, func, arg, arg_free, true);
}
void UI_popup_block_ex(bContext *C,
@@ -669,7 +666,7 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
/* In the case we have nested popups,
* closing one may need to redraw another, see: T48874 */
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
ED_region_tag_refresh_ui(region);
}
}
@@ -678,8 +675,8 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block)
bool UI_popup_block_name_exists(const bScreen *screen, const char *name)
{
- for (const ARegion *region = screen->regionbase.first; region; region = region->next) {
- for (const uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (const ARegion *, region, &screen->regionbase) {
+ LISTBASE_FOREACH (const uiBlock *, block, &region->uiblocks) {
if (STREQ(block->name, name)) {
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index b889f1d6d01..0ad7e570e80 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -171,7 +171,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
}
if (!slideout) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
if (region && region->panels.first) {
@@ -180,14 +180,14 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
/* Prefer popover from header to be positioned into the editor. */
- else if (sa && region) {
+ else if (area && region) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_header_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
if (region->regiontype == RGN_TYPE_FOOTER) {
- if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(sa)) == RGN_ALIGN_BOTTOM) {
+ if (RGN_ALIGN_ENUM_FROM_MASK(ED_area_footer_alignment(area)) == RGN_ALIGN_BOTTOM) {
UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
}
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index ba9a5026ce3..2ad7e517c60 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -118,7 +118,7 @@ static void ui_popup_block_position(wmWindow *window,
if (block->buttons.first) {
BLI_rctf_init_minmax(&block->rect);
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) {
bt->rect.xmax += UI_MENU_SUBMENU_PADDING;
}
@@ -294,7 +294,7 @@ static void ui_popup_block_position(wmWindow *window,
}
/* Apply offset, buttons in window coords. */
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect);
BLI_rctf_translate(&bt->rect, offset_x, offset_y);
@@ -420,7 +420,7 @@ static void ui_block_region_draw(const bContext *C, ARegion *region)
* Use to refresh centered popups on screen resizing (for splash).
*/
static void ui_block_region_popup_window_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -525,36 +525,36 @@ void ui_popup_block_scrolltest(uiBlock *block)
static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
wmWindow *ctx_win = CTX_wm_window(C);
- ScrArea *ctx_sa = CTX_wm_area(C);
- ARegion *ctx_ar = CTX_wm_region(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
+ ARegion *ctx_region = CTX_wm_region(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = ctx_win;
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
/* There may actually be a different window active than the one showing the popup, so lookup real
* one. */
- if (BLI_findindex(&sc->regionbase, handle->region) == -1) {
+ if (BLI_findindex(&screen->regionbase, handle->region) == -1) {
for (win = wm->windows.first; win; win = win->next) {
- sc = WM_window_get_active_screen(win);
- if (BLI_findindex(&sc->regionbase, handle->region) != -1) {
+ screen = WM_window_get_active_screen(win);
+ if (BLI_findindex(&screen->regionbase, handle->region) != -1) {
break;
}
}
}
- BLI_assert(win && sc);
+ BLI_assert(win && screen);
CTX_wm_window_set(C, win);
- ui_region_temp_remove(C, sc, handle->region);
+ ui_region_temp_remove(C, screen, handle->region);
/* Reset context (area and region were NULL'ed when chaning context window). */
CTX_wm_window_set(C, ctx_win);
- CTX_wm_area_set(C, ctx_sa);
- CTX_wm_region_set(C, ctx_ar);
+ CTX_wm_area_set(C, ctx_area);
+ CTX_wm_region_set(C, ctx_region);
/* reset to region cursor (only if there's not another menu open) */
- if (BLI_listbase_is_empty(&sc->regionbase)) {
+ if (BLI_listbase_is_empty(&screen->regionbase)) {
win->tag_cursor_refresh = true;
}
@@ -698,7 +698,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
/* lastly set the buttons at the center of the pie menu, ready for animation */
if (U.pie_animation_timeout > 0) {
- for (uiBut *but_iter = block->buttons.first; but_iter; but_iter = but_iter->next) {
+ LISTBASE_FOREACH (uiBut *, but_iter, &block->buttons) {
if (but_iter->pie_dir != UI_RADIAL_NONE) {
BLI_rctf_recenter(&but_iter->rect, UNPACK2(block->pie_data.pie_center_spawned));
}
@@ -742,7 +742,7 @@ uiBlock *ui_popup_block_refresh(bContext *C,
/* apply scroll offset */
if (handle->scrolloffset != 0.0f) {
- for (uiBut *bt = block->buttons.first; bt; bt = bt->next) {
+ LISTBASE_FOREACH (uiBut *, bt, &block->buttons) {
bt->rect.ymin += handle->scrolloffset;
bt->rect.ymax += handle->scrolloffset;
}
@@ -846,7 +846,7 @@ void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
* then close the popover too. We could extend this to other popup types too. */
ARegion *region = handle->popup_create_vars.butregion;
if (region != NULL) {
- for (uiBlock *block = region->uiblocks.first; block; block = block->next) {
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
if (block->handle && (block->flag & UI_BLOCK_POPOVER) &&
(block->flag & UI_BLOCK_KEEP_OPEN) == 0) {
uiPopupBlockHandle *menu = block->handle;
diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c
index 48779fd86dc..0007f6ab9a2 100644
--- a/source/blender/editors/interface/interface_region_search.c
+++ b/source/blender/editors/interface/interface_region_search.c
@@ -28,12 +28,14 @@
#include <stdlib.h>
#include <string.h>
+#include "DNA_ID.h"
#include "MEM_guardedalloc.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -89,9 +91,14 @@ typedef struct uiSearchboxData {
bool noback;
/** draw thumbnail previews, rather than list */
bool preview;
- /** use the UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data) */
+ /** Use the #UI_SEP_CHAR char for splitting shortcuts (good for operators, bad for data). */
bool use_sep;
int prv_rows, prv_cols;
+ /**
+ * Show the active icon and text after the last instance of this string.
+ * Used so we can show leading text to menu items less prominently (not related to 'use_sep').
+ */
+ const char *sep_string;
} uiSearchboxData;
#define SEARCH_ITEMS 10
@@ -147,7 +154,8 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int
/* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set
* which will cause problems, add others as needed. */
- BLI_assert((state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)) == 0);
+ BLI_assert(
+ (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0);
if (items->states) {
items->states[items->totitem] = state;
}
@@ -289,10 +297,31 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region)
}
}
-void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event)
+static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C,
+ struct ARegion *region,
+ int *UNUSED(r_pass),
+ double *UNUSED(pass_delay),
+ bool *r_exit_on_event)
+{
+ *r_exit_on_event = true;
+
+ LISTBASE_FOREACH (uiBlock *, block, &region->uiblocks) {
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ if (but->search && but->search->tooltip_fn) {
+ return but->search->tooltip_fn(C, region, but->search->arg, but->func_arg2);
+ }
+ }
+ }
+ return NULL;
+}
+
+bool ui_searchbox_event(
+ bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event)
{
uiSearchboxData *data = region->regiondata;
int type = event->type, val = event->val;
+ bool handled = false;
+ bool tooltip_timer_started = false;
if (type == MOUSEPAN) {
ui_pan_to_scroll(event, &type, &val);
@@ -302,12 +331,36 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
case WHEELUPMOUSE:
case EVT_UPARROWKEY:
ui_searchbox_select(C, region, but, -1);
+ handled = true;
break;
case WHEELDOWNMOUSE:
case EVT_DOWNARROWKEY:
ui_searchbox_select(C, region, but, 1);
+ handled = true;
+ break;
+ case RIGHTMOUSE:
+ if (val) {
+ if (but->search->context_menu_fn) {
+ if (data->active != -1) {
+ /* Check the cursor is over the active element
+ * (a little confusing if this isn't the case, although it does work). */
+ rcti rect;
+ ui_searchbox_butrect(&rect, data, data->active);
+ if (BLI_rcti_isect_pt(
+ &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+
+ void *active = data->items.pointers[data->active];
+ if (but->search->context_menu_fn(C, but->search->arg, active, event)) {
+ handled = true;
+ }
+ }
+ }
+ }
+ }
break;
- case MOUSEMOVE:
+ case MOUSEMOVE: {
+ bool is_inside = false;
+
if (BLI_rcti_isect_pt(&region->winrct, event->x, event->y)) {
rcti rect;
int a;
@@ -316,16 +369,46 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent
ui_searchbox_butrect(&rect, data, a);
if (BLI_rcti_isect_pt(
&rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) {
+ is_inside = true;
if (data->active != a) {
data->active = a;
ui_searchbox_select(C, region, but, 0);
+ handled = true;
break;
}
}
}
}
+
+ if (U.flag & USER_TOOLTIPS) {
+ if (is_inside) {
+ if (data->active != -1) {
+ ScrArea *area = CTX_wm_area(C);
+ but->func_arg2 = data->items.pointers[data->active];
+ WM_tooltip_timer_init(C, CTX_wm_window(C), area, butregion, wm_searchbox_tooltip_init);
+ tooltip_timer_started = true;
+ }
+ }
+ }
+
break;
+ }
+ }
+
+ if (handled && (tooltip_timer_started == false)) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_tooltip_clear(C, win);
}
+
+ return handled;
+}
+
+/** Wrap #uiButSearchUpdateFn callback. */
+static void ui_searchbox_update_fn(bContext *C, uiBut *but, const char *str, uiSearchItems *items)
+{
+ wmWindow *win = CTX_wm_window(C);
+ WM_tooltip_clear(C, win);
+ but->search->update_fn(C, but->search->arg, str, items);
}
/* region is the search box itself */
@@ -344,9 +427,9 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
data->active = -1;
/* handle active */
- if (but->search_func && but->func_arg2) {
+ if (but->search->update_fn && but->func_arg2) {
data->items.active = but->func_arg2;
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
data->items.active = NULL;
/* found active item, calculate real offset by centering it */
@@ -375,8 +458,8 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re
}
/* callback */
- if (but->search_func) {
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ if (but->search->update_fn) {
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
}
/* handle case where editstr is equal to one of items */
@@ -410,7 +493,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st
if (str[0]) {
data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but));
- but->search_func(C, but->search_arg, but->editstr, &data->items);
+ ui_searchbox_update_fn(C, but, but->editstr, &data->items);
match = UI_autocomplete_end(data->items.autocpl, str);
data->items.autocpl = NULL;
@@ -465,19 +548,50 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region)
}
}
else {
+ const int search_sep_len = data->sep_string ? strlen(data->sep_string) : 0;
/* draw items */
for (a = 0; a < data->items.totitem; a++) {
const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a];
+ char *name = data->items.names[a];
+ int icon = data->items.icons[a];
+ char *name_sep_test = NULL;
ui_searchbox_butrect(&rect, data, a);
/* widget itself */
- ui_draw_menu_item(&data->fstyle,
- &rect,
- data->items.names[a],
- data->items.icons[a],
- state,
- data->use_sep);
+ if ((search_sep_len == 0) ||
+ !(name_sep_test = strstr(data->items.names[a], data->sep_string))) {
+
+ /* Simple menu item. */
+ ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, data->use_sep, NULL);
+ }
+ else {
+ /* Split menu item, faded text before the separator. */
+ char *name_sep = NULL;
+ do {
+ name_sep = name_sep_test;
+ name_sep_test = strstr(name_sep + search_sep_len, data->sep_string);
+ } while (name_sep_test != NULL);
+
+ name_sep += search_sep_len;
+ const char name_sep_prev = *name_sep;
+ *name_sep = '\0';
+ int name_width = 0;
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width);
+ *name_sep = name_sep_prev;
+ rect.xmin += name_width;
+ rect.xmin += UI_UNIT_X / 4;
+
+ if (icon == ICON_BLANK1) {
+ icon = ICON_NONE;
+ rect.xmin -= UI_DPI_ICON_SIZE / 4;
+ }
+
+ /* The previous menu item draws the active selection. */
+ ui_draw_menu_item(
+ &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, data->use_sep, NULL);
+ }
}
/* indicate more */
if (data->items.more) {
@@ -566,6 +680,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but
if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) {
data->use_sep = true;
}
+ data->sep_string = but->search->sep_string;
/* compute position */
if (but->block->flag & UI_BLOCK_SEARCH_MENU) {
@@ -762,9 +877,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
data->items.icons[a],
state,
- false);
+ false,
+ NULL);
ui_draw_menu_item(
- &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
+ &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL);
}
}
/* indicate more */
@@ -842,7 +958,7 @@ void ui_but_search_refresh(uiBut *but)
items->names[x1] = MEM_callocN(but->hardmax + 1, "search names");
}
- but->search_func(but->block->evil_C, but->search_arg, but->drawstr, items);
+ ui_searchbox_update_fn(but->block->evil_C, but, but->drawstr, items);
/* only redalert when we are sure of it, this can miss cases when >10 matches */
if (items->totitem == 0) {
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index cf8ff51eccf..b64f080d9cc 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -42,6 +42,7 @@
#include "DNA_brush_types.h"
#include "DNA_userdef_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
@@ -318,7 +319,7 @@ static bool ui_tooltip_data_append_from_keymap(bContext *C, uiTooltipData *data,
const int fields_len_init = data->fields_len;
char buf[512];
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
if (ot != NULL) {
/* Tip */
@@ -393,15 +394,15 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
bool has_valid_context = true;
const char *has_valid_context_error = IFACE_("Unsupported context");
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
has_valid_context = false;
}
else {
PropertyRNA *prop = RNA_struct_find_property(but->opptr, "space_type");
if (RNA_property_is_set(but->opptr, prop)) {
const int space_type_prop = RNA_property_enum_get(but->opptr, prop);
- if (space_type_prop != sa->spacetype) {
+ if (space_type_prop != area->spacetype) {
has_valid_context = false;
}
}
@@ -596,7 +597,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
else if (BPY_execute_string_as_intptr(C, expr_imports, expr, true, &expr_result)) {
if (expr_result != 0) {
wmKeyMap *keymap = (wmKeyMap *)expr_result;
- for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
if (STREQ(kmi->idname, but->optype->idname)) {
char tool_id_test[MAX_NAME];
RNA_string_get(kmi->ptr, "name", tool_id_test);
@@ -755,7 +756,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
}
}
#else
- UNUSED_VARS(is_label);
+ UNUSED_VARS(is_label, has_valid_context, has_valid_context_error);
#endif /* WITH_PYTHON */
if (data->fields_len == 0) {
@@ -1450,11 +1451,12 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
}
else {
init_position[0] = BLI_rctf_cent_x(&but->rect);
- init_position[1] = but->rect.ymin - (UI_POPUP_MARGIN / 2);
+ init_position[1] = but->rect.ymin;
if (butregion) {
ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
init_position[0] = win->eventstate->x;
}
+ init_position[1] -= (UI_POPUP_MARGIN / 2);
}
ARegion *region = ui_tooltip_create_with_data(
@@ -1480,9 +1482,9 @@ ARegion *UI_tooltip_create_from_gizmo(bContext *C, wmGizmo *gz)
return ui_tooltip_create_with_data(C, data, init_position, NULL, aspect);
}
-void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *region)
+void UI_tooltip_free(bContext *C, bScreen *screen, ARegion *region)
{
- ui_region_temp_remove(C, sc, region);
+ ui_region_temp_remove(C, screen, region);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 2275f3fecdf..9ff58ddd24f 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -39,12 +39,12 @@
#include "interface_regions_intern.h"
-ARegion *ui_region_temp_add(bScreen *sc)
+ARegion *ui_region_temp_add(bScreen *screen)
{
ARegion *region;
region = MEM_callocN(sizeof(ARegion), "area region");
- BLI_addtail(&sc->regionbase, region);
+ BLI_addtail(&screen->regionbase, region);
region->regiontype = RGN_TYPE_TEMPORARY;
region->alignment = RGN_ALIGN_FLOAT;
@@ -52,17 +52,17 @@ ARegion *ui_region_temp_add(bScreen *sc)
return region;
}
-void ui_region_temp_remove(bContext *C, bScreen *sc, ARegion *region)
+void ui_region_temp_remove(bContext *C, bScreen *screen, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
BLI_assert(region->regiontype == RGN_TYPE_TEMPORARY);
- BLI_assert(BLI_findindex(&sc->regionbase, region) != -1);
+ BLI_assert(BLI_findindex(&screen->regionbase, region) != -1);
if (win) {
wm_draw_region_clear(win, region);
}
ED_region_exit(C, region);
BKE_area_region_free(NULL, region); /* NULL: no spacetype */
- BLI_freelinkN(&sc->regionbase, region);
+ BLI_freelinkN(&screen->regionbase, region);
}
diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h
index 329ee3c08dc..c299562a357 100644
--- a/source/blender/editors/interface/interface_regions_intern.h
+++ b/source/blender/editors/interface/interface_regions_intern.h
@@ -27,7 +27,7 @@
uint ui_popup_menu_hash(const char *str);
/* interface_regions_intern.h */
-ARegion *ui_region_temp_add(bScreen *sc);
-void ui_region_temp_remove(struct bContext *C, bScreen *sc, ARegion *region);
+ARegion *ui_region_temp_add(bScreen *screen);
+void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region);
#endif /* __INTERFACE_REGIONS_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 63fc7825b26..e481ec08d72 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -28,7 +28,6 @@
#include "MEM_guardedalloc.h"
-#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
@@ -147,8 +146,9 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params,
size_t len,
- float *r_xofs,
- float *r_yofs)
+ int *r_xofs,
+ int *r_yofs,
+ struct ResultBLF *r_info)
{
int xofs = 0, yofs;
int font_flag = BLF_CLIPPING;
@@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs,
BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f);
BLF_color4ubv(fs->uifont_id, col);
- BLF_draw(fs->uifont_id, str, len);
+ BLF_draw_ex(fs->uifont_id, str, len, r_info);
BLF_disable(fs->uifont_id, font_flag);
@@ -210,9 +210,9 @@ void UI_fontstyle_draw(const uiFontStyle *fs,
const uchar col[4],
const struct uiFontStyleDraw_Params *fs_params)
{
- float xofs, yofs;
+ int xofs, yofs;
- UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
+ UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL);
}
/* drawn same as above, but at 90 degree angle */
diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c
new file mode 100644
index 00000000000..2c6b09168f4
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_search_menu.c
@@ -0,0 +1,1139 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Search available menu items via the user interface & key-maps.
+ * Accessed via the #WM_OT_search_menu operator.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_dynstr.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_listbase.h"
+#include "BLI_math_matrix.h"
+#include "BLI_memarena.h"
+#include "BLI_string.h"
+#include "BLI_string_utils.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+/* For key-map item access. */
+#include "wm_event_system.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Search Template Implementation
+ * \{ */
+
+/* Unicode arrow. */
+#define MENU_SEP "\xe2\x96\xb6"
+
+/**
+ * Use when #menu_items_from_ui_create is called with `include_all_areas`.
+ * so we can run the menu item in the area it was extracted from.
+ */
+struct MenuSearch_Context {
+ /**
+ * Index into `Area.ui_type` #EnumPropertyItem or the top-bar when -1.
+ * Needed to get the display-name to use as a prefix for each menu item.
+ */
+ int space_type_ui_index;
+
+ ScrArea *area;
+ ARegion *region;
+};
+
+struct MenuSearch_Parent {
+ struct MenuSearch_Parent *parent;
+ MenuType *parent_mt;
+ const char *drawstr;
+
+ /** Set while writing menu items only. */
+ struct MenuSearch_Parent *temp_child;
+};
+
+struct MenuSearch_Item {
+ struct MenuSearch_Item *next, *prev;
+ const char *drawstr;
+ const char *drawwstr_full;
+ /** Support a single level sub-menu nesting (for operator buttons that expand). */
+ const char *drawstr_submenu;
+ int icon;
+ int state;
+
+ struct MenuSearch_Parent *menu_parent;
+ MenuType *mt;
+
+ enum {
+ MENU_SEARCH_TYPE_OP = 1,
+ MENU_SEARCH_TYPE_RNA = 2,
+ } type;
+
+ union {
+ /** Operator menu item. */
+ struct {
+ wmOperatorType *type;
+ PointerRNA *opptr;
+ short opcontext;
+ bContextStore *context;
+ } op;
+
+ /** Property (only for check-box/boolean). */
+ struct {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ /** Only for enum buttons. */
+ int enum_value;
+ } rna;
+ };
+
+ /** Set when we need each menu item to be able to set it's own context. may be NULL. */
+ struct MenuSearch_Context *wm_context;
+};
+
+struct MenuSearch_Data {
+ /** MenuSearch_Item */
+ ListBase items;
+ /** Use for all small allocations. */
+ MemArena *memarena;
+
+ /** Use for context menu, to fake a button to create a context menu. */
+ struct {
+ uiBut but;
+ uiBlock block;
+ } context_menu_data;
+};
+
+static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
+{
+ const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
+ const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
+ return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
+}
+
+static const char *strdup_memarena(MemArena *memarena, const char *str)
+{
+ const uint str_size = strlen(str) + 1;
+ char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ memcpy(str_dst, str, str_size);
+ return str_dst;
+}
+
+static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
+{
+ const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
+ char *str_dst = BLI_memarena_alloc(memarena, str_size);
+ BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
+ return str_dst;
+}
+
+static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
+ MemArena *memarena,
+ struct MenuType *mt,
+ const char *drawstr_submenu,
+ uiBut *but,
+ struct MenuSearch_Context *wm_context)
+{
+ struct MenuSearch_Item *item = NULL;
+
+ /* Use override if the name is empty, this can happen with popovers. */
+ const char *drawstr_override = NULL;
+ const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ?
+ strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0');
+
+ if (but->optype != NULL) {
+ if (drawstr_is_empty) {
+ drawstr_override = WM_operatortype_name(but->optype, but->opptr);
+ }
+
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_OP;
+
+ item->op.type = but->optype;
+ item->op.opcontext = but->opcontext;
+ item->op.context = but->context;
+ item->op.opptr = but->opptr;
+ but->opptr = NULL;
+ }
+ else if (but->rnaprop != NULL) {
+ const int prop_type = RNA_property_type(but->rnaprop);
+
+ if (drawstr_is_empty) {
+ if (prop_type == PROP_ENUM) {
+ const int value_enum = (int)but->hardmax;
+ EnumPropertyItem enum_item;
+ if (RNA_property_enum_item_from_value_gettexted(
+ but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) {
+ drawstr_override = enum_item.name;
+ }
+ else {
+ /* Should never happen. */
+ drawstr_override = "Unknown";
+ }
+ }
+ else {
+ drawstr_override = RNA_property_ui_name(but->rnaprop);
+ }
+ }
+
+ if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
+ /* Note that these buttons are not prevented,
+ * but aren't typically used in menus. */
+ printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
+ but->drawstr,
+ mt->idname,
+ prop_type);
+ }
+ else {
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_RNA;
+
+ item->rna.ptr = but->rnapoin;
+ item->rna.prop = but->rnaprop;
+ item->rna.index = but->rnaindex;
+
+ if (prop_type == PROP_ENUM) {
+ item->rna.enum_value = (int)but->hardmax;
+ }
+ }
+ }
+
+ if (item != NULL) {
+ /* Handle shared settings. */
+ if (drawstr_override != NULL) {
+ const char *drawstr_suffix = drawstr_sep ? drawstr_sep : "";
+ char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix);
+ item->drawstr = strdup_memarena(memarena, drawstr_alloc);
+ MEM_freeN(drawstr_alloc);
+ }
+ else {
+ item->drawstr = strdup_memarena(memarena, but->drawstr);
+ }
+
+ item->icon = ui_but_icon(but);
+ item->state = (but->flag &
+ (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR));
+ item->mt = mt;
+ item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
+
+ item->wm_context = wm_context;
+
+ BLI_addtail(&data->items, item);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Populate a fake button from a menu item (use for context menu).
+ */
+static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but)
+{
+ bool changed = false;
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ but->optype = item->op.type;
+ but->opcontext = item->op.opcontext;
+ but->context = item->op.context;
+ but->opptr = item->op.opptr;
+ changed = true;
+ break;
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ const int prop_type = RNA_property_type(item->rna.prop);
+
+ but->rnapoin = item->rna.ptr;
+ but->rnaprop = item->rna.prop;
+ but->rnaindex = item->rna.index;
+
+ if (prop_type == PROP_ENUM) {
+ but->hardmax = item->rna.enum_value;
+ }
+ changed = true;
+ break;
+ }
+ }
+
+ if (changed) {
+ STRNCPY(but->drawstr, item->drawstr);
+ char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ if (drawstr_sep) {
+ *drawstr_sep = '\0';
+ }
+
+ but->icon = item->icon;
+ but->str = but->strdata;
+ }
+
+ return changed;
+}
+
+/**
+ * Populate \a menu_stack with menus from inspecting active key-maps for this context.
+ */
+static void menu_types_add_from_keymap_items(bContext *C,
+ wmWindow *win,
+ ScrArea *area,
+ ARegion *region,
+ LinkNode **menuid_stack_p,
+ GHash *menu_to_kmi,
+ GSet *menu_tagged)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ ListBase *handlers[] = {
+ region ? &region->handlers : NULL,
+ area ? &area->handlers : NULL,
+ &win->handlers,
+ };
+
+ for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
+ if (handlers[handler_index] == NULL) {
+ continue;
+ }
+ LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
+ /* During this loop, UI handlers for nested menus can tag multiple handlers free. */
+ if (handler_base->flag & WM_HANDLER_DO_FREE) {
+ continue;
+ }
+ if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
+ continue;
+ }
+
+ else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
+ wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
+ wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
+ if (keymap && WM_keymap_poll(C, keymap)) {
+ LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
+ if (kmi->flag & KMI_INACTIVE) {
+ continue;
+ }
+ if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
+ char menu_idname[MAX_NAME];
+ RNA_string_get(kmi->ptr, "name", menu_idname);
+ MenuType *mt = WM_menutype_find(menu_idname, false);
+
+ if (mt && BLI_gset_add(menu_tagged, mt)) {
+ /* Unlikely, but possible this will be included twice. */
+ BLI_linklist_prepend(menuid_stack_p, mt);
+
+ void **kmi_p;
+ if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) {
+ *kmi_p = kmi;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Display all operators (last). Developer-only convenience feature.
+ */
+static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data)
+{
+ /* Add to temporary list so we can sort them separately. */
+ ListBase operator_items = {NULL, NULL};
+
+ MemArena *memarena = data->memarena;
+ GHashIterator iter;
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
+ BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+
+ if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
+ continue;
+ }
+
+ if (WM_operator_poll((bContext *)C, ot)) {
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+
+ struct MenuSearch_Item *item = NULL;
+ item = BLI_memarena_calloc(memarena, sizeof(*item));
+ item->type = MENU_SEARCH_TYPE_OP;
+
+ item->op.type = ot;
+ item->op.opcontext = WM_OP_INVOKE_DEFAULT;
+ item->op.context = NULL;
+
+ char idname_as_py[OP_MAX_TYPENAME];
+ char uiname[256];
+ WM_operator_py_idname(idname_as_py, ot->idname);
+
+ SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name);
+
+ item->drawwstr_full = strdup_memarena(memarena, uiname);
+ item->drawstr = ot_ui_name;
+
+ item->wm_context = NULL;
+
+ BLI_addtail(&operator_items, item);
+ }
+ }
+
+ BLI_listbase_sort(&operator_items, menu_item_sort_by_drawstr_full);
+
+ BLI_movelisttolist(&data->items, &operator_items);
+}
+
+/**
+ * Create #MenuSearch_Data by inspecting the current context, this uses two methods:
+ *
+ * - Look-up pre-defined editor-menus.
+ * - Look-up key-map items which call menus.
+ */
+static struct MenuSearch_Data *menu_items_from_ui_create(
+ bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas)
+{
+ MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ /** Map (#MenuType to #MenuSearch_Parent) */
+ GHash *menu_parent_map = BLI_ghash_ptr_new(__func__);
+ GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__);
+ const uiStyle *style = UI_style_get_dpi();
+
+ /* Convert into non-ui structure. */
+ struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
+
+ DynStr *dyn_str = BLI_dynstr_new_memarena();
+
+ /* Use a stack of menus to handle and discover new menus in passes. */
+ LinkNode *menu_stack = NULL;
+
+ /* Tag menu types not to add, either because they have already been added
+ * or they have been blacklisted.
+ * Set of #MenuType. */
+ GSet *menu_tagged = BLI_gset_ptr_new(__func__);
+ /** Map (#MenuType -> #wmKeyMapItem). */
+ GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__);
+
+ /* Blacklist menus we don't want to show. */
+ {
+ const char *idname_array[] = {
+ /* While we could include this, it's just showing filenames to load. */
+ "TOPBAR_MT_file_open_recent",
+ };
+ for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
+ MenuType *mt = WM_menutype_find(idname_array[i], false);
+ if (mt != NULL) {
+ BLI_gset_add(menu_tagged, mt);
+ }
+ }
+ }
+
+ /* Collect contexts, one for each 'ui_type'. */
+ struct MenuSearch_Context *wm_contexts = NULL;
+
+ const EnumPropertyItem *space_type_ui_items = NULL;
+ int space_type_ui_items_len = 0;
+ bool space_type_ui_items_free = false;
+
+ /* Text used as prefix for top-bar menu items. */
+ const char *global_menu_prefix = NULL;
+
+ if (include_all_areas) {
+ /* First create arrays for ui_type. */
+ PropertyRNA *prop_ui_type = NULL;
+ {
+ PointerRNA ptr;
+ RNA_pointer_create(NULL, &RNA_Area, NULL, &ptr);
+ prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
+ RNA_property_enum_items(C,
+ &ptr,
+ prop_ui_type,
+ &space_type_ui_items,
+ &space_type_ui_items_len,
+ &space_type_ui_items_free);
+
+ wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len);
+ for (int i = 0; i < space_type_ui_items_len; i++) {
+ wm_contexts[i].space_type_ui_index = -1;
+ }
+ }
+
+ bScreen *screen = WM_window_get_active_screen(win);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region != NULL) {
+ PointerRNA ptr;
+ RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr);
+ const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type);
+
+ int space_type_ui_index = RNA_enum_from_value(space_type_ui_items, space_type_ui);
+ if (space_type_ui_index == -1) {
+ continue;
+ }
+
+ if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) {
+ ScrArea *area_best = wm_contexts[space_type_ui_index].area;
+ const uint value_best = (uint)area_best->winx * (uint)area_best->winy;
+ const uint value_test = (uint)area->winx * (uint)area->winy;
+ if (value_best > value_test) {
+ continue;
+ }
+ }
+
+ wm_contexts[space_type_ui_index].space_type_ui_index = space_type_ui_index;
+ wm_contexts[space_type_ui_index].area = area;
+ wm_contexts[space_type_ui_index].region = region;
+ }
+ }
+
+ global_menu_prefix = CTX_IFACE_(RNA_property_translation_context(prop_ui_type), "Top Bar");
+ }
+
+ GHashIterator iter;
+
+ for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len;
+ space_type_ui_index += 1) {
+
+ ScrArea *area = NULL;
+ ARegion *region = NULL;
+ struct MenuSearch_Context *wm_context = NULL;
+
+ if (include_all_areas) {
+ if (space_type_ui_index == -1) {
+ /* First run without any context, to populate the top-bar without. */
+ wm_context = NULL;
+ area = NULL;
+ region = NULL;
+ }
+ else {
+ wm_context = &wm_contexts[space_type_ui_index];
+ if (wm_context->space_type_ui_index == -1) {
+ continue;
+ }
+
+ area = wm_context->area;
+ region = wm_context->region;
+
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+ }
+ }
+ else {
+ area = area_init;
+ region = region_init;
+ }
+
+ /* Populate menus from the editors,
+ * note that we could create a fake header, draw the header and extract the menus
+ * from the buttons, however this is quite involved and can be avoided as by convention
+ * each space-type has a single root-menu that headers use. */
+ {
+ const char *idname_array[2] = {NULL};
+ int idname_array_len = 0;
+
+ /* Use negative for global (no area) context, populate the top-bar. */
+ if (space_type_ui_index == -1) {
+ idname_array[idname_array_len++] = "TOPBAR_MT_editor_menus";
+ }
+
+#define SPACE_MENU_MAP(space_type, menu_id) \
+ case space_type: \
+ idname_array[idname_array_len++] = menu_id; \
+ break
+#define SPACE_MENU_NOP(space_type) \
+ case space_type: \
+ break
+
+ if (area != NULL) {
+ SpaceLink *sl = area->spacedata.first;
+ switch ((eSpace_Type)area->spacetype) {
+ SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
+ SPACE_MENU_NOP(SPACE_PROPERTIES);
+ SPACE_MENU_MAP(SPACE_FILE, "FILEBROWSER_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_ACTION,
+ (((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ?
+ "TIME_MT_editor_menus" :
+ "DOPESHEET_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
+ SPACE_MENU_MAP(SPACE_CLIP,
+ (((const SpaceClip *)sl)->mode == SC_MODE_TRACKING) ?
+ "CLIP_MT_tracking_editor_menus" :
+ "CLIP_MT_masking_editor_menus");
+ SPACE_MENU_NOP(SPACE_EMPTY);
+ SPACE_MENU_NOP(SPACE_SCRIPT);
+ SPACE_MENU_NOP(SPACE_STATUSBAR);
+ SPACE_MENU_NOP(SPACE_TOPBAR);
+ }
+ }
+ for (int i = 0; i < idname_array_len; i++) {
+ MenuType *mt = WM_menutype_find(idname_array[i], false);
+ if (mt != NULL) {
+ /* Check if this exists because of 'include_all_areas'. */
+ if (BLI_gset_add(menu_tagged, mt)) {
+ BLI_linklist_prepend(&menu_stack, mt);
+ }
+ }
+ }
+ }
+#undef SPACE_MENU_MAP
+#undef SPACE_MENU_NOP
+
+ bool has_keymap_menu_items = false;
+
+ while (menu_stack != NULL) {
+ MenuType *mt = BLI_linklist_pop(&menu_stack);
+ if (!WM_menutype_poll(C, mt)) {
+ continue;
+ }
+
+ uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
+ uiLayout *layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+
+ UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
+
+ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
+ UI_menutype_draw(C, mt, layout);
+
+ UI_block_end(C, block);
+
+ LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
+ MenuType *mt_from_but = NULL;
+ /* Support menu titles with dynamic from initial labels
+ * (used by edit-mesh context menu). */
+ if (but->type == UI_BTYPE_LABEL) {
+
+ /* Check if the label is the title. */
+ uiBut *but_test = but->prev;
+ while (but_test && but_test->type == UI_BTYPE_SEPR) {
+ but_test = but_test->prev;
+ }
+
+ if (but_test == NULL) {
+ BLI_ghash_insert(
+ menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
+ }
+ }
+ else if (menu_items_from_ui_create_item_from_button(
+ data, memarena, mt, NULL, but, wm_context)) {
+ /* pass */
+ }
+ else if ((mt_from_but = UI_but_menutype_get(but))) {
+
+ if (BLI_gset_add(menu_tagged, mt_from_but)) {
+ BLI_linklist_prepend(&menu_stack, mt_from_but);
+ }
+
+ if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
+ struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
+ sizeof(*menu_parent));
+ /* Use brackets for menu key shortcuts,
+ * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
+ * This is needed so we don't right align sub-menu contents
+ * we only want to do that for the last menu item, not the path that leads to it.
+ */
+ const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
+ strrchr(but->drawstr, UI_SEP_CHAR) :
+ NULL;
+ bool drawstr_is_empty = false;
+ if (drawstr_sep != NULL) {
+ BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
+ /* Detect empty string, fallback to menu name. */
+ const char *drawstr = but->drawstr;
+ int drawstr_len = drawstr_sep - but->drawstr;
+ if (UNLIKELY(drawstr_len == 0)) {
+ drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
+ drawstr_len = strlen(drawstr);
+ if (drawstr[0] == '\0') {
+ drawstr_is_empty = true;
+ }
+ }
+ BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
+ BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
+ menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
+ BLI_dynstr_clear(dyn_str);
+ }
+ else {
+ const char *drawstr = but->drawstr;
+ if (UNLIKELY(drawstr[0] == '\0')) {
+ drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
+ if (drawstr[0] == '\0') {
+ drawstr_is_empty = true;
+ }
+ }
+ menu_parent->drawstr = strdup_memarena(memarena, drawstr);
+ }
+ menu_parent->parent_mt = mt;
+ BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent);
+
+ if (drawstr_is_empty) {
+ printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
+ }
+ }
+ }
+ else if (but->menu_create_func != NULL) {
+ /* A non 'MenuType' menu button. */
+
+ /* Only expand one level deep, this is mainly for expanding operator menus. */
+ const char *drawstr_submenu = but->drawstr;
+
+ /* +1 to avoid overlap with the current 'block'. */
+ uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
+ uiLayout *sub_layout = UI_block_layout(
+ sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
+
+ UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
+
+ uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN);
+
+ but->menu_create_func(C, sub_layout, but->poin);
+
+ UI_block_end(C, sub_block);
+
+ LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
+ menu_items_from_ui_create_item_from_button(
+ data, memarena, mt, drawstr_submenu, sub_but, wm_context);
+ }
+
+ if (region) {
+ BLI_remlink(&region->uiblocks, sub_block);
+ }
+ UI_block_free(NULL, sub_block);
+ }
+ }
+ if (region) {
+ BLI_remlink(&region->uiblocks, block);
+ }
+ UI_block_free(NULL, block);
+
+ /* Add key-map items as a second pass,
+ * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
+ if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
+ has_keymap_menu_items = true;
+ menu_types_add_from_keymap_items(
+ C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged);
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
+ }
+
+ GHASH_ITER (iter, menu_parent_map) {
+ struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
+ menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
+ }
+
+ /* NOTE: currently this builds the full path for each menu item,
+ * that could be moved into the parent menu. */
+
+ /* Set names as full paths. */
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
+
+ if (include_all_areas) {
+ BLI_dynstr_appendf(dyn_str,
+ "%s: ",
+ (item->wm_context != NULL) ?
+ space_type_ui_items[item->wm_context->space_type_ui_index].name :
+ global_menu_prefix);
+ }
+
+ if (item->menu_parent != NULL) {
+ struct MenuSearch_Parent *menu_parent = item->menu_parent;
+ menu_parent->temp_child = NULL;
+ while (menu_parent && menu_parent->parent) {
+ menu_parent->parent->temp_child = menu_parent;
+ menu_parent = menu_parent->parent;
+ }
+ while (menu_parent) {
+ BLI_dynstr_append(dyn_str, menu_parent->drawstr);
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ menu_parent = menu_parent->temp_child;
+ }
+ }
+ else {
+ const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
+ if (drawstr == NULL) {
+ drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
+ }
+ BLI_dynstr_append(dyn_str, drawstr);
+
+ wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
+ if (kmi != NULL) {
+ char kmi_str[128];
+ WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
+ BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
+ }
+
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ }
+
+ /* Optional nested menu. */
+ if (item->drawstr_submenu != NULL) {
+ BLI_dynstr_append(dyn_str, item->drawstr_submenu);
+ BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
+ }
+
+ BLI_dynstr_append(dyn_str, item->drawstr);
+
+ item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
+ BLI_dynstr_clear(dyn_str);
+ }
+ BLI_dynstr_free(dyn_str);
+
+ /* Finally sort menu items.
+ *
+ * Note: we might want to keep the in-menu order, for now sort all. */
+ BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
+
+ BLI_ghash_free(menu_parent_map, NULL, NULL);
+ BLI_ghash_free(menu_display_name_map, NULL, NULL);
+
+ BLI_ghash_free(menu_to_kmi, NULL, NULL);
+
+ BLI_gset_free(menu_tagged, NULL);
+
+ data->memarena = memarena;
+
+ if (include_all_areas) {
+ CTX_wm_area_set(C, area_init);
+ CTX_wm_region_set(C, region_init);
+
+ if (space_type_ui_items_free) {
+ MEM_freeN((void *)space_type_ui_items);
+ }
+ }
+
+ /* Include all operators for developers,
+ * since it can be handy to have a quick way to access any operator,
+ * including operators being developed which haven't yet been added into the interface.
+ *
+ * These are added after all menu items so developers still get normal behavior by default,
+ * unless searching for something that isn't already in a menu (or scroll down).
+ *
+ * Keep this behind a developer only check:
+ * - Many operators need options to be set to give useful results, see: T74157.
+ * - User who really prefer to list all operators can use #WM_OT_search_operator.
+ */
+ if (U.flag & USER_DEVELOPER_UI) {
+ menu_items_from_all_operators(C, data);
+ }
+
+ return data;
+}
+
+static void menu_search_arg_free_fn(void *data_v)
+{
+ struct MenuSearch_Data *data = data_v;
+ LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ if (item->op.opptr != NULL) {
+ WM_operator_properties_free(item->op.opptr);
+ MEM_freeN(item->op.opptr);
+ }
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ break;
+ }
+ }
+ }
+
+ BLI_memarena_free(data->memarena);
+
+ MEM_freeN(data);
+}
+
+static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
+{
+ struct MenuSearch_Item *item = arg2;
+ if (item == NULL) {
+ return;
+ }
+ if (item->state & UI_BUT_DISABLED) {
+ return;
+ }
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ switch (item->type) {
+ case MENU_SEARCH_TYPE_OP: {
+ CTX_store_set(C, item->op.context);
+ WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
+ CTX_store_set(C, NULL);
+ break;
+ }
+ case MENU_SEARCH_TYPE_RNA: {
+ PointerRNA *ptr = &item->rna.ptr;
+ PropertyRNA *prop = item->rna.prop;
+ int index = item->rna.index;
+ const int prop_type = RNA_property_type(prop);
+ bool changed = false;
+
+ if (prop_type == PROP_BOOLEAN) {
+ const bool is_array = RNA_property_array_check(prop);
+ if (is_array) {
+ const bool value = RNA_property_boolean_get_index(ptr, prop, index);
+ RNA_property_boolean_set_index(ptr, prop, index, !value);
+ }
+ else {
+ const bool value = RNA_property_boolean_get(ptr, prop);
+ RNA_property_boolean_set(ptr, prop, !value);
+ }
+ changed = true;
+ }
+ else if (prop_type == PROP_ENUM) {
+ RNA_property_enum_set(ptr, prop, item->rna.enum_value);
+ changed = true;
+ }
+
+ if (changed) {
+ RNA_property_update(C, ptr, prop);
+ }
+ break;
+ }
+ }
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+}
+
+static void menu_search_update_fn(const bContext *UNUSED(C),
+ void *arg,
+ const char *str,
+ uiSearchItems *items)
+{
+ struct MenuSearch_Data *data = arg;
+ const size_t str_len = strlen(str);
+ const int words_max = (str_len / 2) + 1;
+ int(*words)[2] = BLI_array_alloca(words, words_max);
+
+ const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+
+ for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) {
+ int index;
+
+ /* match name against all search words */
+ for (index = 0; index < words_len; index++) {
+ if (!ui_str_has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) {
+ break;
+ }
+ }
+
+ if (index == words_len) {
+ if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) {
+ break;
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Menu
+ *
+ * This uses a fake button to create a context menu,
+ * if this ever causes hard to solve bugs we may need to create
+ * a separate context menu just for the search, however this is fairly involved.
+ * \{ */
+
+static bool ui_search_menu_create_context_menu(struct bContext *C,
+ void *arg,
+ void *active,
+ const struct wmEvent *UNUSED(event))
+{
+ struct MenuSearch_Data *data = arg;
+ struct MenuSearch_Item *item = active;
+ bool has_menu = false;
+
+ memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
+ uiBut *but = &data->context_menu_data.but;
+ uiBlock *block = &data->context_menu_data.block;
+
+ but->block = block;
+
+ if (menu_items_to_ui_button(item, but)) {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ if (ui_popup_context_menu_for_button(C, but)) {
+ has_menu = true;
+ }
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+ }
+
+ return has_menu;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Tooltip
+ * \{ */
+
+static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C,
+ struct ARegion *region,
+ void *arg,
+ void *active)
+{
+ struct MenuSearch_Data *data = arg;
+ struct MenuSearch_Item *item = active;
+
+ memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data));
+ uiBut *but = &data->context_menu_data.but;
+ uiBlock *block = &data->context_menu_data.block;
+ unit_m4(block->winmat);
+ block->aspect = 1;
+
+ but->block = block;
+
+ /* Place the fake button at the cursor so the tool-tip is places properly. */
+ float tip_init[2];
+ const wmEvent *event = CTX_wm_window(C)->eventstate;
+ tip_init[0] = event->x;
+ tip_init[1] = event->y - (UI_UNIT_Y / 2);
+ ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]);
+
+ but->rect.xmin = tip_init[0];
+ but->rect.xmax = tip_init[0];
+ but->rect.ymin = tip_init[1];
+ but->rect.ymax = tip_init[1];
+
+ if (menu_items_to_ui_button(item, but)) {
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *region_prev = CTX_wm_region(C);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, item->wm_context->area);
+ CTX_wm_region_set(C, item->wm_context->region);
+ }
+
+ ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false);
+
+ if (item->wm_context != NULL) {
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, region_prev);
+ }
+ return region_tip;
+ }
+
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Search Template Public API
+ * \{ */
+
+void UI_but_func_menu_search(uiBut *but)
+{
+ bContext *C = but->block->evil_C;
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ /* When run from top-bar scan all areas in the current window. */
+ bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR));
+ struct MenuSearch_Data *data = menu_items_from_ui_create(
+ C, win, area, region, include_all_areas);
+ UI_but_func_search_set(but,
+ /* Generic callback. */
+ ui_searchbox_create_menu,
+ menu_search_update_fn,
+ data,
+ menu_search_arg_free_fn,
+ menu_search_exec_fn,
+ NULL);
+
+ UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu);
+ UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip);
+ UI_but_func_search_set_sep_string(but, MENU_SEP);
+}
+
+void uiTemplateMenuSearch(uiLayout *layout)
+{
+ uiBlock *block;
+ uiBut *but;
+ static char search[256] = "";
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_layout_set_current(block, layout);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
+ UI_but_func_menu_search(but);
+}
+
+#undef MENU_SEP
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.c
new file mode 100644
index 00000000000..cdf87103587
--- /dev/null
+++ b/source/blender/editors/interface/interface_template_search_operator.c
@@ -0,0 +1,151 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Search available operators by scanning all and checking their poll function.
+ * accessed via the #WM_OT_search_operator operator.
+ */
+
+#include <string.h>
+
+#include "DNA_gpencil_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_shader_fx_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_global.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "interface_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template Implementation
+ * \{ */
+
+static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2)
+{
+ wmOperatorType *ot = arg2;
+
+ if (ot) {
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
+ }
+}
+
+static void operator_search_update_fn(const bContext *C,
+ void *UNUSED(arg),
+ const char *str,
+ uiSearchItems *items)
+{
+ GHashIterator iter;
+ const size_t str_len = strlen(str);
+ const int words_max = (str_len / 2) + 1;
+ int(*words)[2] = BLI_array_alloca(words, words_max);
+
+ const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
+
+ for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
+ BLI_ghashIterator_step(&iter)) {
+ wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
+ const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
+ int index;
+
+ if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
+ continue;
+ }
+
+ /* match name against all search words */
+ for (index = 0; index < words_len; index++) {
+ if (!ui_str_has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) {
+ break;
+ }
+ }
+
+ if (index == words_len) {
+ if (WM_operator_poll((bContext *)C, ot)) {
+ char name[256];
+ int len = strlen(ot_ui_name);
+
+ /* display name for menu, can hold hotkey */
+ BLI_strncpy(name, ot_ui_name, sizeof(name));
+
+ /* check for hotkey */
+ if (len < sizeof(name) - 6) {
+ if (WM_key_event_operator_string(C,
+ ot->idname,
+ WM_OP_EXEC_DEFAULT,
+ NULL,
+ true,
+ &name[len + 1],
+ sizeof(name) - len - 1)) {
+ name[len] = UI_SEP_CHAR;
+ }
+ }
+
+ if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Operator Search Template API
+ * \{ */
+
+void UI_but_func_operator_search(uiBut *but)
+{
+ UI_but_func_search_set(but,
+ ui_searchbox_create_operator,
+ operator_search_update_fn,
+ NULL,
+ false,
+ operator_search_exec_fn,
+ NULL);
+}
+
+void uiTemplateOperatorSearch(uiLayout *layout)
+{
+ uiBlock *block;
+ uiBut *but;
+ static char search[256] = "";
+
+ block = uiLayoutGetBlock(layout);
+ UI_block_layout_set_current(block, layout);
+
+ but = uiDefSearchBut(
+ block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
+ UI_but_func_operator_search(but);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index d7377a0e56e..6001e1ea1b5 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -37,18 +37,12 @@
#include "DNA_shader_fx_types.h"
#include "DNA_texture_types.h"
-#include "BLI_alloca.h"
-#include "BLI_dynstr.h"
#include "BLI_fnmatch.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_memarena.h"
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
-#include "BLI_string_utils.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
@@ -73,7 +67,6 @@
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_packedFile.h"
-#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_report.h"
#include "BKE_scene.h"
@@ -103,9 +96,6 @@
#include "PIL_time.h"
-/* For key-map item access. */
-#include "wm_event_system.h"
-
// #define USE_OP_RESET_BUT // we may want to make this optional, disable for now.
/* defines for templateID/TemplateSearch */
@@ -213,9 +203,9 @@ static void template_add_button_search_menu(const bContext *C,
static uiBlock *template_common_search_menu(const bContext *C,
ARegion *region,
- uiButSearchFunc search_func,
+ uiButSearchUpdateFn search_update_fn,
void *search_arg,
- uiButHandleFunc handle_func,
+ uiButHandleFunc search_exec_fn,
void *active_item,
const int preview_rows,
const int preview_cols,
@@ -287,8 +277,13 @@ static uiBlock *template_common_search_menu(const bContext *C,
0,
"");
}
- UI_but_func_search_set(
- but, ui_searchbox_create_generic, search_func, search_arg, NULL, handle_func, active_item);
+ UI_but_func_search_set(but,
+ ui_searchbox_create_generic,
+ search_update_fn,
+ search_arg,
+ NULL,
+ search_exec_fn,
+ active_item);
UI_block_bounds_set_normal(block, 0.3f * U.widget_unit);
UI_block_direction_set(block, UI_DIR_DOWN);
@@ -320,7 +315,7 @@ typedef struct TemplateID {
} TemplateID;
/* Search browse menu, assign */
-static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item)
+static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item)
{
TemplateID *template_ui = (TemplateID *)arg_template;
@@ -455,7 +450,8 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
{
static TemplateID template_ui;
PointerRNA active_item_ptr;
- void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
+ void (*id_search_update_fn)(
+ const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
/* arg_litem is malloced, can be freed by parent button */
template_ui = *((TemplateID *)arg_litem);
@@ -465,16 +461,16 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem)
/* Currently only used for objects. */
if (template_ui.idcode == ID_OB) {
if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
- id_search_cb_p = id_search_cb_objects_from_scene;
+ id_search_update_fn = id_search_cb_objects_from_scene;
}
}
}
return template_common_search_menu(C,
region,
- id_search_cb_p,
+ id_search_update_fn,
&template_ui,
- template_ID_set_property_cb,
+ template_ID_set_property_exec_fn,
active_item_ptr.data,
template_ui.prv_rows,
template_ui.prv_cols,
@@ -530,6 +526,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
if (id && CTX_wm_window(C)->eventstate->shift) {
/* only way to force-remove data (on save) */
+ id_us_clear_real(id);
id_fake_user_clear(id);
id->us = 0;
}
@@ -681,6 +678,8 @@ static const char *template_id_browse_tip(const StructRNA *type)
return N_("Browse Point Cloud Data to be linked");
case ID_VO:
return N_("Browse Volume Data to be linked");
+ case ID_SIM:
+ return N_("Browse Simulation to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -698,6 +697,8 @@ static const char *template_id_context(StructRNA *type)
}
return BLT_I18NCONTEXT_DEFAULT;
}
+#else
+# define template_id_context(type) 0
#endif
static uiBut *template_id_def_new_but(uiBlock *block,
@@ -746,7 +747,8 @@ static uiBut *template_id_def_new_but(uiBlock *block,
BLT_I18NCONTEXT_ID_LIGHTPROBE,
BLT_I18NCONTEXT_ID_HAIR,
BLT_I18NCONTEXT_ID_POINTCLOUD,
- BLT_I18NCONTEXT_ID_VOLUME, );
+ BLT_I18NCONTEXT_ID_VOLUME,
+ BLT_I18NCONTEXT_ID_SIMULATION, );
/* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters,
* check the definition to see if a new call must be added when the limit
* is exceeded. */
@@ -797,7 +799,7 @@ static uiBut *template_id_def_new_but(uiBlock *block,
return but;
}
-static void template_ID(bContext *C,
+static void template_ID(const bContext *C,
uiLayout *layout,
TemplateID *template_ui,
StructRNA *type,
@@ -831,7 +833,7 @@ static void template_ID(bContext *C,
if (text) {
/* Add label resepecting the separated layout property split state. */
- layout = uiItemL_respect_property_split(layout, text, ICON_NONE);
+ uiItemL_respect_property_split(layout, text, ICON_NONE);
}
if (flag & UI_ID_BROWSE) {
@@ -1138,7 +1140,7 @@ ID *UI_context_active_but_get_tab_ID(bContext *C)
}
}
-static void template_ID_tabs(bContext *C,
+static void template_ID_tabs(const bContext *C,
uiLayout *layout,
TemplateID *template,
StructRNA *type,
@@ -1148,7 +1150,7 @@ static void template_ID_tabs(bContext *C,
{
const ARegion *region = CTX_wm_region(C);
const PointerRNA active_ptr = RNA_property_pointer_get(&template->ptr, template->prop);
- MenuType *mt = WM_menutype_find(menu, false);
+ MenuType *mt = menu ? WM_menutype_find(menu, false) : NULL;
const int but_align = ui_but_align_opposite_to_area_align_get(region);
const int but_height = UI_UNIT_Y * 1.1;
@@ -1159,7 +1161,7 @@ static void template_ID_tabs(bContext *C,
ListBase ordered;
BKE_id_ordered_list(&ordered, template->idlb);
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
ID *id = link->data;
const int name_width = UI_fontstyle_string_width(&style->widgetlabel, id->name + 2);
const int but_width = name_width + UI_UNIT_X;
@@ -1180,7 +1182,7 @@ static void template_ID_tabs(bContext *C,
0.0f,
0.0f,
"");
- UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id);
+ UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id);
tab->but.custom_data = (void *)id;
tab->but.dragpoin = id;
tab->menu = mt;
@@ -1212,12 +1214,14 @@ static void template_ID_tabs(bContext *C,
}
static void ui_template_id(uiLayout *layout,
- bContext *C,
+ const bContext *C,
PointerRNA *ptr,
const char *propname,
const char *newop,
const char *openop,
const char *unlinkop,
+ /* Only respected by tabs (use_tabs). */
+ const char *menu,
const char *text,
int flag,
int prv_rows,
@@ -1272,7 +1276,7 @@ static void ui_template_id(uiLayout *layout,
if (template_ui->idlb) {
if (use_tabs) {
layout = uiLayoutRow(layout, true);
- template_ID_tabs(C, layout, template_ui, type, flag, newop, unlinkop);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, menu);
}
else {
layout = uiLayoutRow(layout, true);
@@ -1294,7 +1298,7 @@ static void ui_template_id(uiLayout *layout,
}
void uiTemplateID(uiLayout *layout,
- bContext *C,
+ const bContext *C,
PointerRNA *ptr,
const char *propname,
const char *newop,
@@ -1311,6 +1315,7 @@ void uiTemplateID(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
0,
@@ -1339,6 +1344,7 @@ void uiTemplateIDBrowse(uiLayout *layout,
newop,
openop,
unlinkop,
+ NULL,
text,
UI_ID_BROWSE | UI_ID_RENAME,
0,
@@ -1370,6 +1376,7 @@ void uiTemplateIDPreview(uiLayout *layout,
openop,
unlinkop,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
rows,
cols,
@@ -1397,6 +1404,7 @@ void uiTemplateGpencilColorPreview(uiLayout *layout,
NULL,
NULL,
NULL,
+ NULL,
UI_ID_BROWSE | UI_ID_PREVIEWS | UI_ID_DELETE,
rows,
cols,
@@ -1415,7 +1423,7 @@ void uiTemplateIDTabs(uiLayout *layout,
PointerRNA *ptr,
const char *propname,
const char *newop,
- const char *unlinkop,
+ const char *menu,
int filter)
{
ui_template_id(layout,
@@ -1424,7 +1432,8 @@ void uiTemplateIDTabs(uiLayout *layout,
propname,
newop,
NULL,
- unlinkop,
+ NULL,
+ menu,
NULL,
UI_ID_BROWSE | UI_ID_RENAME,
0,
@@ -1526,7 +1535,7 @@ typedef struct TemplateSearch {
int preview_rows, preview_cols;
} TemplateSearch;
-static void template_search_handle_cb(bContext *C, void *arg_template, void *item)
+static void template_search_exec_fn(bContext *C, void *arg_template, void *item)
{
TemplateSearch *template_search = arg_template;
uiRNACollectionSearch *coll_search = &template_search->search_data;
@@ -1550,9 +1559,9 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem
return template_common_search_menu(C,
region,
- ui_rna_collection_search_cb,
+ ui_rna_collection_search_update_fn,
&template_search,
- template_search_handle_cb,
+ template_search_exec_fn,
active_ptr.data,
template_search.preview_rows,
template_search.preview_cols,
@@ -1816,14 +1825,14 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
{
Object *ob = ob_v;
ModifierData *md = md_v;
- ModifierData *nmd = modifier_new(md->type);
+ ModifierData *nmd = BKE_modifier_new(md->type);
- modifier_copyData(md, nmd);
+ BKE_modifier_copydata(md, nmd);
nmd->mode &= ~eModifierMode_Virtual;
BLI_addhead(&ob->modifiers, nmd);
- modifier_unique_name(&ob->modifiers, nmd);
+ BKE_modifier_unique_name(&ob->modifiers, nmd);
ob->partype = PAROBJECT;
@@ -1833,20 +1842,26 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
ED_undo_push(C, "Modifier convert to real");
}
-static int modifier_can_delete(ModifierData *md)
+static bool modifier_can_delete(ModifierData *md)
{
/* fluid particle modifier can't be deleted here */
if (md->type == eModifierType_ParticleSystem) {
short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type;
- if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP ||
- particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY ||
- particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER ||
- particle_type == PART_FLUID_SPRAYFOAM || particle_type == PART_FLUID_SPRAYBUBBLE ||
- particle_type == PART_FLUID_FOAMBUBBLE || particle_type == PART_FLUID_SPRAYFOAMBUBBLE) {
- return 0;
+ if (ELEM(particle_type,
+ PART_FLUID,
+ PART_FLUID_FLIP,
+ PART_FLUID_FOAM,
+ PART_FLUID_SPRAY,
+ PART_FLUID_BUBBLE,
+ PART_FLUID_TRACER,
+ PART_FLUID_SPRAYFOAM,
+ PART_FLUID_SPRAYBUBBLE,
+ PART_FLUID_FOAMBUBBLE,
+ PART_FLUID_SPRAYFOAMBUBBLE)) {
+ return false;
}
}
- return 1;
+ return true;
}
/* Check whether Modifier is a simulation or not,
@@ -1881,7 +1896,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
int cageIndex,
int lastCageIndex)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
PointerRNA ptr;
uiBut *but;
uiBlock *block;
@@ -1975,9 +1990,9 @@ static uiLayout *draw_modifier(uiLayout *layout,
}
if (ob->type == OB_MESH) {
- if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
+ if (BKE_modifier_supports_cage(scene, md) && (index <= lastCageIndex)) {
sub = uiLayoutRow(row, true);
- if (index < cageIndex || !modifier_couldBeCage(scene, md)) {
+ if (index < cageIndex || !BKE_modifier_couldbe_cage(scene, md)) {
uiLayoutSetActive(sub, false);
}
uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE);
@@ -2073,7 +2088,7 @@ static uiLayout *draw_modifier(uiLayout *layout,
"apply_as",
MODIFIER_APPLY_DATA);
- if (modifier_isSameTopology(md) && !modifier_isNonGeometrical(md)) {
+ if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) {
uiItemEnumO(row,
"OBJECT_OT_modifier_apply",
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"),
@@ -2140,10 +2155,10 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE);
/* find modifier and draw it */
- cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0);
+ cageIndex = BKE_modifiers_get_cage_index(scene, ob, &lastCageIndex, 0);
/* XXX virtual modifiers are not accessible for python */
- vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ vmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
for (i = 0; vmd; i++, vmd = vmd->next) {
if (md == vmd) {
@@ -2165,7 +2180,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr)
static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
PointerRNA ptr;
uiBlock *block;
uiLayout *box, *column, *row, *sub;
@@ -2242,6 +2257,10 @@ static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModi
0,
"apply_as",
MODIFIER_APPLY_DATA);
+
+ UI_block_lock_clear(block);
+ UI_block_lock_set(block, ob && ID_IS_LINKED(ob), ERROR_LIBDATA_MESSAGE);
+
uiItemO(row,
CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"),
ICON_NONE,
@@ -2304,7 +2323,7 @@ uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), Point
static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md)
{
- const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type);
+ const ShaderFxTypeInfo *mti = BKE_shaderfx_get_info(md->type);
PointerRNA ptr;
uiBlock *block;
uiLayout *box, *column, *row, *sub;
@@ -2421,21 +2440,196 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Redo Buttons Template
+/** \name Operator Property Buttons Template
* \{ */
-static void template_operator_redo_property_buts_draw(
- const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced)
+typedef struct uiTemplateOperatorPropertyPollParam {
+ const bContext *C;
+ wmOperator *op;
+ short flag;
+} uiTemplateOperatorPropertyPollParam;
+
+#ifdef USE_OP_RESET_BUT
+static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
+ void *op_pt,
+ void *UNUSED(arg_dummy2))
+{
+ WM_operator_properties_reset((wmOperator *)op_pt);
+}
+#endif
+
+static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
+ struct PropertyRNA *prop,
+ void *user_data)
+{
+ uiTemplateOperatorPropertyPollParam *params = user_data;
+
+ if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
+ (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
+ return false;
+ }
+ return params->op->type->poll_property(params->C, params->op, prop);
+}
+
+static eAutoPropButsReturn template_operator_property_buts_draw_single(
+ const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags)
+{
+ uiBlock *block = uiLayoutGetBlock(layout);
+ eAutoPropButsReturn return_info = 0;
+
+ if (!op->properties) {
+ IDPropertyTemplate val = {0};
+ op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+
+ /* poll() on this operator may still fail,
+ * at the moment there is no nice feedback when this happens just fails silently. */
+ if (!WM_operator_repeat_check(C, op)) {
+ UI_block_lock_set(block, true, "Operator can't' redo");
+ return return_info;
+ }
+ else {
+ /* useful for macros where only one of the steps can't be re-done */
+ UI_block_lock_clear(block);
+ }
+
+ if (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
+ uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
+ }
+
+ /* menu */
+ if (op->type->flag & OPTYPE_PRESET) {
+ /* XXX, no simple way to get WM_MT_operator_presets.bl_label
+ * from python! Label remains the same always! */
+ PointerRNA op_ptr;
+ uiLayout *row;
+
+ block->ui_operator = op;
+
+ row = uiLayoutRow(layout, true);
+ uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
+
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
+ uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+
+ uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
+ RNA_string_set(&op_ptr, "operator", op->type->idname);
+ RNA_boolean_set(&op_ptr, "remove_active", true);
+ }
+
+ if (op->type->ui) {
+ op->layout = layout;
+ op->type->ui((bContext *)C, op);
+ op->layout = NULL;
+
+ /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could
+ * allow ot.ui callback to return this, but not needed right now. */
+ }
+ else {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ PointerRNA ptr;
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ const bool use_prop_split = (layout_flags & UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT) == 0;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ uiLayoutSetPropSep(layout, use_prop_split);
+ uiLayoutSetPropDecorate(layout, false);
+
+ /* main draw call */
+ return_info = uiDefAutoButsRNA(
+ layout,
+ &ptr,
+ op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
+ op->type->poll_property ? &user_data : NULL,
+ op->type->prop,
+ label_align,
+ (layout_flags & UI_TEMPLATE_OP_PROPS_COMPACT));
+
+ if ((return_info & UI_PROP_BUTS_NONE_ADDED) &&
+ (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
+ uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
+ }
+ }
+
+#ifdef USE_OP_RESET_BUT
+ /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
+ * but this is not so important if this button is drawn in those cases
+ * (which isn't all that likely anyway) - campbell */
+ if (op->properties->len) {
+ uiBut *but;
+ uiLayout *col; /* needed to avoid alignment errors with previous buttons */
+
+ col = uiLayoutColumn(layout, false);
+ block = uiLayoutGetBlock(col);
+ but = uiDefIconTextBut(block,
+ UI_BTYPE_BUT,
+ 0,
+ ICON_FILE_REFRESH,
+ IFACE_("Reset"),
+ 0,
+ 0,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ NULL,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ TIP_("Reset operator defaults"));
+ UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
+ }
+#endif
+
+ /* set various special settings for buttons */
+
+ /* Only do this if we're not refreshing an existing UI. */
+ if (block->oldblock == NULL) {
+ const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
+ uiBut *but;
+
+ for (but = block->buttons.first; but; but = but->next) {
+ /* no undo for buttons for operator redo panels */
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+
+ /* only for popups, see [#36109] */
+
+ /* if button is operator's default property, and a text-field, enable focus for it
+ * - this is used for allowing operators with popups to rename stuff with fewer clicks
+ */
+ if (is_popup) {
+ if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
+ UI_but_focus_on_enter_event(CTX_wm_window(C), but);
+ }
+ }
+ }
+ }
+
+ return return_info;
+}
+
+static void template_operator_property_buts_draw_recursive(const bContext *C,
+ wmOperator *op,
+ uiLayout *layout,
+ const eButLabelAlign label_align,
+ int layout_flags,
+ bool *r_has_advanced)
{
if (op->type->flag & OPTYPE_MACRO) {
- for (wmOperator *macro_op = op->macro.first; macro_op; macro_op = macro_op->next) {
- template_operator_redo_property_buts_draw(C, macro_op, layout, layout_flags, r_has_advanced);
+ LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
+ template_operator_property_buts_draw_recursive(
+ C, macro_op, layout, label_align, layout_flags, r_has_advanced);
}
}
else {
/* Might want to make label_align adjustable somehow. */
- eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs(
- C, layout, op, UI_BUT_LABEL_ALIGN_NONE, layout_flags);
+ eAutoPropButsReturn return_info = template_operator_property_buts_draw_single(
+ C, op, layout, label_align, layout_flags);
if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) {
if (r_has_advanced) {
*r_has_advanced = true;
@@ -2444,6 +2638,61 @@ static void template_operator_redo_property_buts_draw(
}
}
+static bool ui_layout_operator_properties_only_booleans(const bContext *C,
+ wmWindowManager *wm,
+ wmOperator *op,
+ int layout_flags)
+{
+ if (op->type->flag & OPTYPE_MACRO) {
+ LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) {
+ if (!ui_layout_operator_properties_only_booleans(C, wm, macro_op, layout_flags)) {
+ return false;
+ }
+ }
+ }
+ else {
+ uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags};
+ PointerRNA ptr;
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ RNA_STRUCT_BEGIN (&ptr, prop) {
+ if (RNA_property_flag(prop) & PROP_HIDDEN) {
+ continue;
+ }
+ if (op->type->poll_property &&
+ !ui_layout_operator_buts_poll_property(&ptr, prop, &user_data)) {
+ continue;
+ }
+ if (RNA_property_type(prop) != PROP_BOOLEAN) {
+ return false;
+ }
+ }
+ RNA_STRUCT_END;
+ }
+
+ return true;
+}
+
+/**
+ * Draw Operator property buttons for redoing execution with different settings.
+ * This function does not initialize the layout,
+ * functions can be called on the layout before and after.
+ */
+void uiTemplateOperatorPropertyButs(
+ const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
+ /* If there are only checkbox items, don't use split layout by default. It looks weird if the
+ * checkboxes only use half the width. */
+ if (ui_layout_operator_properties_only_booleans(C, wm, op, flag)) {
+ flag |= UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT;
+ }
+
+ template_operator_property_buts_draw_recursive(C, op, layout, label_align, flag, NULL);
+}
+
void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
{
wmOperator *op = WM_operator_last_redo(C);
@@ -2476,8 +2725,8 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
#endif
UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op);
- template_operator_redo_property_buts_draw(
- C, op, layout, layout_flags, NULL /* &has_advanced */);
+ template_operator_property_buts_draw_recursive(
+ C, op, layout, UI_BUT_LABEL_ALIGN_NONE, layout_flags, NULL /* &has_advanced */);
/* Warning! this leaves the handle function for any other users of this block. */
#if 0
@@ -2496,7 +2745,7 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C)
static void constraint_active_func(bContext *UNUSED(C), void *ob_v, void *con_v)
{
- ED_object_constraint_set_active(ob_v, con_v);
+ ED_object_constraint_active_set(ob_v, con_v);
}
/* draw panel showing settings for a constraint */
@@ -6572,936 +6821,6 @@ void uiTemplateList(uiLayout *layout,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Operator Search Template
- * \{ */
-
-static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
-{
- wmOperatorType *ot = arg2;
-
- if (ot) {
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
- }
-}
-
-static bool has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
-{
- const char *match = BLI_strncasestr(haystack, needle, needle_len);
- if (match) {
- if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
- return true;
- }
- else {
- return has_word_prefix(match + 1, needle, needle_len);
- }
- }
- else {
- return false;
- }
-}
-
-static void operator_search_cb(const bContext *C,
- void *UNUSED(arg),
- const char *str,
- uiSearchItems *items)
-{
- GHashIterator iter;
- const size_t str_len = strlen(str);
- const int words_max = (str_len / 2) + 1;
- int(*words)[2] = BLI_array_alloca(words, words_max);
-
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
-
- for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter);
- BLI_ghashIterator_step(&iter)) {
- wmOperatorType *ot = BLI_ghashIterator_getValue(&iter);
- const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name);
- int index;
-
- if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) {
- continue;
- }
-
- /* match name against all search words */
- for (index = 0; index < words_len; index++) {
- if (!has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) {
- break;
- }
- }
-
- if (index == words_len) {
- if (WM_operator_poll((bContext *)C, ot)) {
- char name[256];
- int len = strlen(ot_ui_name);
-
- /* display name for menu, can hold hotkey */
- BLI_strncpy(name, ot_ui_name, sizeof(name));
-
- /* check for hotkey */
- if (len < sizeof(name) - 6) {
- if (WM_key_event_operator_string(C,
- ot->idname,
- WM_OP_EXEC_DEFAULT,
- NULL,
- true,
- &name[len + 1],
- sizeof(name) - len - 1)) {
- name[len] = UI_SEP_CHAR;
- }
- }
-
- if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) {
- break;
- }
- }
- }
- }
-}
-
-void UI_but_func_operator_search(uiBut *but)
-{
- UI_but_func_search_set(
- but, ui_searchbox_create_operator, operator_search_cb, NULL, false, operator_call_cb, NULL);
-}
-
-void uiTemplateOperatorSearch(uiLayout *layout)
-{
- uiBlock *block;
- uiBut *but;
- static char search[256] = "";
-
- block = uiLayoutGetBlock(layout);
- UI_block_layout_set_current(block, layout);
-
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
- UI_but_func_operator_search(but);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Menu Search Template
- * \{ */
-
-struct MenuSearch_Parent {
- struct MenuSearch_Parent *parent;
- MenuType *parent_mt;
- /* Set while writing menu items only. */
- struct MenuSearch_Parent *temp_child;
- const char *drawstr;
-};
-
-struct MenuSearch_Item {
- struct MenuSearch_Item *next, *prev;
- const char *drawstr;
- const char *drawwstr_full;
- /** Support a single level sub-menu nesting (for operator buttons that expand). */
- const char *drawstr_submenu;
- int icon;
- int state;
-
- struct MenuSearch_Parent *menu_parent;
- MenuType *mt;
-
- enum {
- MENU_SEARCH_TYPE_OP = 1,
- MENU_SEARCH_TYPE_RNA = 2,
- } type;
-
- union {
- /* Operator menu item. */
- struct {
- wmOperatorType *type;
- PointerRNA *opptr;
- short opcontext;
- bContextStore *context;
- } op;
-
- /* Property (only for check-boxe/boolean). */
- struct {
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
- /** Only for enum buttons. */
- int enum_value;
- } rna;
- };
-};
-
-struct MenuSearch_Data {
- /** MenuSearch_Item */
- ListBase items;
- /** Use for all small allocations. */
- MemArena *memarena;
-};
-
-static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v)
-{
- const struct MenuSearch_Item *menu_item_a = menu_item_a_v;
- const struct MenuSearch_Item *menu_item_b = menu_item_b_v;
- return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full);
-}
-
-static const char *strdup_memarena(MemArena *memarena, const char *str)
-{
- const uint str_size = strlen(str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
- memcpy(str_dst, str, str_size);
- return str_dst;
-}
-
-static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str)
-{
- const uint str_size = BLI_dynstr_get_len(dyn_str) + 1;
- char *str_dst = BLI_memarena_alloc(memarena, str_size);
- BLI_dynstr_get_cstring_ex(dyn_str, str_dst);
- return str_dst;
-}
-
-static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data,
- MemArena *memarena,
- struct MenuType *mt,
- const char *drawstr_submenu,
- uiBut *but)
-{
- struct MenuSearch_Item *item = NULL;
- if (but->optype != NULL) {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_OP;
-
- item->op.type = but->optype;
- item->op.opcontext = but->opcontext;
- item->op.context = but->context;
- item->op.opptr = but->opptr;
- but->opptr = NULL;
- }
- else if (but->rnaprop != NULL) {
- const int prop_type = RNA_property_type(but->rnaprop);
- if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) {
- /* Note that these buttons are not prevented,
- * but aren't typically used in menus. */
- printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n",
- but->drawstr,
- mt->idname,
- prop_type);
- }
- else {
- item = BLI_memarena_calloc(memarena, sizeof(*item));
- item->type = MENU_SEARCH_TYPE_RNA;
-
- item->rna.ptr = but->rnapoin;
- item->rna.prop = but->rnaprop;
- item->rna.index = but->rnaindex;
-
- if (prop_type == PROP_ENUM) {
- item->rna.enum_value = (int)but->hardmax;
- }
- }
- }
-
- if (item != NULL) {
- /* Handle shared settings. */
- item->drawstr = strdup_memarena(memarena, but->drawstr);
- item->icon = but->icon;
- item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT));
- item->mt = mt;
- item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL;
- BLI_addtail(&data->items, item);
- return true;
- }
-
- return false;
-}
-
-/**
- * Populate \a menu_stack with menus from inspecting active key-maps for this context.
- */
-static void menu_types_add_from_keymap_items(bContext *C,
- wmWindow *win,
- ScrArea *sa,
- ARegion *region,
- LinkNode **menuid_stack_p,
- GHash *menu_to_kmi,
- GSet *menu_tagged)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- ListBase *handlers[] = {
- &region->handlers,
- &sa->handlers,
- &win->handlers,
- };
-
- for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
- LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) {
- /* During this loop, ui handlers for nested menus can tag multiple handlers free. */
- if (handler_base->flag & WM_HANDLER_DO_FREE) {
- continue;
- }
- if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) {
- continue;
- }
-
- else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) {
- wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base;
- wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler);
- if (keymap && WM_keymap_poll(C, keymap)) {
- LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) {
- if (kmi->flag & KMI_INACTIVE) {
- continue;
- }
- if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) {
- char menu_idname[MAX_NAME];
- RNA_string_get(kmi->ptr, "name", menu_idname);
- MenuType *mt = WM_menutype_find(menu_idname, false);
-
- if (mt && BLI_gset_add(menu_tagged, mt)) {
- /* Unlikely, but possible this will be included twice. */
- BLI_linklist_prepend(menuid_stack_p, mt);
-
- void **kmi_p;
- if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) {
- *kmi_p = kmi;
- }
- }
- }
- }
- }
- }
- }
- }
-}
-
-/**
- * Create #MenuSearch_Data by inspecting the current context, this uses two methods:
- *
- * - Look-up pre-defined editor-menus.
- * - Look-up key-map items which call menus.
- */
-static struct MenuSearch_Data *menu_items_from_ui_create(bContext *C,
- wmWindow *win,
- ScrArea *sa,
- ARegion *region)
-{
- MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
- /** Map (#MenuType to #MenuSearch_Parent) */
- GHash *menu_parent_map = BLI_ghash_ptr_new(__func__);
- GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__);
- const uiStyle *style = UI_style_get_dpi();
-
- /* Convert into non-ui structure. */
- struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__);
-
- DynStr *dyn_str = BLI_dynstr_new_memarena();
-
- /* Use a stack of menus to handle and discover new menus in passes. */
- LinkNode *menu_stack = NULL;
-
- /* Tag menu types not to add, either because they have already been added
- * or they have been blacklisted.
- * Set of #MenuType. */
- GSet *menu_tagged = BLI_gset_ptr_new(__func__);
- /** Map (#MenuType -> #wmKeyMapItem). */
- GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__);
-
- /* Blacklist menus we don't want to show. */
- {
- const char *idname_array[] = {
- /* While we could include this, it's just showing filenames to load. */
- "TOPBAR_MT_file_open_recent",
- };
- for (int i = 0; i < ARRAY_SIZE(idname_array); i++) {
- MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_gset_add(menu_tagged, mt);
- }
- }
- }
-
- /* Populate menus from the editors,
- * note that we could create a fake header, draw the header and extract the menus
- * from the buttons, however this is quite involved and can be avoided as by convention
- * each space-type has a single root-menu that headers use. */
- {
- const char *idname_array[] = {
- "TOPBAR_MT_editor_menus",
- /* Optional second menu for the space-type. */
- NULL,
- };
- int idname_array_len = 1;
-
-#define SPACE_MENU_MAP(space_type, menu_id) \
- case space_type: \
- idname_array[idname_array_len++] = menu_id; \
- break
-#define SPACE_MENU_NOP(space_type) \
- case space_type: \
- break
-
- if (sa != NULL) {
- switch (sa->spacetype) {
- SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus");
- SPACE_MENU_NOP(SPACE_PROPERTIES);
- SPACE_MENU_MAP(SPACE_FILE, "FILE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_ACTION, "ACTION_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus");
- SPACE_MENU_MAP(SPACE_CLIP,
- (((const SpaceClip *)sa->spacedata.first)->mode == SC_MODE_TRACKING) ?
- "CLIP_MT_tracking_editor_menus" :
- "CLIP_MT_masking_editor_menus");
- SPACE_MENU_NOP(SPACE_TOPBAR);
- SPACE_MENU_NOP(SPACE_STATUSBAR);
- default:
- printf("Unknown space type '%d'\n", sa->spacetype);
- }
- }
- for (int i = 0; i < idname_array_len; i++) {
- MenuType *mt = WM_menutype_find(idname_array[i], false);
- if (mt != NULL) {
- BLI_linklist_prepend(&menu_stack, mt);
- BLI_gset_add(menu_tagged, mt);
- }
- }
- }
-#undef SPACE_MENU_MAP
-#undef SPACE_MENU_NOP
-
- bool has_keymap_menu_items = false;
-
- GHashIterator iter;
-
- while (menu_stack != NULL) {
- MenuType *mt = BLI_linklist_pop(&menu_stack);
- if (!WM_menutype_poll(C, mt)) {
- continue;
- }
-
- uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
- uiLayout *layout = UI_block_layout(
- block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
-
- UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
-
- uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- UI_menutype_draw(C, mt, layout);
-
- UI_block_end(C, block);
-
- LISTBASE_FOREACH (uiBut *, but, &block->buttons) {
- MenuType *mt_from_but = NULL;
- /* Support menu titles with dynamic from initial labels
- * (used by edit-mesh context menu). */
- if (but->type == UI_BTYPE_LABEL) {
-
- /* Check if the label is the title. */
- uiBut *but_test = but->prev;
- while (but_test && but_test->type == UI_BTYPE_SEPR) {
- but_test = but_test->prev;
- }
-
- if (but_test == NULL) {
- BLI_ghash_insert(
- menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr));
- }
- }
- else if (menu_items_from_ui_create_item_from_button(data, memarena, mt, NULL, but)) {
- /* pass */
- }
- else if ((mt_from_but = UI_but_menutype_get(but))) {
-
- if (BLI_gset_add(menu_tagged, mt_from_but)) {
- BLI_linklist_prepend(&menu_stack, mt_from_but);
- }
-
- if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) {
- struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena,
- sizeof(*menu_parent));
- /* Use brackets for menu key shortcuts,
- * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)".
- * This is needed so we don't right align sub-menu contents
- * we only want to do that for the last menu item, not the path that leads to it.
- */
- const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ?
- strrchr(but->drawstr, UI_SEP_CHAR) :
- NULL;
- bool drawstr_is_empty = false;
- if (drawstr_sep != NULL) {
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- /* Detect empty string, fallback to menu name. */
- const char *drawstr = but->drawstr;
- int drawstr_len = drawstr_sep - but->drawstr;
- if (UNLIKELY(drawstr_len == 0)) {
- drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
- drawstr_len = strlen(drawstr);
- if (drawstr[0] == '\0') {
- drawstr_is_empty = true;
- }
- }
- BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len);
- BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1);
- menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str);
- BLI_dynstr_clear(dyn_str);
- }
- else {
- const char *drawstr = but->drawstr;
- if (UNLIKELY(drawstr[0] == '\0')) {
- drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label);
- if (drawstr[0] == '\0') {
- drawstr_is_empty = true;
- }
- }
- menu_parent->drawstr = strdup_memarena(memarena, drawstr);
- }
- menu_parent->parent_mt = mt;
- BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent);
-
- if (drawstr_is_empty) {
- printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname);
- }
- }
- }
- else if (but->menu_create_func != NULL) {
- /* A non 'MenuType' menu button. */
-
- /* Only expand one level deep, this is mainly for expanding operator menus. */
- const char *drawstr_submenu = but->drawstr;
-
- /* +1 to avoid overlap with the current 'block'. */
- uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS);
- uiLayout *sub_layout = UI_block_layout(
- sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style);
-
- UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS);
-
- uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN);
-
- but->menu_create_func(C, sub_layout, but->poin);
-
- UI_block_end(C, sub_block);
-
- LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) {
- menu_items_from_ui_create_item_from_button(data, memarena, mt, drawstr_submenu, sub_but);
- }
-
- BLI_remlink(&region->uiblocks, sub_block);
- UI_block_free(NULL, sub_block);
- }
- }
- BLI_remlink(&region->uiblocks, block);
- UI_block_free(NULL, block);
-
- /* Add key-map items as a second pass,
- * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */
- if ((menu_stack == NULL) && (has_keymap_menu_items == false)) {
- has_keymap_menu_items = true;
- menu_types_add_from_keymap_items(C, win, sa, region, &menu_stack, menu_to_kmi, menu_tagged);
- }
- }
-
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt);
- }
-
- GHASH_ITER (iter, menu_parent_map) {
- struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter);
- menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt);
- }
-
- /* NOTE: currently this builds the full path for each menu item,
- * that could be moved into the parent menu. */
-
- /* Unicode arrow. */
-#define MENU_SEP "\xe2\x86\x92"
-
- /* Set names as full paths. */
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- if (item->menu_parent != NULL) {
- struct MenuSearch_Parent *menu_parent = item->menu_parent;
- menu_parent->temp_child = NULL;
- while (menu_parent && menu_parent->parent) {
- menu_parent->parent->temp_child = menu_parent;
- menu_parent = menu_parent->parent;
- }
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- while (menu_parent) {
- BLI_dynstr_append(dyn_str, menu_parent->drawstr);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- menu_parent = menu_parent->temp_child;
- }
- }
- else {
- BLI_assert(BLI_dynstr_get_len(dyn_str) == 0);
- const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt);
- if (drawstr == NULL) {
- drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label);
- }
- BLI_dynstr_append(dyn_str, drawstr);
-
- wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt);
- if (kmi != NULL) {
- char kmi_str[128];
- WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str));
- BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str);
- }
-
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- }
-
- /* Optional nested menu. */
- if (item->drawstr_submenu != NULL) {
- BLI_dynstr_append(dyn_str, item->drawstr_submenu);
- BLI_dynstr_append(dyn_str, " " MENU_SEP " ");
- }
-
- BLI_dynstr_append(dyn_str, item->drawstr);
-
- item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str);
- BLI_dynstr_clear(dyn_str);
- }
- BLI_dynstr_free(dyn_str);
-#undef MENU_SEP
-
- /* Finally sort menu items.
- *
- * Note: we might want to keep the in-menu order, for now sort all. */
- BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full);
-
- BLI_ghash_free(menu_parent_map, NULL, NULL);
- BLI_ghash_free(menu_display_name_map, NULL, NULL);
-
- BLI_ghash_free(menu_to_kmi, NULL, NULL);
-
- BLI_gset_free(menu_tagged, NULL);
-
- data->memarena = memarena;
-
- return data;
-}
-
-static void menu_items_from_ui_destroy(void *data_v)
-{
- struct MenuSearch_Data *data = data_v;
- LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) {
- switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- if (item->op.opptr != NULL) {
- WM_operator_properties_free(item->op.opptr);
- MEM_freeN(item->op.opptr);
- }
- }
- case MENU_SEARCH_TYPE_RNA: {
- break;
- }
- }
- }
-
- BLI_memarena_free(data->memarena);
-
- MEM_freeN(data);
-}
-
-static void menu_call_fn(bContext *C, void *UNUSED(arg1), void *arg2)
-{
- struct MenuSearch_Item *item = arg2;
- if (item == NULL) {
- return;
- }
- if (item->state & UI_BUT_DISABLED) {
- return;
- }
-
- switch (item->type) {
- case MENU_SEARCH_TYPE_OP: {
- CTX_store_set(C, item->op.context);
- WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr);
- CTX_store_set(C, NULL);
- break;
- }
- case MENU_SEARCH_TYPE_RNA: {
- PointerRNA *ptr = &item->rna.ptr;
- PropertyRNA *prop = item->rna.prop;
- int index = item->rna.index;
- const int prop_type = RNA_property_type(prop);
- bool changed = false;
-
- if (prop_type == PROP_BOOLEAN) {
- const bool is_array = RNA_property_array_check(prop);
- if (is_array) {
- const bool value = RNA_property_boolean_get_index(ptr, prop, index);
- RNA_property_boolean_set_index(ptr, prop, index, !value);
- }
- else {
- const bool value = RNA_property_boolean_get(ptr, prop);
- RNA_property_boolean_set(ptr, prop, !value);
- }
- changed = true;
- }
- else if (prop_type == PROP_ENUM) {
- RNA_property_enum_set(ptr, prop, item->rna.enum_value);
- changed = true;
- }
-
- if (changed) {
- RNA_property_update(C, ptr, prop);
- }
- break;
- }
- }
-}
-
-static void menu_search_cb(const bContext *UNUSED(C),
- void *arg,
- const char *str,
- uiSearchItems *items)
-{
- struct MenuSearch_Data *data = arg;
- const size_t str_len = strlen(str);
- const int words_max = (str_len / 2) + 1;
- int(*words)[2] = BLI_array_alloca(words, words_max);
-
- const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max);
-
- for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) {
- int index;
-
- /* match name against all search words */
- for (index = 0; index < words_len; index++) {
- if (!has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) {
- break;
- }
- }
-
- if (index == words_len) {
- if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) {
- break;
- }
- }
- }
-}
-
-void UI_but_func_menu_search(uiBut *but)
-{
- bContext *C = but->block->evil_C;
- wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = CTX_wm_region(C);
- struct MenuSearch_Data *data = menu_items_from_ui_create(C, win, sa, region);
- UI_but_func_search_set(but,
- ui_searchbox_create_menu,
- menu_search_cb,
- data,
- menu_items_from_ui_destroy,
- menu_call_fn,
- NULL);
-}
-
-void uiTemplateMenuSearch(uiLayout *layout)
-{
- uiBlock *block;
- uiBut *but;
- static char search[256] = "";
-
- block = uiLayoutGetBlock(layout);
- UI_block_layout_set_current(block, layout);
-
- but = uiDefSearchBut(
- block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, "");
- UI_but_func_menu_search(but);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Operator Redo Properties Template
- * \{ */
-
-#ifdef USE_OP_RESET_BUT
-static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C),
- void *op_pt,
- void *UNUSED(arg_dummy2))
-{
- WM_operator_properties_reset((wmOperator *)op_pt);
-}
-#endif
-
-struct uiTemplateOperatorPropertyPollParam {
- const bContext *C;
- wmOperator *op;
- short flag;
-};
-
-static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr),
- struct PropertyRNA *prop,
- void *user_data)
-{
- struct uiTemplateOperatorPropertyPollParam *params = user_data;
- if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) &&
- (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) {
- return false;
- }
- return params->op->type->poll_property(params->C, params->op, prop);
-}
-
-/**
- * Draw Operator property buttons for redoing execution with different settings.
- * This function does not initialize the layout,
- * functions can be called on the layout before and after.
- */
-eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C,
- uiLayout *layout,
- wmOperator *op,
- const eButLabelAlign label_align,
- const short flag)
-{
- uiBlock *block = uiLayoutGetBlock(layout);
- eAutoPropButsReturn return_info = 0;
-
- if (!op->properties) {
- IDPropertyTemplate val = {0};
- op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
- }
-
- /* poll() on this operator may still fail,
- * at the moment there is no nice feedback when this happens just fails silently. */
- if (!WM_operator_repeat_check(C, op)) {
- UI_block_lock_set(block, true, "Operator can't' redo");
- return return_info;
- }
- else {
- /* useful for macros where only one of the steps can't be re-done */
- UI_block_lock_clear(block);
- }
-
- if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) {
- uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE);
- }
-
- /* menu */
- if (op->type->flag & OPTYPE_PRESET) {
- /* XXX, no simple way to get WM_MT_operator_presets.bl_label
- * from python! Label remains the same always! */
- PointerRNA op_ptr;
- uiLayout *row;
-
- block->ui_operator = op;
-
- row = uiLayoutRow(layout, true);
- uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE);
-
- wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false);
- uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
-
- uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr);
- RNA_string_set(&op_ptr, "operator", op->type->idname);
- RNA_boolean_set(&op_ptr, "remove_active", true);
- }
-
- if (op->type->ui) {
- op->layout = layout;
- op->type->ui((bContext *)C, op);
- op->layout = NULL;
-
- /* UI_LAYOUT_OP_SHOW_EMPTY ignored. return_info is ignored too. We could
- * allow ot.ui callback to return this, but not needed right now. */
- }
- else {
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- struct uiTemplateOperatorPropertyPollParam user_data = {
- .C = C,
- .op = op,
- .flag = flag,
- };
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- /* main draw call */
- return_info = uiDefAutoButsRNA(
- layout,
- &ptr,
- op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL,
- op->type->poll_property ? &user_data : NULL,
- op->type->prop,
- label_align,
- (flag & UI_TEMPLATE_OP_PROPS_COMPACT));
-
- if ((return_info & UI_PROP_BUTS_NONE_ADDED) && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) {
- uiItemL(layout, IFACE_("No Properties"), ICON_NONE);
- }
- }
-
-#ifdef USE_OP_RESET_BUT
- /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled
- * but this is not so important if this button is drawn in those cases
- * (which isn't all that likely anyway) - campbell */
- if (op->properties->len) {
- uiBut *but;
- uiLayout *col; /* needed to avoid alignment errors with previous buttons */
-
- col = uiLayoutColumn(layout, false);
- block = uiLayoutGetBlock(col);
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_FILE_REFRESH,
- IFACE_("Reset"),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- NULL,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- TIP_("Reset operator defaults"));
- UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
- }
-#endif
-
- /* set various special settings for buttons */
-
- /* Only do this if we're not refreshing an existing UI. */
- if (block->oldblock == NULL) {
- const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0;
- uiBut *but;
-
- for (but = block->buttons.first; but; but = but->next) {
- /* no undo for buttons for operator redo panels */
- UI_but_flag_disable(but, UI_BUT_UNDO);
-
- /* only for popups, see [#36109] */
-
- /* if button is operator's default property, and a text-field, enable focus for it
- * - this is used for allowing operators with popups to rename stuff with fewer clicks
- */
- if (is_popup) {
- if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) {
- UI_but_focus_on_enter_event(CTX_wm_window(C), but);
- }
- }
- }
- }
-
- return return_info;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Running Jobs Template
* \{ */
@@ -7579,7 +6898,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
uiBlock *block;
void *owner = NULL;
int handle_event, icon = 0;
@@ -7653,7 +6972,7 @@ void uiTemplateRunningJobs(uiLayout *layout, bContext *C)
* progress bar which is not being updated (bake jobs only need
* to update NC_IMAGE context.
*/
- if (sa->spacetype != SPACE_NODE) {
+ if (area->spacetype != SPACE_NODE) {
handle_event = B_STOPOTHER;
icon = ICON_IMAGE;
break;
@@ -8204,7 +7523,10 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float *color)
/** \name Cache File Template
* \{ */
-void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname)
+void uiTemplateCacheFile(uiLayout *layout,
+ const bContext *C,
+ PointerRNA *ptr,
+ const char *propname)
{
if (!ptr->data) {
return;
diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c
new file mode 100644
index 00000000000..016bc4159db
--- /dev/null
+++ b/source/blender/editors/interface/interface_undo.c
@@ -0,0 +1,139 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Undo stack to use for UI widgets that manage their own editing state.
+ */
+
+#include <string.h>
+
+#include "BLI_listbase.h"
+
+#include "DNA_listBase.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "interface_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Text Field Undo Stack
+ * \{ */
+
+typedef struct uiUndoStack_Text_State {
+ struct uiUndoStack_Text_State *next, *prev;
+ int cursor_index;
+ char text[0];
+} uiUndoStack_Text_State;
+
+typedef 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;
+ }
+
+ /* Travel backwards in the stack and copy information to the caller. */
+ if (stack->current->prev != NULL) {
+ stack->current = stack->current->prev;
+
+ *r_cursor_index = stack->current->cursor_index;
+ return stack->current->text;
+ }
+ return NULL;
+}
+
+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;
+ }
+
+ /* Only redo if new data has not been entered since the last undo. */
+ if (stack->current->next) {
+ stack->current = stack->current->next;
+
+ *r_cursor_index = stack->current->cursor_index;
+ return stack->current->text;
+ }
+ return NULL;
+}
+
+const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index)
+{
+ BLI_assert(ELEM(direction, -1, 1));
+ if (direction < 0) {
+ return ui_textedit_undo_impl(stack, r_cursor_index);
+ }
+ else {
+ return ui_textedit_redo_impl(stack, r_cursor_index);
+ }
+}
+
+/**
+ * Push the information in the arguments to a new state in the undo stack.
+ *
+ * \note Currently the total length of the undo stack is not limited.
+ */
+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) {
+ while (stack->current->next) {
+ uiUndoStack_Text_State *state = stack->current->next;
+ BLI_remlink(&stack->states, state);
+ MEM_freeN(state);
+ }
+ }
+
+ /* Create the new state */
+ const int text_size = strlen(text) + 1;
+ stack->current = 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);
+}
+/**
+ * Start the undo stack.
+ *
+ * \note The current state should be pushed immediately after calling this.
+ */
+uiUndoStack_Text *ui_textedit_undo_stack_create(void)
+{
+ uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__);
+ stack->current = NULL;
+ BLI_listbase_clear(&stack->states);
+
+ return stack;
+}
+
+void ui_textedit_undo_stack_destroy(uiUndoStack_Text *stack)
+{
+ BLI_freelistN(&stack->states);
+ MEM_freeN(stack);
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index a69837e9b51..4013e962ce5 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -22,6 +22,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -36,6 +37,7 @@
#include "BLT_translation.h"
+#include "BKE_lib_id.h"
#include "BKE_report.h"
#include "MEM_guardedalloc.h"
@@ -50,6 +52,22 @@
#include "interface_intern.h"
+bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len)
+{
+ const char *match = BLI_strncasestr(haystack, needle, needle_len);
+ if (match) {
+ if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) {
+ return true;
+ }
+ else {
+ return ui_str_has_word_prefix(match + 1, needle, needle_len);
+ }
+ }
+ else {
+ return false;
+ }
+}
+
/*************************** RNA Utilities ******************************/
uiBut *uiDefAutoButR(uiBlock *block,
@@ -293,7 +311,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
const bool compact)
{
eAutoPropButsReturn return_info = UI_PROP_BUTS_NONE_ADDED;
- uiLayout *split, *col;
+ uiLayout *col;
const char *name;
RNA_STRUCT_BEGIN (ptr, prop) {
@@ -324,19 +342,11 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
}
else {
BLI_assert(label_align == UI_BUT_LABEL_ALIGN_SPLIT_COLUMN);
- split = uiLayoutSplit(layout, 0.5f, false);
-
- col = uiLayoutColumn(split, false);
- uiItemL(col, (is_boolean) ? "" : name, ICON_NONE);
- col = uiLayoutColumn(split, false);
+ col = uiLayoutColumn(layout, true);
+ /* Let uiItemFullR() create the split layout. */
+ uiLayoutSetPropSep(col, true);
}
- /* May need to add more cases here.
- * don't override enum flag names */
-
- /* name is shown above, empty name for button below */
- name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : "";
-
break;
}
case UI_BUT_LABEL_ALIGN_NONE:
@@ -389,17 +399,23 @@ static int sort_search_items_list(const void *a, const void *b)
}
}
-void ui_rna_collection_search_cb(const struct bContext *C,
- void *arg,
- const char *str,
- uiSearchItems *items)
+void ui_rna_collection_search_update_fn(const struct bContext *C,
+ void *arg,
+ const char *str,
+ uiSearchItems *items)
{
uiRNACollectionSearch *data = arg;
- char *name;
int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop);
ListBase *items_list = MEM_callocN(sizeof(ListBase), "items_list");
CollItemSearch *cis;
- const bool skip_filter = (data->but_changed && !(*data->but_changed));
+ const bool is_ptr_target = (RNA_property_type(data->target_prop) == PROP_POINTER);
+ /* For non-pointer properties, UI code acts entirely based on the item's name. So the name has to
+ * match the RNA name exactly. So only for pointer properties, the name can be modified to add
+ * further UI hints. */
+ const bool requires_exact_data_name = !is_ptr_target;
+ const bool skip_filter = data->search_but && !data->search_but->changed;
+ char name_buf[UI_MAX_DRAW_STR];
+ char *name;
/* build a temporary list of relevant items first */
RNA_PROP_BEGIN (&data->search_ptr, itemptr, data->search_prop) {
@@ -411,30 +427,42 @@ void ui_rna_collection_search_cb(const struct bContext *C,
}
/* use filter */
- if (RNA_property_type(data->target_prop) == PROP_POINTER) {
+ if (is_ptr_target) {
if (RNA_property_pointer_poll(&data->target_ptr, data->target_prop, &itemptr) == 0) {
continue;
}
}
- /* Could use the string length here. */
- name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
-
iconid = 0;
if (itemptr.type && RNA_struct_is_ID(itemptr.type)) {
iconid = ui_id_icon_get(C, itemptr.data, false);
+
+ if (requires_exact_data_name) {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), NULL);
+ }
+ else {
+ BKE_id_full_name_ui_prefix_get(name_buf, itemptr.data);
+ BLI_STATIC_ASSERT(sizeof(name_buf) >= MAX_ID_FULL_NAME_UI,
+ "Name string buffer should be big enough to hold full UI ID name");
+ name = name_buf;
+ }
+ }
+ else {
+ name = RNA_struct_name_get_alloc(&itemptr, name_buf, sizeof(name_buf), NULL);
}
if (name) {
if (skip_filter || BLI_strcasestr(name, str)) {
cis = MEM_callocN(sizeof(CollItemSearch), "CollectionItemSearch");
cis->data = itemptr.data;
- cis->name = MEM_dupallocN(name);
+ cis->name = BLI_strdup(name);
cis->index = i;
cis->iconid = iconid;
BLI_addtail(items_list, cis);
}
- MEM_freeN(name);
+ if (name != name_buf) {
+ MEM_freeN(name);
+ }
}
i++;
@@ -647,6 +675,7 @@ void UI_butstore_free(uiBlock *block, uiButStore *bs_handle)
}
BLI_freelistN(&bs_handle->items);
+ BLI_assert(BLI_findindex(&block->butstore, bs_handle) != -1);
BLI_remlink(&block->butstore, bs_handle);
MEM_freeN(bs_handle);
@@ -747,8 +776,7 @@ void UI_butstore_update(uiBlock *block)
/* move this list to the new block */
if (block->oldblock) {
if (block->oldblock->butstore.first) {
- block->butstore = block->oldblock->butstore;
- BLI_listbase_clear(&block->oldblock->butstore);
+ BLI_movelisttolist(&block->butstore, &block->oldblock->butstore);
}
}
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 7e6ef11518a..0498b312618 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -27,7 +27,6 @@
#include <string.h>
#include "DNA_brush_types.h"
-#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
@@ -42,6 +41,8 @@
#include "BLF_api.h"
+#include "ED_node.h"
+
#include "UI_interface.h"
#include "UI_interface_icons.h"
@@ -1348,6 +1349,7 @@ void UI_widgetbase_draw_cache_flush(void)
(float *)g_widget_base_batch.params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_matrix_bind(batch->interface);
+ GPU_shader_set_srgb_uniform(batch->interface);
GPU_batch_bind(batch);
GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count);
@@ -2091,6 +2093,25 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
}
#endif /* WITH_INPUT_IME */
+static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str),
+ const size_t str_step_ofs,
+ const rcti *glyph_step_bounds,
+ const int UNUSED(glyph_advance_x),
+ const rctf *glyph_bounds,
+ const int glyph_bearing[2],
+ void *user_data)
+{
+ /* The index of the character to get, set to the x-position. */
+ int *ul_data = user_data;
+ if (ul_data[0] == (int)str_step_ofs) {
+ ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] +
+ (BLI_rctf_size_x(glyph_bounds) / 2.0f);
+ /* Early exit. */
+ return false;
+ }
+ return true;
+}
+
static void widget_draw_text(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
@@ -2300,7 +2321,7 @@ static void widget_draw_text(const uiFontStyle *fstyle,
if (!use_right_only) {
/* for underline drawing */
- float font_xofs, font_yofs;
+ int font_xofs, font_yofs;
int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) :
(drawstr_left_len - but->ofs);
@@ -2315,34 +2336,44 @@ static void widget_draw_text(const uiFontStyle *fstyle,
},
drawlen,
&font_xofs,
- &font_yofs);
+ &font_yofs,
+ NULL);
if (but->menu_key != '\0') {
- char fixedbuf[128];
- const char *str;
-
- BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawlen));
-
- str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
- if (str == NULL) {
- str = strchr(fixedbuf, but->menu_key);
+ const char *drawstr_ofs = drawstr + but->ofs;
+ int ul_index = -1;
+
+ {
+ /* Find upper case, fallback to lower case. */
+ const char *drawstr_end = drawstr_ofs + drawlen;
+ const char keys[] = {but->menu_key - 32, but->menu_key};
+ for (int i = 0; i < ARRAY_SIZE(keys); i++) {
+ const char *drawstr_menu = strchr(drawstr_ofs, keys[i]);
+ if (drawstr_menu != NULL && drawstr_menu < drawstr_end) {
+ ul_index = (int)(drawstr_menu - drawstr_ofs);
+ break;
+ }
+ }
}
- if (str) {
- int ul_index = -1;
- float ul_advance;
-
- ul_index = (int)(str - fixedbuf);
-
+ if (ul_index != -1) {
if (fstyle->kerning == 1) {
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
- fixedbuf[ul_index] = '\0';
- ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index) + (1.0f * UI_DPI_FAC);
+ int ul_data[2] = {
+ ul_index, /* Character index to test. */
+ 0, /* Write the x-offset here. */
+ };
+ BLF_boundbox_foreach_glyph(fstyle->uifont_id,
+ drawstr_ofs,
+ ul_index + 1,
+ widget_draw_text_underline_calc_center_x,
+ ul_data);
+ ul_data[1] -= BLF_width(fstyle->uifont_id, "_", 2) / 2.0f;
BLF_position(fstyle->uifont_id,
- rect->xmin + font_xofs + ul_advance,
+ rect->xmin + font_xofs + ul_data[1],
rect->ymin + font_yofs,
0.0f);
BLF_color4ubv(fstyle->uifont_id, wcol->text);
@@ -2375,21 +2406,6 @@ static void widget_draw_text(const uiFontStyle *fstyle,
}
}
-static BIFIconID widget_icon_id(uiBut *but)
-{
- if (!(but->flag & UI_HAS_ICON)) {
- return ICON_NONE;
- }
-
- /* Consecutive icons can be toggle between. */
- if (but->drawflag & UI_BUT_ICON_REVERSE) {
- return but->icon - but->iconadd;
- }
- else {
- return but->icon + but->iconadd;
- }
-}
-
static void widget_draw_extra_icons(const uiWidgetColors *wcol,
uiBut *but,
rcti *rect,
@@ -2407,6 +2423,30 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol,
}
}
+static void widget_draw_node_link_socket(const uiWidgetColors *wcol,
+ const rcti *rect,
+ uiBut *but,
+ float alpha)
+{
+ /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
+ if (but->custom_data) {
+ const float scale = 0.9f / but->block->aspect;
+
+ float col[4];
+ rgba_uchar_to_float(col, but->col);
+ col[3] *= alpha;
+
+ GPU_blend(true);
+ UI_widgetbase_draw_cache_flush();
+ GPU_blend(false);
+
+ ED_node_socket_draw(but->custom_data, rect, col, scale);
+ }
+ else {
+ widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
+ }
+}
+
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
@@ -2416,15 +2456,27 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
+ bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
- temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
- widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text);
- rect->xmax = temp.xmin;
+ const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
+
+ if (but->drawflag & UI_BUT_ICON_LEFT) {
+ temp.xmax = rect->xmin + size;
+ rect->xmin = temp.xmax;
+ /* Further padding looks off. */
+ no_text_padding = true;
+ }
+ else {
+ temp.xmin = rect->xmax - size;
+ rect->xmax = temp.xmin;
+ }
+
+ widget_draw_node_link_socket(wcol, &temp, but, alpha);
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
@@ -2432,7 +2484,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
/* Big previews with optional text label below */
if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
- const BIFIconID icon = widget_icon_id(but);
+ const BIFIconID icon = ui_but_icon(but);
int icon_size = BLI_rcti_size_y(rect);
int text_size = 0;
@@ -2469,7 +2521,7 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
}
#endif
- const BIFIconID icon = widget_icon_id(but);
+ const BIFIconID icon = ui_but_icon(but);
int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac);
const float icon_padding = 2 * UI_DPI_FAC;
@@ -2509,21 +2561,30 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle,
rect->xmin += icon_size + icon_padding;
}
- int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
- if (but->editstr) {
- rect->xmin += text_padding;
- }
- else if (but->flag & UI_BUT_DRAG_MULTI) {
- bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
- if (text_is_edited) {
+ if (!no_text_padding) {
+ int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
+ if (but->editstr) {
rect->xmin += text_padding;
}
- }
- else if (but->drawflag & UI_BUT_TEXT_LEFT) {
- rect->xmin += text_padding;
- }
- else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
- rect->xmax -= text_padding;
+ else if (but->flag & UI_BUT_DRAG_MULTI) {
+ bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
+ if (text_is_edited) {
+ rect->xmin += text_padding;
+ }
+ }
+ else if (but->drawflag & UI_BUT_TEXT_LEFT) {
+
+ /* Reduce the left padding for labels without an icon. */
+ if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) &&
+ !ui_block_is_menu(but->block)) {
+ text_padding /= 2;
+ }
+
+ rect->xmin += text_padding;
+ }
+ else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
+ rect->xmax -= text_padding;
+ }
}
/* Menu contains sub-menu items with triangle icon on their right. Shortcut
@@ -4127,10 +4188,10 @@ static void widget_optionbut(uiWidgetColors *wcol,
/* smaller */
delta = 1 + BLI_rcti_size_y(&recttemp) / 8;
- recttemp.xmin += delta;
- recttemp.ymin += delta;
- recttemp.xmax -= delta;
- recttemp.ymax -= delta;
+ BLI_rcti_resize(
+ &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
+ /* Keep one edge in place. */
+ BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
@@ -4142,13 +4203,13 @@ static void widget_optionbut(uiWidgetColors *wcol,
widgetbase_draw(&wtb, wcol);
- /* text space */
- const float offset = BLI_rcti_size_y(rect) * 0.7 + delta;
+ /* Text space - factor is really just eyeballed. */
+ const float offset = delta * 0.9;
if (text_before_widget) {
- rect->xmax -= offset;
+ rect->xmax = recttemp.xmin - offset;
}
else {
- rect->xmin += offset;
+ rect->xmin = recttemp.xmax + offset;
}
}
@@ -4204,7 +4265,7 @@ static void widget_box(
copy_v3_v3_uchar(old_col, wcol->inner);
/* abuse but->hsv - if it's non-zero, use this color as the box's background */
- if (but->col[3]) {
+ if (but != NULL && but->col[3]) {
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
@@ -4597,7 +4658,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
* \{ */
/* conversion from old to new buttons, so still messy */
-void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
+void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
bTheme *btheme = UI_GetTheme();
const ThemeUI *tui = &btheme->tui;
@@ -4705,9 +4766,14 @@ void ui_draw_but(const bContext *C, ARegion *region, uiStyle *style, uiBut *but,
case UI_BTYPE_CHECKBOX_N:
if (!(but->flag & UI_HAS_ICON)) {
wt = widget_type(UI_WTYPE_CHECKBOX);
+
if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
+ /* widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
+ * text drawing were to add its own padding, DPI and zoom factor would be applied twice
+ * in the final padding, so it's difficult to control it. */
+ but->drawflag |= UI_BUT_NO_TEXT_PADDING;
}
else {
wt = widget_type(UI_WTYPE_TOGGLE);
@@ -4955,6 +5021,30 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
/**
+ * Uses the widget base drawing and colors from from the box widget, but ensures an opaque
+ * inner color.
+ */
+void ui_draw_box_opaque(rcti *rect, int roundboxalign)
+{
+ uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
+
+ /* Alpha blend with the region's background color to force an opaque background. */
+ uiWidgetColors *wcol = &wt->wcol;
+ wt->state(wt, 0, 0);
+ float background[4];
+ UI_GetThemeColor4fv(TH_BACK, background);
+ float new_inner[4];
+ rgba_uchar_to_float(new_inner, wcol->inner);
+ new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3]));
+ new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3]));
+ new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3]));
+ new_inner[3] = 1.0f;
+ rgba_float_to_uchar(wcol->inner, new_inner);
+
+ wt->custom(NULL, wcol, rect, 0, roundboxalign);
+}
+
+/**
* Similar to 'widget_menu_back', however we can't use the widget preset system
* because we need to pass in the original location so we know where to show the arrow.
*/
@@ -5027,7 +5117,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
GPU_blend(false);
}
-void ui_draw_popover_back(ARegion *region, uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
+void ui_draw_popover_back(struct ARegion *region,
+ uiStyle *UNUSED(style),
+ uiBlock *block,
+ rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
@@ -5258,10 +5351,23 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl
wt->draw(&wt->wcol, rect, 0, 0);
}
-/* helper call to draw a menu item without button */
-/* state: UI_ACTIVE or 0 */
-void ui_draw_menu_item(
- const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep)
+/**
+ * Helper call to draw a menu item without a button.
+ *
+ * \param state: The state of the button,
+ * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
+ * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned,
+ * use for displaying key shortcuts.
+ * \param r_xmax: The right hand position of the text, this takes into the icon,
+ * padding and text clipping when there is not enough room to display the full text.
+ */
+void ui_draw_menu_item(const uiFontStyle *fstyle,
+ rcti *rect,
+ const char *name,
+ int iconid,
+ int state,
+ bool use_sep,
+ int *r_xmax)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
rcti _rect = *rect;
@@ -5280,7 +5386,7 @@ void ui_draw_menu_item(
/* cut string in 2 parts? */
if (use_sep) {
- cpoin = strchr(name, UI_SEP_CHAR);
+ cpoin = strrchr(name, UI_SEP_CHAR);
if (cpoin) {
*cpoin = 0;
@@ -5311,27 +5417,21 @@ void ui_draw_menu_item(
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
}
- UI_fontstyle_draw(fstyle,
- rect,
- drawstr,
- wt->wcol.text,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_LEFT,
- });
- }
-
- /* part text right aligned */
- if (use_sep) {
- if (cpoin) {
- rect->xmax = _rect.xmax - 5;
- UI_fontstyle_draw(fstyle,
- rect,
- cpoin + 1,
- wt->wcol.text,
- &(struct uiFontStyleDraw_Params){
- .align = UI_STYLE_TEXT_RIGHT,
- });
- *cpoin = UI_SEP_CHAR;
+ int xofs = 0, yofs = 0;
+ struct ResultBLF info;
+ UI_fontstyle_draw_ex(fstyle,
+ rect,
+ drawstr,
+ wt->wcol.text,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_LEFT,
+ },
+ BLF_DRAW_STR_DUMMY_MAX,
+ &xofs,
+ &yofs,
+ &info);
+ if (r_xmax != NULL) {
+ *r_xmax = xofs + info.width;
}
}
@@ -5351,6 +5451,24 @@ void ui_draw_menu_item(
UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
GPU_blend(false);
}
+
+ /* part text right aligned */
+ if (use_sep) {
+ if (cpoin) {
+ /* Set inactive state for grayed out text. */
+ wt->state(wt, state | UI_BUT_INACTIVE, 0);
+
+ rect->xmax = _rect.xmax - 5;
+ UI_fontstyle_draw(fstyle,
+ rect,
+ cpoin + 1,
+ wt->wcol.text,
+ &(struct uiFontStyleDraw_Params){
+ .align = UI_STYLE_TEXT_RIGHT,
+ });
+ *cpoin = UI_SEP_CHAR;
+ }
+ }
}
void ui_draw_preview_item(
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index e5af8768e6e..01c9716ec86 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1198,7 +1198,7 @@ void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColorType4fv(int colorid, int spacetype, float col[4])
{
- const unsigned char *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
+ const uchar *cp = UI_ThemeGetColorPtr(theme_active, spacetype, colorid);
col[0] = ((float)cp[0]) / 255.0f;
col[1] = ((float)cp[1]) / 255.0f;
col[2] = ((float)cp[2]) / 255.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index a93c80f02d2..f8419ba3eba 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -33,6 +33,7 @@
#include "BLI_array.h"
#include "BLI_link_utils.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_rect.h"
@@ -59,7 +60,7 @@
#include "interface_intern.h"
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers);
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize);
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
@@ -67,8 +68,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
BLI_INLINE int clamp_float_to_int(const float f)
{
- const float min = INT_MIN;
- const float max = INT_MAX;
+ const float min = (float)INT_MIN;
+ const float max = (float)INT_MAX;
if (UNLIKELY(f < min)) {
return min;
@@ -133,7 +134,7 @@ void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask)
*
* \param mask_scroll: Optionally clamp scrollbars by this region.
*/
-static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scroll)
+static void view2d_masks(View2D *v2d, const rcti *mask_scroll)
{
int scroll;
@@ -143,26 +144,24 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr
mask_scroll = &v2d->mask;
}
- if (check_scrollers) {
- /* check size if hiding flag is set: */
- if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
- if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
- }
+ /* check size if hiding flag is set: */
+ if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) {
+ if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR;
}
}
- if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
- if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
- if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
- v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
- }
- else {
- v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
- }
+ }
+ if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) {
+ if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) {
+ if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) {
+ v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR;
+ }
+ else {
+ v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR;
}
}
}
@@ -268,7 +267,6 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
*/
v2d->align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_NEG_Y);
v2d->keeptot = V2D_KEEPTOT_BOUNDS;
-
if (do_init) {
v2d->tot.xmin = v2d->tot.ymin = 0.0f;
v2d->tot.xmax = (float)(winx - 1);
@@ -385,8 +383,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->winx = winx;
v2d->winy = winy;
- /* set masks (always do), but leave scroller scheck to totrect_set */
- view2d_masks(v2d, 0, NULL);
+ view2d_masks(v2d, NULL);
if (do_init) {
/* Visible by default. */
@@ -394,13 +391,12 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
/* set 'tot' rect before setting cur? */
- /* XXX confusing stuff here still -
- * I made this function not check scroller hide - that happens in totrect_set */
+ /* XXX confusing stuff here still */
if (tot_changed) {
UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init);
}
else {
- ui_view2d_curRect_validate_resize(v2d, !do_init, 0);
+ ui_view2d_curRect_validate_resize(v2d, !do_init);
}
}
@@ -409,7 +405,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
* 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot'
*/
// XXX pre2.5 -> this used to be called test_view2d()
-static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers)
+static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize)
{
float totwidth, totheight, curwidth, curheight, width, height;
float winx, winy;
@@ -851,12 +847,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas
}
/* set masks */
- view2d_masks(v2d, mask_scrollers, NULL);
+ view2d_masks(v2d, NULL);
}
void UI_view2d_curRect_validate(View2D *v2d)
{
- ui_view2d_curRect_validate_resize(v2d, 0, 1);
+ ui_view2d_curRect_validate_resize(v2d, false);
}
/* ------------------ */
@@ -865,7 +861,6 @@ void UI_view2d_curRect_validate(View2D *v2d)
* to make sure 'related' views stay in synchrony */
void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
{
- ScrArea *sa;
ARegion *region;
/* don't continue if no view syncing to be done */
@@ -900,8 +895,8 @@ void UI_view2d_sync(bScreen *screen, ScrArea *area, View2D *v2dcur, int flag)
/* check if doing whole screen syncing (i.e. time/horizontal) */
if ((v2dcur->flag & V2D_VIEWSYNC_SCREEN_TIME) && (screen)) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
+ for (region = area_iter->regionbase.first; region; region = region->next) {
/* don't operate on self */
if (v2dcur != &region->v2d) {
/* only if view has horizontal locks enabled */
@@ -983,22 +978,10 @@ void UI_view2d_curRect_reset(View2D *v2d)
/* Change the size of the maximum viewable area (i.e. 'tot' rect) */
void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize)
{
- // int scroll = view2d_scroll_mapped(v2d->scroll);
-
/* don't do anything if either value is 0 */
width = abs(width);
height = abs(height);
- /* hrumf! */
- /* XXX: there are work arounds for this in the panel and file browse code. */
- /* round to int, because this is called with width + V2D_SCROLL_WIDTH */
- // if (scroll & V2D_SCROLL_HORIZONTAL) {
- // width -= (int)V2D_SCROLL_WIDTH;
- // }
- // if (scroll & V2D_SCROLL_VERTICAL) {
- // height -= (int)V2D_SCROLL_HEIGHT;
- // }
-
if (ELEM(0, width, height)) {
if (G.debug & G_DEBUG) {
printf("Error: View2D totRect set exiting: v2d=%p width=%d height=%d\n",
@@ -1048,20 +1031,12 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resiz
}
/* make sure that 'cur' rect is in a valid state as a result of these changes */
- ui_view2d_curRect_validate_resize(v2d, resize, 1);
+ ui_view2d_curRect_validate_resize(v2d, resize);
}
void UI_view2d_totRect_set(View2D *v2d, int width, int height)
{
- int scroll = view2d_scroll_mapped(v2d->scroll);
-
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
-
- /* solve bad recursion... if scroller state changed,
- * mask is different, so you get different rects */
- if (scroll != view2d_scroll_mapped(v2d->scroll)) {
- UI_view2d_totRect_set_resize(v2d, width, height, 0);
- }
+ UI_view2d_totRect_set_resize(v2d, width, height, false);
}
bool UI_view2d_tab_set(View2D *v2d, int tab)
@@ -1259,7 +1234,7 @@ void UI_view2d_view_restore(const bContext *C)
* \{ */
/* Draw a constant grid in given 2d-region */
-void UI_view2d_constant_grid_draw(View2D *v2d, float step)
+void UI_view2d_constant_grid_draw(const View2D *v2d, float step)
{
float start_x, start_y;
int count_x, count_y;
@@ -1331,7 +1306,8 @@ void UI_view2d_constant_grid_draw(View2D *v2d, float step)
}
/* Draw a multi-level grid in given 2d-region */
-void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels)
+void UI_view2d_multi_grid_draw(
+ const View2D *v2d, int colorid, float step, int level_size, int totlevels)
{
/* Exit if there is nothing to draw */
if (totlevels == 0) {
@@ -1449,7 +1425,7 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom)
scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers");
/* Always update before drawing (for dynamically sized scrollers). */
- view2d_masks(v2d, false, mask_custom);
+ view2d_masks(v2d, mask_custom);
vert = v2d->vert;
hor = v2d->hor;
@@ -1802,7 +1778,8 @@ bool UI_view2d_view_to_region_clip(
* \param x, y: Coordinates to convert.
* \param r_region_x, r_region_y: Resultant coordinates.
*/
-void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
+void UI_view2d_view_to_region(
+ const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y)
{
/* step 1: express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1818,7 +1795,7 @@ void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, in
}
void UI_view2d_view_to_region_fl(
- View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
+ const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y)
{
/* express given coordinates as proportional values */
x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
@@ -1829,7 +1806,7 @@ void UI_view2d_view_to_region_fl(
*r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask));
}
-void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+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)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1850,7 +1827,7 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect
clamp_rctf_to_rcti(rect_dst, &rect_tmp);
}
-void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
+void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4])
{
rctf mask;
unit_m4(matrix);
@@ -1858,7 +1835,7 @@ void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4])
BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix);
}
-bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst)
+bool UI_view2d_view_to_region_rcti_clip(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)};
const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)};
@@ -1915,17 +1892,17 @@ View2D *UI_view2d_fromcontext(const bContext *C)
/* same as above, but it returns regionwindow. Utility for pulldowns or buttons */
View2D *UI_view2d_fromcontext_rwin(const bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (sa == NULL) {
+ if (area == NULL) {
return NULL;
}
if (region == NULL) {
return NULL;
}
if (region->regiontype != RGN_TYPE_WINDOW) {
- ARegion *region_win = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ARegion *region_win = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
return region_win ? &(region_win->v2d) : NULL;
}
return &(region->v2d);
@@ -1984,7 +1961,7 @@ float UI_view2d_scale_get_y(const View2D *v2d)
/**
* Same as ``UI_view2d_scale_get() - 1.0f / x, y``
*/
-void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
*r_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
@@ -1998,7 +1975,7 @@ void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y)
* Simple functions for consistent center offset access.
* Used by node editor to shift view center for each individual node tree.
*/
-void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y)
+void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y)
{
/* get center */
if (r_x) {
diff --git a/source/blender/editors/interface/view2d_draw.c b/source/blender/editors/interface/view2d_draw.c
index 17a95ba3fff..677043c1ccf 100644
--- a/source/blender/editors/interface/view2d_draw.c
+++ b/source/blender/editors/interface/view2d_draw.c
@@ -40,6 +40,7 @@
#include "GPU_immediate.h"
#include "GPU_matrix.h"
+#include "GPU_state.h"
#include "WM_api.h"
@@ -196,7 +197,19 @@ static void draw_parallel_lines(const ParallelLinesSet *lines,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (U.pixelsize > 1.0f) {
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ /* -1.0f offset here is because the line is too fat due to the builtin anti-aliasing.
+ * TODO make a variant or a uniform to toggle it off. */
+ immUniform1f("lineWidth", U.pixelsize - 1.0f);
+ }
+ else {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ }
immUniformColor3ubv(color);
immBegin(GPU_PRIM_LINES, steps * 2);
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 2adf441514b..5b1e5f746ef 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -79,9 +79,9 @@ static bool view2d_poll(bContext *C)
*/
typedef struct v2dViewPanData {
/** screen where view pan was initiated */
- bScreen *sc;
+ bScreen *screen;
/** area where view pan was initiated */
- ScrArea *sa;
+ ScrArea *area;
/** region where view pan was initiated */
ARegion *region;
/** view2d we're operating in */
@@ -126,8 +126,8 @@ static int view_pan_init(bContext *C, wmOperator *op)
op->customdata = vpd;
/* set pointers to owners */
- vpd->sc = CTX_wm_screen(C);
- vpd->sa = CTX_wm_area(C);
+ vpd->screen = CTX_wm_screen(C);
+ vpd->area = CTX_wm_area(C);
vpd->v2d = v2d;
vpd->region = region;
@@ -190,7 +190,7 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float
/* request updates to be done... */
WM_event_add_mousemove(CTX_wm_window(C));
- UI_view2d_sync(vpd->sc, vpd->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(vpd->screen, vpd->area, v2d, V2D_LOCK_COPY);
}
static void view_pan_apply(bContext *C, wmOperator *op)
@@ -589,13 +589,13 @@ typedef struct v2dViewZoomData {
*/
static void view_zoom_axis_lock_defaults(bContext *C, bool r_do_zoom_xy[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
r_do_zoom_xy[0] = true;
r_do_zoom_xy[1] = true;
/* default not to zoom the sequencer vertically */
- if (sa && sa->spacetype == SPACE_SEQ) {
+ if (area && area->spacetype == SPACE_SEQ) {
ARegion *region = CTX_wm_region(C);
if (region && region->regiontype == RGN_TYPE_WINDOW) {
@@ -758,8 +758,8 @@ static void view_zoomstep_apply_ex(
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -1017,8 +1017,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op)
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(vzd->region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -2211,8 +2211,8 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op))
UI_view2d_curRect_validate(v2d);
if (ED_region_snap_size_apply(region, snap_test)) {
- ScrArea *sa = CTX_wm_area(C);
- ED_area_tag_redraw(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index af17303466b..dc8ad858a9f 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
@@ -663,7 +663,7 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op)
/* Switch out of edit mode to avoid being stuck in it (T54326). */
Object *obedit = CTX_data_edit_object(C);
if (obedit) {
- ED_object_mode_toggle(C, OB_MODE_EDIT);
+ ED_object_mode_set(C, OB_MODE_OBJECT);
}
bool ok = ABC_import(C,
diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h
index 881712fe630..ecd8c1818f8 100644
--- a/source/blender/editors/io/io_alembic.h
+++ b/source/blender/editors/io/io_alembic.h
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c
index 6c5abf60272..045a293f71b 100644
--- a/source/blender/editors/io/io_cache.c
+++ b/source/blender/editors/io/io_cache.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h
index 25548dcdbce..c6fc50a236e 100644
--- a/source/blender/editors/io/io_cache.h
+++ b/source/blender/editors/io/io_cache.h
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2016 Blender Foundation.
diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c
index bb527ee6a3f..262b15c63e5 100644
--- a/source/blender/editors/io/io_usd.c
+++ b/source/blender/editors/io/io_usd.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2019 Blender Foundation.
diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h
index 4738e1c348d..c794dc744df 100644
--- a/source/blender/editors/io/io_usd.h
+++ b/source/blender/editors/io/io_usd.h
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2019 Blender Foundation.
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 5d461ffdb20..767976b5ae6 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -29,7 +29,6 @@
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
@@ -445,11 +444,11 @@ static void mask_point_make_pixel_space(bContext *C,
float point_normalized[2],
float point_pixel[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float scalex, scaley;
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
point_pixel[0] = point_normalized[0] * scalex;
point_pixel[1] = point_normalized[1] * scaley;
@@ -557,12 +556,12 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -649,12 +648,12 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
static int add_feather_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -694,7 +693,7 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot)
static int create_primitive_from_points(
bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Mask *mask;
MaskLayer *mask_layer;
MaskSpline *new_spline;
@@ -702,7 +701,7 @@ static int create_primitive_from_points(
int i, width, height;
int size = RNA_float_get(op->ptr, "size");
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
scale = (float)size / max_ii(width, height);
/* Get location in mask space. */
@@ -763,12 +762,12 @@ static int create_primitive_from_points(
static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
float cursor[2];
int width, height;
- ED_mask_get_size(sa, &width, &height);
- ED_mask_cursor_location_get(sa, cursor);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_cursor_location_get(area, cursor);
cursor[0] *= width;
cursor[1] *= height;
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index a532ff9e1f0..3786ed2789c 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -54,12 +54,10 @@
#include "DEG_depsgraph_query.h"
-#include "mask_intern.h" /* own include */
-
static void mask_spline_color_get(MaskLayer *mask_layer,
MaskSpline *spline,
const bool is_sel,
- unsigned char r_rgb[4])
+ uchar r_rgb[4])
{
if (is_sel) {
if (mask_layer->act_spline == spline) {
@@ -81,7 +79,7 @@ static void mask_spline_color_get(MaskLayer *mask_layer,
static void mask_spline_feather_color_get(MaskLayer *UNUSED(mask_layer),
MaskSpline *UNUSED(spline),
const bool is_sel,
- unsigned char r_rgb[4])
+ uchar r_rgb[4])
{
if (is_sel) {
r_rgb[1] = 255;
@@ -126,7 +124,7 @@ static void draw_single_handle(const MaskLayer *mask_layer,
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- const unsigned char rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
+ const uchar rgb_gray[4] = {0x60, 0x60, 0x60, 0xff};
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ubv(rgb_gray);
@@ -196,7 +194,7 @@ static void draw_spline_points(const bContext *C,
(mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
- unsigned char rgb_spline[4];
+ uchar rgb_spline[4];
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
SpaceClip *sc = CTX_wm_space_clip(C);
bool undistort = false;
@@ -370,28 +368,26 @@ static void draw_spline_points(const bContext *C,
}
}
-static void mask_color_active_tint(unsigned char r_rgb[4],
- const unsigned char rgb[4],
- const bool is_active)
+static void mask_color_active_tint(uchar r_rgb[4], const uchar rgb[4], const bool is_active)
{
if (!is_active) {
- r_rgb[0] = (unsigned char)((((int)(rgb[0])) + 128) / 2);
- r_rgb[1] = (unsigned char)((((int)(rgb[1])) + 128) / 2);
- r_rgb[2] = (unsigned char)((((int)(rgb[2])) + 128) / 2);
+ r_rgb[0] = (uchar)((((int)(rgb[0])) + 128) / 2);
+ r_rgb[1] = (uchar)((((int)(rgb[1])) + 128) / 2);
+ r_rgb[2] = (uchar)((((int)(rgb[2])) + 128) / 2);
r_rgb[3] = rgb[3];
}
else {
- *(unsigned int *)r_rgb = *(const unsigned int *)rgb;
+ *(uint *)r_rgb = *(const uint *)rgb;
}
}
-static void mask_draw_array(unsigned int pos,
+static void mask_draw_array(uint pos,
GPUPrimType prim_type,
const float (*points)[2],
- unsigned int vertex_len)
+ uint vertex_len)
{
immBegin(prim_type, vertex_len);
- for (unsigned int i = 0; i < vertex_len; i++) {
+ for (uint i = 0; i < vertex_len; i++) {
immVertex2fv(pos, points[i]);
}
immEnd();
@@ -403,13 +399,13 @@ static void mask_draw_curve_type(const bContext *C,
int tot_point,
const bool is_feather,
const bool is_active,
- const unsigned char rgb_spline[4],
+ const uchar rgb_spline[4],
const char draw_type)
{
const GPUPrimType draw_method = (spline->flag & MASK_SPLINE_CYCLIC) ? GPU_PRIM_LINE_LOOP :
GPU_PRIM_LINE_STRIP;
- const unsigned char rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
- unsigned char rgb_tmp[4];
+ const uchar rgb_black[4] = {0x00, 0x00, 0x00, 0xff};
+ uchar rgb_tmp[4];
SpaceClip *sc = CTX_wm_space_clip(C);
float(*points)[2] = orig_points;
@@ -471,9 +467,9 @@ static void mask_draw_curve_type(const bContext *C,
}
if (is_feather) {
- rgb_tmp[0] = (unsigned char)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
- rgb_tmp[1] = (unsigned char)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
- rgb_tmp[2] = (unsigned char)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
+ rgb_tmp[0] = (uchar)(((short)rgb_tmp[0] + (short)rgb_spline[0]) / 2);
+ rgb_tmp[1] = (uchar)(((short)rgb_tmp[1] + (short)rgb_spline[1]) / 2);
+ rgb_tmp[2] = (uchar)(((short)rgb_tmp[2] + (short)rgb_spline[2]) / 2);
}
mask_color_active_tint(rgb_tmp, rgb_tmp, is_active);
@@ -527,20 +523,20 @@ static void draw_spline_curve(const bContext *C,
const int width,
const int height)
{
- const unsigned int resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
- BKE_mask_spline_resolution(spline, width, height));
+ const uint resol = max_ii(BKE_mask_spline_feather_resolution(spline, width, height),
+ BKE_mask_spline_resolution(spline, width, height));
- unsigned char rgb_tmp[4];
+ uchar rgb_tmp[4];
const bool is_spline_sel = (spline->flag & SELECT) &&
(mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
- unsigned int tot_diff_point;
+ uint tot_diff_point;
float(*diff_points)[2];
- unsigned int tot_feather_point;
+ uint tot_feather_point;
float(*feather_points)[2];
diff_points = BKE_mask_spline_differentiate_with_resolution(spline, &tot_diff_point, resol);
@@ -614,7 +610,7 @@ static void draw_mask_layers(const bContext *C,
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
/* draw curve itself first... */
draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
@@ -642,7 +638,7 @@ static void draw_mask_layers(const bContext *C,
void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Mask *mask = CTX_data_edit_mask(C);
int width, height;
@@ -650,7 +646,7 @@ void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
return;
}
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
draw_mask_layers(C, mask, draw_flag, draw_type, width, height);
}
@@ -756,7 +752,7 @@ void ED_mask_draw_region(
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, 0.0f, 0.0f, width, height, GL_RED, GL_FLOAT, GL_NEAREST, buffer, 1.0f, 1.0f, NULL);
@@ -803,7 +799,7 @@ void ED_mask_draw_frames(
return;
}
- unsigned int num_lines = BLI_listbase_count(&mask_layer->splines_shapes);
+ uint num_lines = BLI_listbase_count(&mask_layer->splines_shapes);
if (num_lines == 0) {
return;
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index e18c4992671..663ae0097ad 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -21,12 +21,9 @@
* \ingroup edmask
*/
-#include "BLI_math.h"
-
#include "BKE_context.h"
#include "BKE_mask.h"
-#include "DNA_mask_types.h"
#include "DNA_scene_types.h"
#include "WM_api.h"
@@ -34,14 +31,8 @@
#include "ED_clip.h"
#include "ED_image.h"
-#include "ED_mask.h" /* own include */
-#include "ED_object.h" /* ED_keymap_proportional_maskmode only */
-#include "ED_screen.h"
-#include "ED_select_utils.h"
+#include "ED_mask.h" /* own include */
#include "ED_sequencer.h"
-#include "ED_transform.h"
-
-#include "UI_view2d.h"
#include "RNA_access.h"
@@ -53,9 +44,9 @@
bool ED_maskedit_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_poll(C);
case SPACE_SEQ:
@@ -69,9 +60,9 @@ bool ED_maskedit_poll(bContext *C)
bool ED_maskedit_mask_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP:
return ED_space_clip_maskedit_mask_poll(C);
case SPACE_SEQ:
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index 758d0abbab7..68dfe0d151f 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -31,7 +31,6 @@
#include "BKE_mask.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h" /* SELECT */
@@ -56,16 +55,16 @@
Mask *ED_mask_new(bContext *C, const char *name)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Main *bmain = CTX_data_main(C);
Mask *mask;
mask = BKE_mask_new(bmain, name);
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_set_mask(C, sc, mask);
break;
}
@@ -74,7 +73,7 @@ Mask *ED_mask_new(bContext *C, const char *name)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_set_mask(C, sima, mask);
break;
}
@@ -261,7 +260,7 @@ static bool spline_under_mouse_get(const bContext *C,
MaskSpline **r_mask_spline)
{
const float threshold = 19.0f;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
int width, height;
float pixel_co[2];
@@ -271,7 +270,7 @@ static bool spline_under_mouse_get(const bContext *C,
bool undistort = false;
*r_mask_layer = NULL;
*r_mask_spline = NULL;
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_get_size(area, &width, &height);
pixel_co[0] = co[0] * width;
pixel_co[1] = co[1] * height;
if (sc != NULL) {
@@ -421,7 +420,7 @@ static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle w
static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -436,8 +435,8 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
const float threshold = 19;
eMaskWhichHandle which_handle;
- ED_mask_mouse_pos(sa, region, event->mval, co);
- ED_mask_get_size(sa, &width, &height);
+ ED_mask_mouse_pos(area, region, event->mval, co);
+ ED_mask_get_size(area, &width, &height);
cv_point = ED_mask_point_find_nearest(
C, mask, co, threshold, &cv_mask_layer, &cv_spline, &which_handle, &cv_score);
@@ -535,7 +534,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
}
customdata->which_handle = which_handle;
- ED_mask_mouse_pos(sa, region, event->mval, customdata->prev_mouse_coord);
+ ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord);
}
return customdata;
@@ -659,11 +658,11 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
ATTR_FALLTHROUGH; /* update CV position */
case MOUSEMOVE: {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float delta[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
sub_v2_v2v2(delta, co, data->prev_mouse_coord);
if (data->is_accurate) {
mul_v2_fl(delta, 0.2f);
@@ -1294,12 +1293,12 @@ static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
spline->flag ^= MASK_SPLINE_CYCLIC;
}
@@ -1372,7 +1371,7 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskSpline *spline;
int mask_layer_shape_ofs = 0;
@@ -1494,14 +1493,14 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
bool changed_layer = false;
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
BKE_mask_spline_direction_switch(mask_layer, spline);
changed = true;
@@ -1552,14 +1551,14 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
bool changed_layer = false;
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1615,12 +1614,12 @@ static int set_handle_type_exec(bContext *C, wmOperator *op)
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1696,7 +1695,7 @@ static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
bool changed = false;
const bool select = RNA_boolean_get(op->ptr, "select");
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & OB_RESTRICT_VIEWPORT) {
ED_mask_layer_select_set(mask_layer, select);
@@ -1740,7 +1739,7 @@ static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
@@ -1802,12 +1801,12 @@ static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -1936,7 +1935,7 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
for (MaskSpline *spline = mask_layer->splines.last; spline; spline = spline->prev) {
MaskSplinePoint *point = spline->points;
int i = 0;
diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c
index 4459607191f..cf5997d8a18 100644
--- a/source/blender/editors/mask/mask_query.c
+++ b/source/blender/editors/mask/mask_query.c
@@ -35,20 +35,12 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
-#include "WM_api.h"
-#include "WM_types.h"
-
#include "ED_clip.h"
#include "ED_image.h"
#include "ED_mask.h" /* own include */
-#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "UI_view2d.h"
-#include "RNA_access.h"
-#include "RNA_define.h"
-
#include "mask_intern.h" /* own include */
/* -------------------------------------------------------------------- */
@@ -69,7 +61,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
float *r_u,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer;
@@ -83,8 +75,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -107,13 +99,13 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
for (i = 0, cur_point_eval = use_deform ? spline_eval->points_deform : spline_eval->points;
i < spline_eval->tot_point;
i++, cur_point_eval++) {
- unsigned int tot_diff_point;
+ uint tot_diff_point;
float *diff_points = BKE_mask_point_segment_diff(
spline_eval, cur_point_eval, width, height, &tot_diff_point);
if (diff_points) {
int j, tot_point;
- unsigned int tot_feather_point;
+ uint tot_feather_point;
float *feather_points = NULL, *points;
if (feather) {
@@ -227,7 +219,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
eMaskWhichHandle *r_which_handle,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer = NULL;
@@ -242,8 +234,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -382,7 +374,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
MaskSplinePointUW **r_uw,
float *r_score)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
MaskLayer *point_mask_layer = NULL;
@@ -397,8 +389,8 @@ bool ED_mask_feather_find_nearest(const bContext *C,
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Mask *mask_eval = (Mask *)DEG_get_evaluated_id(depsgraph, &mask_orig->id);
- ED_mask_get_size(sa, &width, &height);
- ED_mask_pixelspace_factor(sa, region, &scalex, &scaley);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_pixelspace_factor(area, region, &scalex, &scaley);
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
@@ -498,12 +490,12 @@ bool ED_mask_feather_find_nearest(const bContext *C,
}
/* takes event->mval */
-void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co[2])
+void ED_mask_mouse_pos(ScrArea *area, ARegion *region, const int mval[2], float co[2])
{
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_clip_mouse_pos(sc, region, mval, co);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
@@ -513,7 +505,7 @@ void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_image_mouse_pos(sima, region, mval, co);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
@@ -533,14 +525,14 @@ void ED_mask_mouse_pos(ScrArea *sa, ARegion *region, const int mval[2], float co
/* input: x/y - mval space
* output: xr/yr - mask point space */
-void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr, float *yr)
+void ED_mask_point_pos(ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_clip_point_stable_pos(sc, region, x, y, &co[0], &co[1]);
BKE_mask_coord_from_movieclip(sc->clip, &sc->user, co, co);
break;
@@ -549,7 +541,7 @@ void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_image_point_pos(sima, region, x, y, &co[0], &co[1]);
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, co);
break;
@@ -571,14 +563,14 @@ void ED_mask_point_pos(ScrArea *sa, ARegion *region, float x, float y, float *xr
}
void ED_mask_point_pos__reverse(
- ScrArea *sa, ARegion *region, float x, float y, float *xr, float *yr)
+ ScrArea *area, ARegion *region, float x, float y, float *xr, float *yr)
{
float co[2];
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, co, co);
@@ -589,7 +581,7 @@ void ED_mask_point_pos__reverse(
zero_v2(co); /* MASKTODO */
break;
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
co[0] = x;
co[1] = y;
BKE_mask_coord_to_image(sima->image, &sima->iuser, co, co);
@@ -667,12 +659,12 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
/** \name Generic 2D View Queries
* \{ */
-void ED_mask_get_size(ScrArea *sa, int *width, int *height)
+void ED_mask_get_size(ScrArea *area, int *width, int *height)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_size(sc, width, height);
break;
}
@@ -683,7 +675,7 @@ void ED_mask_get_size(ScrArea *sa, int *width, int *height)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_size(sima, width, height);
break;
}
@@ -702,12 +694,12 @@ void ED_mask_get_size(ScrArea *sa, int *width, int *height)
}
}
-void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
+void ED_mask_zoom(ScrArea *area, ARegion *region, float *zoomx, float *zoomy)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_zoom(sc, region, zoomx, zoomy);
break;
}
@@ -716,7 +708,7 @@ void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_zoom(sima, region, zoomx, zoomy);
break;
}
@@ -733,12 +725,12 @@ void ED_mask_zoom(ScrArea *sa, ARegion *region, float *zoomx, float *zoomy)
}
}
-void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float *aspy)
+void ED_mask_get_aspect(ScrArea *area, ARegion *UNUSED(region), float *aspx, float *aspy)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
ED_space_clip_get_aspect(sc, aspx, aspy);
break;
}
@@ -747,7 +739,7 @@ void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_get_aspect(sima, aspx, aspy);
break;
}
@@ -764,12 +756,12 @@ void ED_mask_get_aspect(ScrArea *sa, ARegion *UNUSED(region), float *aspx, float
}
}
-void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, float *scaley)
+void ED_mask_pixelspace_factor(ScrArea *area, ARegion *region, float *scalex, float *scaley)
{
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
+ SpaceClip *sc = area->spacedata.first;
float aspx, aspy;
UI_view2d_scale_get(&region->v2d, scalex, scaley);
@@ -784,7 +776,7 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, floa
break;
}
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
float aspx, aspy;
UI_view2d_scale_get(&region->v2d, scalex, scaley);
@@ -807,12 +799,12 @@ void ED_mask_pixelspace_factor(ScrArea *sa, ARegion *region, float *scalex, floa
}
}
-void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
+void ED_mask_cursor_location_get(ScrArea *area, float cursor[2])
{
- if (sa) {
- switch (sa->spacetype) {
+ if (area) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *space_clip = sa->spacedata.first;
+ SpaceClip *space_clip = area->spacedata.first;
copy_v2_v2(cursor, space_clip->cursor);
break;
}
@@ -821,7 +813,7 @@ void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
break;
}
case SPACE_IMAGE: {
- SpaceImage *space_image = sa->spacedata.first;
+ SpaceImage *space_image = area->spacedata.first;
copy_v2_v2(cursor, space_image->cursor);
break;
}
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 49eb4fbd4ca..971e1c948c9 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -21,6 +21,7 @@
* \ingroup edmask
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -44,12 +45,12 @@ static int mask_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -136,12 +137,12 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 53ef398ccd6..c8cddced99c 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_lasso_2d.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_utildefines.h"
@@ -38,7 +39,6 @@
#include "ED_clip.h"
#include "ED_mask.h" /* own include */
-#include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h"
@@ -74,7 +74,7 @@ bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
return false;
}
- for (const MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (const MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
return true;
}
@@ -85,8 +85,7 @@ bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
bool ED_mask_select_check(const Mask *mask)
{
- for (const MaskLayer *mask_layer = mask->masklayers.first; mask_layer;
- mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (const MaskLayer *, mask_layer, &mask->masklayers) {
if (ED_mask_layer_select_check(mask_layer)) {
return true;
}
@@ -122,7 +121,7 @@ void ED_mask_layer_select_set(MaskLayer *mask_layer, const bool do_select)
}
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
ED_mask_spline_select_set(spline, do_select);
}
}
@@ -138,7 +137,7 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
}
}
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & MASK_RESTRICT_VIEW) {
continue;
@@ -151,7 +150,7 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -167,8 +166,8 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
void ED_mask_select_flush_all(Mask *mask)
{
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
spline->flag &= ~SELECT;
/* intentionally _dont_ do this in the mask layer loop
@@ -386,12 +385,12 @@ static int select_exec(bContext *C, wmOperator *op)
static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
float co[2];
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
RNA_float_set_array(op->ptr, "location", co);
@@ -436,7 +435,7 @@ void MASK_OT_select(wmOperatorType *ot)
static int box_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -455,16 +454,16 @@ static int box_select_exec(bContext *C, wmOperator *op)
/* get rectangle from operator */
WM_operator_properties_border_to_rcti(op, &rect);
- ED_mask_point_pos(sa, region, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
- ED_mask_point_pos(sa, region, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
+ ED_mask_point_pos(area, region, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
+ ED_mask_point_pos(area, region, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (int i = 0; i < spline->tot_point; i++) {
@@ -522,11 +521,11 @@ void MASK_OT_select_box(wmOperatorType *ot)
* \{ */
static bool do_lasso_select_mask(bContext *C,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -541,15 +540,15 @@ static bool do_lasso_select_mask(bContext *C,
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (int i = 0; i < spline->tot_point; i++) {
@@ -566,7 +565,7 @@ static bool do_lasso_select_mask(bContext *C,
float screen_co[2];
/* point in screen coords */
- ED_mask_point_pos__reverse(sa,
+ ED_mask_point_pos__reverse(area,
region,
point_deform->bezt.vec[1][0],
point_deform->bezt.vec[1][1],
@@ -574,7 +573,7 @@ static bool do_lasso_select_mask(bContext *C,
&screen_co[1]);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
BKE_mask_point_select_set(point, select);
BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select);
changed = true;
@@ -595,14 +594,14 @@ static bool do_lasso_select_mask(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_mask(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_mask(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
@@ -652,7 +651,7 @@ static int mask_spline_point_inside_ellipse(BezTriple *bezt,
static int circle_select_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -668,14 +667,14 @@ static int circle_select_exec(bContext *C, wmOperator *op)
const int radius = RNA_int_get(op->ptr, "radius");
/* compute ellipse and position in unified coordinates */
- ED_mask_get_size(sa, &width, &height);
- ED_mask_zoom(sa, region, &zoomx, &zoomy);
+ ED_mask_get_size(area, &width, &height);
+ ED_mask_zoom(area, region, &zoomx, &zoomy);
width = height = max_ii(width, height);
ellipse[0] = width * zoomx / radius;
ellipse[1] = height * zoomy / radius;
- ED_mask_point_pos(sa, region, x, y, &offset[0], &offset[1]);
+ ED_mask_point_pos(area, region, x, y, &offset[0], &offset[1]);
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(op->customdata));
@@ -686,12 +685,12 @@ static int circle_select_exec(bContext *C, wmOperator *op)
}
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (i = 0; i < spline->tot_point; i++) {
@@ -749,7 +748,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
@@ -761,7 +760,7 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
const float threshold = 19;
bool changed = false;
- ED_mask_mouse_pos(sa, region, event->mval, co);
+ ED_mask_mouse_pos(area, region, event->mval, co);
point = ED_mask_point_find_nearest(C, mask, co, threshold, &mask_layer, &spline, NULL, NULL);
@@ -815,12 +814,12 @@ static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
bool changed = false;
/* do actual selection */
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
if (ED_mask_spline_select_check(spline)) {
ED_mask_spline_select_set(spline, true);
changed = true;
@@ -865,12 +864,12 @@ static int mask_select_more_less(bContext *C, bool more)
{
Mask *mask = CTX_data_edit_mask(C);
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
const bool cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
bool start_sel, end_sel, prev_sel, cur_sel;
int i;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 25b602d63c3..f264e67d35c 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -53,7 +53,7 @@ static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskLayerShape *mask_layer_shape;
if (!ED_mask_layer_select_check(mask_layer)) {
@@ -98,7 +98,7 @@ static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
MaskLayerShape *mask_layer_shape;
if (!ED_mask_layer_select_check(mask_layer)) {
@@ -146,7 +146,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
Mask *mask = CTX_data_edit_mask(C);
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
@@ -172,7 +172,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_reset->data;
shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape->data;
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -243,7 +243,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
const bool do_feather = RNA_boolean_get(op->ptr, "feather");
const bool do_location = RNA_boolean_get(op->ptr, "location");
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
@@ -324,7 +324,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_tmp->data;
shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape_tmp_rekey->data;
- for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -404,7 +404,7 @@ bool ED_mask_layer_shape_auto_key_all(Mask *mask, const int frame)
{
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
ED_mask_layer_shape_auto_key(mask_layer, frame);
changed = true;
}
@@ -416,7 +416,7 @@ bool ED_mask_layer_shape_auto_key_select(Mask *mask, const int frame)
{
bool changed = false;
- for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
if (!ED_mask_layer_select_check(mask_layer)) {
continue;
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 987447c3663..b303c4c7e4e 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -190,7 +190,7 @@ void paintface_reveal(bContext *C, Object *ob, const bool select)
/* Set tface seams based on edge data, uses hash table to find seam edges. */
-static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index, const bool select)
+static void select_linked_tfaces_with_seams(Mesh *me, const uint index, const bool select)
{
MPoly *mp;
MLoop *ml;
@@ -201,7 +201,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
BLI_bitmap *edge_tag = BLI_BITMAP_NEW(me->totedge, __func__);
BLI_bitmap *poly_tag = BLI_BITMAP_NEW(me->totpoly, __func__);
- if (index != (unsigned int)-1) {
+ if (index != (uint)-1) {
/* only put face under cursor in array */
mp = &me->mpoly[index];
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
@@ -267,7 +267,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
void paintface_select_linked(bContext *C, Object *ob, const int mval[2], const bool select)
{
Mesh *me;
- unsigned int index = (unsigned int)-1;
+ uint index = (uint)-1;
me = BKE_mesh_from_object(ob);
if (me == NULL || me->totpoly == 0) {
@@ -493,8 +493,10 @@ void paintvert_tag_select_update(struct bContext *C, struct Object *ob)
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
}
-/* note: if the caller passes false to flush_flags,
- * then they will need to run paintvert_flush_flags(ob) themselves */
+/**
+ * \note if the caller passes false to flush_flags,
+ * then they will need to run #paintvert_flush_flags(ob) themselves.
+ */
bool paintvert_deselect_all_visible(Object *ob, int action, bool flush_flags)
{
Mesh *me;
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index 1484dcfa92d..3c426e5d2b1 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -59,6 +59,7 @@ static Object *make_prim_init(bContext *C,
const char *idname,
const float loc[3],
const float rot[3],
+ const float scale[3],
ushort local_view_bits,
MakePrimitiveData *r_creation_data)
{
@@ -76,6 +77,13 @@ static Object *make_prim_init(bContext *C,
ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
+ if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) {
+ float scale_half[3];
+ copy_v3_v3(scale_half, scale);
+ mul_v3_fl(scale_half, 0.5f);
+ rescale_m4(r_creation_data->mat, scale_half);
+ }
+
return obedit;
}
@@ -112,9 +120,16 @@ static int add_primitive_plane_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Plane"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -164,15 +179,22 @@ static int add_primitive_cube_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cube"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -237,9 +259,16 @@ static int add_primitive_circle_exec(bContext *C, wmOperator *op)
cap_tri = (cap_end == 2);
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Circle"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
+
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -294,7 +323,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -303,11 +332,13 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cylinder"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
@@ -368,7 +399,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const int end_fill_type = RNA_enum_get(op->ptr, "end_fill_type");
@@ -377,9 +408,15 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Cone"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -447,9 +484,15 @@ static int add_primitive_grid_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Grid"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -514,10 +557,16 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Y', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"), loc, rot, local_view_bits, &creation_data);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Suzanne"),
+ loc,
+ rot,
+ NULL,
+ local_view_bits,
+ &creation_data);
dia = RNA_float_get(op->ptr, "size") / 2.0f;
mul_mat3_m4_fl(creation_data.mat, dia);
@@ -567,15 +616,21 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
- obedit = make_prim_init(
- C, CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"), loc, rot, local_view_bits, &creation_data);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
+ obedit = make_prim_init(C,
+ CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Sphere"),
+ loc,
+ rot,
+ scale,
+ local_view_bits,
+ &creation_data);
em = BKE_editmesh_from_object(obedit);
if (calc_uvs) {
@@ -629,17 +684,19 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
MakePrimitiveData creation_data;
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3];
+ float loc[3], rot[3], scale[3];
bool enter_editmode;
ushort local_view_bits;
const bool calc_uvs = RNA_boolean_get(op->ptr, "calc_uvs");
WM_operator_view3d_unit_defaults(C, op);
- ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL);
+ ED_object_add_generic_get_opts(
+ C, op, 'Z', loc, rot, scale, &enter_editmode, &local_view_bits, NULL);
obedit = make_prim_init(C,
CTX_DATA_(BLT_I18NCONTEXT_ID_MESH, "Icosphere"),
loc,
rot,
+ scale,
local_view_bits,
&creation_data);
em = BKE_editmesh_from_object(obedit);
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 10c290e2be9..e94412233ff 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -416,10 +416,10 @@ static bool edbm_bevel_calc(wmOperator *op)
static void edbm_bevel_exit(bContext *C, wmOperator *op)
{
BevelData *opdata = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
@@ -690,14 +690,14 @@ wmKeyMap *bevel_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Bevel Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Bevel Modal Map");
/* This function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Bevel Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Bevel Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_bevel");
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 1ea1501fc66..bf6c5a2f829 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -226,6 +226,7 @@ static bool edbm_extrude_ex(Object *obedit,
char htype,
const char hflag,
const bool use_normal_flip,
+ const bool use_dissolve_ortho_edges,
const bool use_mirror,
const bool use_select_history)
{
@@ -241,6 +242,7 @@ static bool edbm_extrude_ex(Object *obedit,
BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip);
+ BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", use_dissolve_ortho_edges);
BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag);
@@ -274,11 +276,27 @@ static bool edbm_extrude_ex(Object *obedit,
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
{
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset");
const int steps = RNA_int_get(op->ptr, "steps");
- const float offs = RNA_float_get(op->ptr, "offset");
- float dvec[3], tmat[3][3], bmat[3][3];
- short a;
+ const float scale_offset = RNA_float_get(op->ptr, "scale_offset");
+ float offset[3];
+
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d != NULL) {
+ normalize_v3_v3(offset, rv3d->persinv[2]);
+ }
+ else {
+ copy_v3_v3(offset, (const float[3]){0, 0, 1});
+ }
+ RNA_property_float_set_array(op->ptr, prop, offset);
+ }
+ else {
+ RNA_property_float_get_array(op->ptr, prop, offset);
+ }
+
+ mul_v3_fl(offset, scale_offset);
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
@@ -286,22 +304,19 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ float offset_local[3], tmat[3][3];
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /* dvec */
- normalize_v3_v3_length(dvec, rv3d->persinv[2], offs);
+ copy_m3_m4(tmat, obedit->obmat);
+ invert_m3(tmat);
+ mul_v3_m3v3(offset_local, tmat, offset);
- /* base correction */
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(tmat, bmat);
- mul_m3_v3(tmat, dvec);
-
- for (a = 0; a < steps; a++) {
- edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false);
-
- BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT);
+ for (int a = 0; a < steps; a++) {
+ edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false, true);
+ BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT);
}
EDBM_mesh_normals_update(em);
@@ -317,20 +332,23 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
void MESH_OT_extrude_repeat(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Extrude Repeat Mesh";
+ ot->name = "Extrude Repeat";
ot->description = "Extrude selected vertices, edges or faces repeatedly";
ot->idname = "MESH_OT_extrude_repeat";
/* api callbacks */
ot->exec = edbm_extrude_repeat_exec;
- ot->poll = ED_operator_editmesh_view3d;
+ ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f);
RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180);
+ PropertyRNA *prop = RNA_def_float_vector_xyz(
+ ot->srna, "offset", 3, NULL, -100000, 100000, "Offset", "Offset vector", -1000.0f, 1000.0f);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_float(ot->srna, "scale_offset", 1.0f, 0.0f, 1e12f, "Scale Offset", "", 0.0f, 100.0f);
}
/** \} */
@@ -343,6 +361,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot)
static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
{
const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
+ const bool use_dissolve_ortho_edges = RNA_boolean_get(op->ptr, "use_dissolve_ortho_edges");
const char htype = edbm_extrude_htype_from_em_select(em);
enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr;
bool changed = false;
@@ -385,7 +404,14 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op)
case NONE:
return false;
case ELEM_FLAG:
- changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true);
+ changed = edbm_extrude_ex(obedit,
+ em,
+ htype,
+ BM_ELEM_SELECT,
+ use_normal_flip,
+ use_dissolve_ortho_edges,
+ true,
+ true);
break;
case VERT_ONLY:
changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT);
@@ -449,6 +475,7 @@ void MESH_OT_extrude_region(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -503,6 +530,7 @@ void MESH_OT_extrude_context(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", "");
+ RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", "");
Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY);
}
@@ -824,7 +852,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
}
}
- edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true);
+ edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, false, true, true);
EDBM_op_callf(
vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat);
EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 75a36b68f8b..feb6b5aaca9 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -18,6 +18,7 @@
* \ingroup edmesh
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -1030,7 +1031,7 @@ static void gizmo_mesh_spin_redo_draw_prepare(const bContext *UNUSED(C), wmGizmo
* could shift because of float precision.
* Updates in this case are also redundant. */
bool is_modal = false;
- for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) {
+ LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) {
if (gz->state & WM_GIZMO_STATE_MODAL) {
is_modal = true;
break;
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index f2983f06da6..2eeada95eda 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -88,10 +88,10 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
"(%s)");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *sce = CTX_data_scene(C);
- if (sa) {
+ if (area) {
char flts_str[NUM_STR_REP_LEN * 2];
if (hasNumInput(&opdata->num_input)) {
outputNumInput(&opdata->num_input, flts_str, &sce->unit);
@@ -111,7 +111,7 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_boundary")),
WM_bool_as_string(RNA_boolean_get(op->ptr, "use_individual")));
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
}
@@ -189,7 +189,7 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
static void edbm_inset_exit(bContext *C, wmOperator *op)
{
InsetData *opdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
opdata = op->customdata;
@@ -206,8 +206,8 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
G.moving = 0;
}
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
MEM_SAFE_FREE(opdata->ob_store);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 7718a07a55e..fd7cc2733ec 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -479,7 +479,7 @@ static bool bm_vert_in_faces_radial(BMVert *v, BMEdge *e_radial, BMFace *f_ignor
struct LinkBase {
LinkNode *list;
- unsigned int list_len;
+ uint list_len;
};
static void ghash_insert_face_edge_link(GHash *gh,
@@ -535,7 +535,7 @@ static void bm_face_split_by_edges_island_connect(
}
{
- unsigned int edge_arr_holes_len;
+ uint edge_arr_holes_len;
BMEdge **edge_arr_holes;
if (BM_face_split_edgenet_connect_islands(bm,
f,
@@ -704,6 +704,8 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMEdge *e;
BMIter iter;
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
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(
@@ -717,8 +719,6 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
- BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
-
{
BMVert *v;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -765,7 +765,7 @@ static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
BMIter liter;
BMLoop *l;
- unsigned int loop_stack_len;
+ uint loop_stack_len;
BMLoop *l_best = NULL;
BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 6230eacba94..5f5599b53df 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1162,6 +1162,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v
rgba_uchar_to_float(fcol, kcd->colors.point_a);
GPU_batch_uniform_4fv(batch, "color", fcol);
GPU_matrix_bind(batch->interface);
+ GPU_shader_set_srgb_uniform(batch->interface);
GPU_point_size(11);
if (snapped_verts_count > 0) {
GPU_batch_draw_advanced(batch, 0, snapped_verts_count, 0, 0);
@@ -1579,7 +1580,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
float line_tol, line_tol_sq;
float face_tol, face_tol_sq;
int isect_kind;
- unsigned int tot;
+ uint tot;
int i;
const bool use_hit_prev = true;
const bool use_hit_curr = (kcd->is_drag_hold == false);
@@ -2419,7 +2420,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
edge_array_len = i;
#ifdef USE_NET_ISLAND_CONNECT
- unsigned int edge_array_holes_len;
+ uint edge_array_holes_len;
BMEdge **edge_array_holes;
if (BM_face_split_edgenet_connect_islands(bm,
f,
@@ -2824,14 +2825,14 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Knife Tool Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Knife Tool Modal Map");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Knife Tool Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_knife_tool");
@@ -2997,6 +2998,7 @@ static int knifetool_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEROTATE:
case WHEELUPMOUSE:
case WHEELDOWNMOUSE:
+ case NDOF_MOTION:
return OPERATOR_PASS_THROUGH;
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
if (kcd->mode != MODE_PANNING) {
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 37bacb4af55..0f52911c603 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -372,7 +372,8 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
if (is_interactive) {
for (uint base_index = 0; base_index < bases_len; base_index++) {
Object *ob_iter = bases[base_index]->object;
- if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) {
+ if (BKE_modifiers_is_deformed_by_lattice(ob_iter) ||
+ BKE_modifiers_is_deformed_by_armature(ob_iter)) {
BKE_report(
op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display");
break;
@@ -514,6 +515,10 @@ static int loopcut_finish(RingSelOpData *lcd, bContext *C, wmOperator *op)
static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ if (event->type == NDOF_MOTION) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
RingSelOpData *lcd = op->customdata;
float cuts = lcd->cuts;
float smoothness = lcd->smoothness;
@@ -605,7 +610,8 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
handled = true;
break;
- case MOUSEMOVE: /* mouse moved somewhere to select another loop */
+ case MOUSEMOVE: {
+ /* mouse moved somewhere to select another loop */
/* This is normally disabled for all modal operators.
* This is an exception since mouse movement doesn't relate to numeric input.
@@ -614,14 +620,16 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
#if 0
if (!has_numinput)
#endif
- {
- lcd->vc.mval[0] = event->mval[0];
- lcd->vc.mval[1] = event->mval[1];
- loopcut_mouse_move(lcd, (int)lcd->cuts);
+ {
+ lcd->vc.mval[0] = event->mval[0];
+ lcd->vc.mval[1] = event->mval[1];
+ loopcut_mouse_move(lcd, (int)lcd->cuts);
- ED_region_tag_redraw(lcd->region);
- handled = true;
- } break;
+ ED_region_tag_redraw(lcd->region);
+ handled = true;
+ }
+ break;
+ }
}
/* Modal numinput inactive, try to handle numeric inputs last... */
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 3a0a028468d..739bc5bdf7c 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -67,10 +67,10 @@ static bool paint_mask_extract_poll(bContext *C)
return false;
}
else {
- return true;
+ return ED_operator_object_active_editable_mesh(C);
}
}
- return ED_operator_object_active_editable_mesh(C);
+ return false;
}
static int paint_mask_extract_exec(bContext *C, wmOperator *op)
@@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "add_solidify")) {
ED_object_modifier_add(
op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify);
- SolidifyModifierData *sfmd = (SolidifyModifierData *)modifiers_findByName(
+ SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name(
new_ob, "mask_extract_solidify");
if (sfmd) {
sfmd->offset = -0.05f;
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index a1ea6074044..5d9923c6a7d 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -402,7 +402,7 @@ static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
BMIter iter;
BMEdge *e;
- unsigned int total_tag = 0;
+ uint total_tag = 0;
/* count tags, could be pre-calculated */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
@@ -441,8 +441,8 @@ static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs)
{
UnorderedLoopPair *ulp;
- unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
- unsigned int i;
+ uint total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
+ uint i;
for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) {
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index f01511fa513..6b029cdef16 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2335,6 +2335,8 @@ void EDBM_selectmode_convert(BMEditMesh *em,
BM_edge_select_set(bm, eed, false);
}
}
+ /* Deselect faces without edges selected. */
+ BM_mesh_deselect_flush(bm);
}
else if (selectmode_new == SCE_SELECT_VERTEX) {
/* flush down (face -> vert) */
@@ -2668,8 +2670,9 @@ bool EDBM_selectmode_disable_multi_ex(Scene *scene,
Object *ob_iter = base_iter->object;
BMEditMesh *em_iter = BKE_editmesh_from_object(ob_iter);
- EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback);
- changed_multi = true;
+ if (EDBM_selectmode_disable(scene, em_iter, selectmode_disable, selectmode_fallback)) {
+ changed_multi = true;
+ }
}
return changed_multi;
}
@@ -3201,8 +3204,12 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BMEdge *e;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) {
- BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
- BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ /* Check the edge for selected faces,
+ * this supports stepping off isolated vertices which would otherwise be ignored. */
+ if (BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_disable(e->v2, BM_ELEM_TAG);
+ }
}
}
}
@@ -3258,10 +3265,13 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
if (delimit) {
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(
- e,
- BM_ELEM_TAG,
- (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG)));
+ /* Check the edge for selected faces,
+ * this supports stepping off isolated edges which would otherwise be ignored. */
+ BM_elem_flag_set(e,
+ BM_ELEM_TAG,
+ (BM_elem_flag_test(e, BM_ELEM_SELECT) &&
+ (BMO_edge_flag_test(bm, e, BMO_ELE_TAG) ||
+ !BM_edge_is_any_face_flag_test(e, BM_ELEM_SELECT))));
}
}
else {
diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c
index 5106108a16c..365c5b5d264 100644
--- a/source/blender/editors/mesh/editmesh_select_similar.c
+++ b/source/blender/editors/mesh/editmesh_select_similar.c
@@ -1059,7 +1059,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op)
if (type == SIMVERT_VGROUP) {
/* We store the names of the vertex groups, so we can select
- * vertex groups with the same name in different objects. */
+ * vertex groups with the same name in different objects. */
const int dvert_tot = BLI_listbase_count(&ob->defbase);
for (int i = 0; i < dvert_tot; i++) {
if (dvert_selected & (1 << i)) {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index b52f63e0a1b..684bb73dc0e 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -69,9 +69,9 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_transform.h"
-#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -410,45 +410,6 @@ void MESH_OT_unsubdivide(wmOperatorType *ot)
ot->srna, "iterations", 2, 1, 1000, "Iterations", "Number of times to unsubdivide", 1, 100);
}
-void EDBM_project_snap_verts(
- bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
-{
- Main *bmain = CTX_data_main(C);
- BMIter iter;
- BMVert *eve;
-
- ED_view3d_init_mats_rv3d(obedit, region->regiondata);
-
- struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- float mval[2], co_proj[3];
- if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
- V3D_PROJ_RET_OK) {
- if (ED_transform_snap_object_project_view3d(snap_context,
- depsgraph,
- SCE_SNAP_MODE_FACE,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_NOT_ACTIVE,
- .use_object_edit_cage = false,
- .use_occlusion_test = true,
- },
- mval,
- NULL,
- NULL,
- co_proj,
- NULL)) {
- mul_v3_m4v3(eve->co, obedit->imat, co_proj);
- }
- }
- }
- }
-
- ED_transform_snap_object_context_destroy(snap_context);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -731,8 +692,10 @@ static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
void MESH_OT_edge_collapse(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Edge Collapse";
- ot->description = "Collapse selected edges";
+ ot->name = "Collapse Edges & Faces";
+ ot->description =
+ "Collapse isolated edges & faces regions, merging data such as UV's and vertex colors. "
+ "This can collapse edge-rings as well as regions of connected faces into vertices";
ot->idname = "MESH_OT_edge_collapse";
/* api callbacks */
@@ -754,7 +717,7 @@ static bool edbm_add_edge_face__smooth_get(BMesh *bm)
BMEdge *e;
BMIter iter;
- unsigned int vote_on_smooth[2] = {0, 0};
+ uint vote_on_smooth[2] = {0, 0};
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l) {
@@ -1184,6 +1147,12 @@ void MESH_OT_mark_sharp(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Connect Vertex Path Operator
+ * \{ */
+
static bool edbm_connect_vert_pair(BMEditMesh *em, struct Mesh *me, wmOperator *op)
{
BMesh *bm = em->bm;
@@ -1309,7 +1278,7 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Split Concave Faces Operator
+/** \name Connect Vertex Path Operator
* \{ */
/**
@@ -1598,6 +1567,12 @@ void MESH_OT_vert_connect_path(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Connect Concave Operator
+ * \{ */
+
static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1771,8 +1746,93 @@ void MESH_OT_face_make_planar(wmOperatorType *ot)
/** \name Split Edge Operator
* \{ */
+static bool edbm_edge_split_selected_edges(wmOperator *op, Object *obedit, BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+ if (bm->totedgesel == 0) {
+ return false;
+ }
+ if (!EDBM_op_call_and_selectf(
+ em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
+ return false;
+ }
+
+ EDBM_select_flush(em);
+ EDBM_update_generic(obedit->data, true, true);
+
+ return true;
+}
+
+static bool edbm_edge_split_selected_verts(wmOperator *op, Object *obedit, BMEditMesh *em)
+{
+ BMesh *bm = em->bm;
+
+ /* Note that tracking vertices through the 'split_edges' operator is complicated.
+ * Instead, tag loops for selection. */
+ if (bm->totvertsel == 0) {
+ return false;
+ }
+
+ /* Flush from vertices to edges. */
+ BMIter iter;
+ BMEdge *eed;
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_disable(eed, BM_ELEM_TAG);
+ if (eed->l != NULL) {
+ if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) &&
+ (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
+ BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) {
+ BM_elem_flag_enable(eed, BM_ELEM_TAG);
+ }
+ /* Store selection in loop tags. */
+ BMLoop *l_iter = eed->l;
+ do {
+ BM_elem_flag_set(l_iter, BM_ELEM_TAG, BM_elem_flag_test(l_iter->v, BM_ELEM_SELECT));
+ } while ((l_iter = l_iter->radial_next) != eed->l);
+ }
+ }
+
+ if (!EDBM_op_callf(em,
+ op,
+ "split_edges edges=%he verts=%hv use_verts=%b",
+ BM_ELEM_TAG,
+ BM_ELEM_SELECT,
+ true)) {
+ return false;
+ }
+
+ BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (eed->l != NULL) {
+ BMLoop *l_iter = eed->l;
+ do {
+ if (BM_elem_flag_test(l_iter, BM_ELEM_TAG)) {
+ BM_vert_select_set(em->bm, l_iter->v, true);
+ }
+ } while ((l_iter = l_iter->radial_next) != eed->l);
+ }
+ else {
+ /* Split out wire. */
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = *(&eed->v1 + i);
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ if (eed != BM_DISK_EDGE_NEXT(eed, v)) {
+ BM_vert_separate(bm, v, &eed, 1, true, NULL, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ EDBM_select_flush(em);
+ EDBM_update_generic(obedit->data, true, true);
+
+ return true;
+}
+
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
{
+ const int type = RNA_enum_get(op->ptr, "type");
+
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(
@@ -1780,20 +1840,21 @@ static int edbm_edge_split_exec(bContext *C, wmOperator *op)
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->bm->totedgesel == 0) {
- continue;
- }
-
- if (!EDBM_op_call_and_selectf(
- em, op, "edges.out", false, "split_edges edges=%he", BM_ELEM_SELECT)) {
- continue;
- }
- if (em->selectmode == SCE_SELECT_FACE) {
- EDBM_select_flush(em);
+ switch (type) {
+ case BM_VERT:
+ if (!edbm_edge_split_selected_verts(op, obedit, em)) {
+ continue;
+ }
+ break;
+ case BM_EDGE:
+ if (!edbm_edge_split_selected_edges(op, obedit, em)) {
+ continue;
+ }
+ break;
+ default:
+ BLI_assert(0);
}
-
- EDBM_update_generic(obedit->data, true, true);
}
MEM_freeN(objects);
@@ -1813,6 +1874,20 @@ void MESH_OT_edge_split(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ static const EnumPropertyItem merge_type_items[] = {
+ {BM_EDGE, "EDGE", 0, "Faces by Edges", "Split faces along selected edges"},
+ {BM_VERT,
+ "VERT",
+ 0,
+ "Faces & Edges by Vertices",
+ "Split faces & edges connected to selected vertices"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ ot->prop = RNA_def_enum(
+ ot->srna, "type", merge_type_items, BM_EDGE, "Type", "Method to use for splitting");
}
/** \} */
@@ -1895,6 +1970,84 @@ void MESH_OT_duplicate(wmOperatorType *ot)
RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
}
+static BMLoopNorEditDataArray *flip_custom_normals_init_data(BMesh *bm)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+ if (CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, update these too.
+ * Otherwise they will be left in a mangled state.
+ */
+ BM_lnorspace_update(bm);
+ lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true);
+ }
+
+ return lnors_ed_arr;
+}
+
+static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
+{
+ if (!lnors_ed_arr) {
+ return false;
+ }
+
+ if (lnors_ed_arr->totloop == 0) {
+ /* No loops normals to flip, exit early! */
+ return false;
+ }
+
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BM_lnorspace_update(bm);
+
+ /* We need to recreate the custom normal array because the clnors_data will
+ * be mangled because we swapped the loops around when we flipped the faces. */
+ BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true);
+
+ {
+ /* We need to recalculate all loop normals in the affected area. Even the ones that are not
+ * going to be flipped because the clnors data is mangled. */
+
+ BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) {
+
+ BMLoopNorEditData *lnor_ed =
+ lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index];
+
+ BLI_assert(lnor_ed != NULL);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index],
+ lnor_ed->nloc,
+ lnor_ed_new_full->clnors_data);
+ }
+ }
+
+ BMFace *f;
+ BMLoop *l;
+ BMIter iter_f, iter_l;
+ BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ continue;
+ }
+ /* Flip all the custom loop normals on the selected faces. */
+
+ BM_ITER_ELEM (l, &iter_l, f, BM_LOOPS_OF_FACE) {
+
+ int loop_index = BM_elem_index_get(l);
+
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[loop_index];
+ BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index];
+ BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL);
+
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data);
+ }
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full);
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1902,6 +2055,8 @@ void MESH_OT_duplicate(wmOperatorType *ot)
* \{ */
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
{
+ const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors");
+
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(
@@ -1911,15 +2066,48 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->bm->totfacesel == 0) {
+ if (only_clnors) {
+ if (CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) {
+ /* The mesh has custom normal data, flip them. */
+ BMesh *bm = em->bm;
+
+ BM_lnorspace_update(bm);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ negate_v3(lnor_ed->nloc);
+
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ lnor_ed->nloc,
+ lnor_ed->clnors_data);
+ }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ EDBM_update_generic(obedit->data, true, false);
+ }
continue;
}
- if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ if (em->bm->totfacesel == 0) {
continue;
}
- EDBM_update_generic(obedit->data, true, false);
+ bool has_flipped_faces = false;
+
+ /* See if we have any custom normals to flip. */
+ BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+
+ if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) {
+ has_flipped_faces = true;
+ }
+
+ if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) {
+ EDBM_update_generic(obedit->data, true, false);
+ }
+
+ if (lnors_ed_arr != NULL) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
}
MEM_freeN(objects);
@@ -1939,6 +2127,12 @@ void MESH_OT_flip_normals(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna,
+ "only_clnors",
+ false,
+ "Custom Normals Only",
+ "Only flip the custom loop normals of the selected elements");
}
/** \} */
@@ -2201,6 +2395,7 @@ void MESH_OT_reveal(wmOperatorType *ot)
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool inside = RNA_boolean_get(op->ptr, "inside");
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
@@ -2213,11 +2408,23 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
continue;
}
+ BMLoopNorEditDataArray *lnors_ed_arr = NULL;
+
+ if (inside) {
+ /* Save custom normal data for later so we can flip them correctly. */
+ lnors_ed_arr = flip_custom_normals_init_data(em->bm);
+ }
+
if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) {
continue;
}
- if (RNA_boolean_get(op->ptr, "inside")) {
+
+ if (inside) {
EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true);
+ flip_custom_normals(em->bm, lnors_ed_arr);
+ if (lnors_ed_arr != NULL) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
}
EDBM_update_generic(obedit->data, true, false);
@@ -3108,7 +3315,7 @@ void MESH_OT_merge(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Remove Doubles Operator
+/** \name Merge By Distance Operator
* \{ */
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
@@ -4330,6 +4537,7 @@ static int edbm_separate_exec(bContext *C, wmOperator *op)
/* delay depsgraph recalc until all objects are duplicated */
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -4455,7 +4663,7 @@ void MESH_OT_fill(wmOperatorType *ot)
static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v))
{
- return BM_elem_flag_test_bool(e, BM_ELEM_TAG);
+ return BM_elem_flag_test_bool(e, BM_ELEM_SELECT);
}
static float edbm_fill_grid_vert_tag_angle(BMVert *v)
@@ -4477,7 +4685,7 @@ static float edbm_fill_grid_vert_tag_angle(BMVert *v)
/**
* non-essential utility function to select 2 open edge loops from a closed loop.
*/
-static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span_calc)
+static bool edbm_fill_grid_prepare(BMesh *bm, int offset, int *span_p, const bool span_calc)
{
/* angle differences below this value are considered 'even'
* in that they shouldn't be used to calculate corners used for the 'span' */
@@ -4485,28 +4693,48 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BMEdge *e;
BMIter iter;
int count;
- int span = *r_span;
+ int span = *span_p;
ListBase eloops = {NULL};
struct BMEdgeLoopStore *el_store;
// LinkData *el_store;
- /* select -> tag */
+ count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm);
+ el_store = eloops.first;
+
+ if (count != 1) {
+ /* Let the operator use the selection flags,
+ * most likely failing with an error in this case. */
+ BM_mesh_edgeloops_free(&eloops);
+ return false;
+ }
+
+ /* Only tag edges that are part of a loop. */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ BM_elem_flag_disable(e, BM_ELEM_TAG);
+ }
+ const int verts_len = BM_edgeloop_length_get(el_store);
+ const int edges_len = verts_len - (BM_edgeloop_is_closed(el_store) ? 0 : 1);
+ BMEdge **edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
+ BM_edgeloop_edges_get(el_store, edges);
+ for (int i = 0; i < edges_len; i++) {
+ BM_elem_flag_enable(edges[i], BM_ELEM_TAG);
}
- count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm);
- el_store = eloops.first;
+ if (span_calc) {
+ span = verts_len / 4;
+ }
+ else {
+ span = min_ii(span, (verts_len / 2) - 1);
+ }
+ offset = mod_i(offset, verts_len);
+
+ if ((count == 1) && ((verts_len & 1) == 0) && (verts_len == edges_len)) {
- if (count == 1 && BM_edgeloop_is_closed(el_store) &&
- (BM_edgeloop_length_get(el_store) & 1) == 0) {
/* be clever! detect 2 edge loops from one closed edge loop */
- const int verts_len = BM_edgeloop_length_get(el_store);
ListBase *verts = BM_edgeloop_verts_get(el_store);
BMVert *v_act = BM_mesh_active_vert_get(bm);
LinkData *v_act_link;
- BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__);
int i;
if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) {
@@ -4537,6 +4765,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BLI_listbase_rotate_first(verts, v_act_link);
}
+ /* Run again to update the edge order from the rotated vertex list. */
BM_edgeloop_edges_get(el_store, edges);
if (span_calc) {
@@ -4589,18 +4818,19 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
BM_elem_flag_disable(edges[i], BM_ELEM_TAG);
BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG);
}
- MEM_freeN(edges);
}
/* else let the bmesh-operator handle it */
BM_mesh_edgeloops_free(&eloops);
+ MEM_freeN(edges);
- *r_span = span;
+ *span_p = span;
+
+ return true;
}
static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
{
- const bool use_prepare = true;
const bool use_interp_simple = RNA_boolean_get(op->ptr, "use_interp_simple");
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -4612,6 +4842,7 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool use_prepare = true;
const bool use_smooth = edbm_add_edge_face__smooth_get(em->bm);
const int totedge_orig = em->bm->totedge;
const int totface_orig = em->bm->totface;
@@ -4626,7 +4857,6 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset");
bool calc_span;
- const int clamp = em->bm->totvertsel;
int span;
int offset;
@@ -4635,19 +4865,18 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op)
if (((op->flag & OP_IS_INVOKE) || (op->flag & OP_IS_REPEAT_LAST) == 0) &&
RNA_property_is_set(op->ptr, prop_span)) {
span = RNA_property_int_get(op->ptr, prop_span);
- span = min_ii(span, (clamp / 2) - 1);
calc_span = false;
}
else {
- span = clamp / 4;
+ /* Will be overwritten if possible. */
+ span = 0;
calc_span = true;
}
offset = RNA_property_int_get(op->ptr, prop_offset);
- offset = clamp ? mod_i(offset, clamp) : 0;
/* in simple cases, move selection for tags, but also support more advanced cases */
- edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
+ use_prepare = edbm_fill_grid_prepare(em->bm, offset, &span, calc_span);
RNA_property_int_set(op->ptr, prop_span, span);
}
@@ -6020,7 +6249,7 @@ static void sort_bmelem_flag(bContext *C,
const int flag,
const int action,
const int reverse,
- const unsigned int seed)
+ const uint seed)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
@@ -6033,7 +6262,7 @@ static void sort_bmelem_flag(bContext *C,
/* Just to mark protected elements. */
char *pblock[3] = {NULL, NULL, NULL}, *pb;
BMElemSort *sblock[3] = {NULL, NULL, NULL}, *sb;
- unsigned int *map[3] = {NULL, NULL, NULL}, *mp;
+ uint *map[3] = {NULL, NULL, NULL}, *mp;
int totelem[3] = {0, 0, 0};
int affected[3] = {0, 0, 0};
int i, j;
@@ -6210,7 +6439,7 @@ static void sort_bmelem_flag(bContext *C,
}
else if (action == SRT_SELECTED) {
- unsigned int *tbuf[3] = {NULL, NULL, NULL}, *tb;
+ uint *tbuf[3] = {NULL, NULL, NULL}, *tb;
if (totelem[0]) {
tb = tbuf[0] = MEM_callocN(sizeof(int) * totelem[0], "sort_bmelem vert tbuf");
@@ -6474,7 +6703,7 @@ static int edbm_sort_elements_exec(bContext *C, wmOperator *op)
const int action = RNA_enum_get(op->ptr, "type");
PropertyRNA *prop_elem_types = RNA_struct_find_property(op->ptr, "elements");
const bool use_reverse = RNA_boolean_get(op->ptr, "reverse");
- unsigned int seed = RNA_int_get(op->ptr, "seed");
+ uint seed = RNA_int_get(op->ptr, "seed");
int elem_types = 0;
if (ELEM(action, SRT_VIEW_ZAXIS, SRT_VIEW_XAXIS)) {
@@ -6984,37 +7213,17 @@ void MESH_OT_wireframe(wmOperatorType *ot)
static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
{
- bool mode_change = false;
const bool use_cap_endpoint = RNA_boolean_get(op->ptr, "use_cap_endpoint");
- int ret = OPERATOR_CANCELLED;
-
- {
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- if (em->selectmode == SCE_SELECT_FACE) {
- EDBM_selectmode_to_scene(C);
- mode_change = true;
- }
- }
-
+ bool changed_multi = false;
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
- view_layer, CTX_wm_view3d(C), &objects_len);
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
+ uint bases_len = 0;
+ Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &bases_len);
+ for (uint base_index = 0; base_index < bases_len; base_index++) {
+ Object *obedit = bases[base_index]->object;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- /** If in face-only select mode, switch to edge select mode so that
- * an edge-only selection is not inconsistent state.
- *
- * We need to run this for all objects, even when nothing is selected.
- * This way we keep them in sync. */
- if (mode_change) {
- em->selectmode = SCE_SELECT_EDGE;
- EDBM_selectmode_set(em);
- }
-
if (em->bm->totedgesel == 0) {
continue;
}
@@ -7034,16 +7243,26 @@ static int edbm_offset_edgeloop_exec(bContext *C, wmOperator *op)
BMO_slot_buffer_hflag_enable(
em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
- if (!EDBM_op_finish(em, &bmop, op, true)) {
- continue;
- }
- else {
+ if (EDBM_op_finish(em, &bmop, op, true)) {
EDBM_update_generic(obedit->data, true, true);
- ret = OPERATOR_FINISHED;
+ changed_multi = true;
}
}
- MEM_freeN(objects);
- return ret;
+
+ if (changed_multi) {
+ /** If in face-only select mode, switch to edge select mode so that
+ * an edge-only selection is not inconsistent state.
+ *
+ * We need to run this for all objects, even when nothing is selected.
+ * This way we keep them in sync. */
+ if (scene->toolsettings->selectmode == SCE_SELECT_FACE) {
+ EDBM_selectmode_disable_multi_ex(scene, bases, bases_len, SCE_SELECT_FACE, SCE_SELECT_EDGE);
+ }
+ }
+
+ MEM_freeN(bases);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void MESH_OT_offset_edge_loops(wmOperatorType *ot)
@@ -7694,14 +7913,14 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
};
static const char *keymap_name = "Custom Normals Modal Map";
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, keymap_name);
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
/* We only need to add map once */
if (keymap && keymap->modal_items) {
return NULL;
}
- keymap = WM_modalkeymap_add(keyconf, keymap_name, modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
WM_modalkeymap_assign(keymap, "MESH_OT_point_normals");
@@ -7710,7 +7929,11 @@ wmKeyMap *point_normals_modal_keymap(wmKeyConfig *keyconf)
#define CLNORS_VALID_VEC_LEN (1e-4f)
-/********************** 'Point to' Loop Normals **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Normals 'Point To' Operator
+ * \{ */
enum {
EDBM_CLNOR_POINTTO_MODE_COORDINATES = 1,
@@ -7728,7 +7951,7 @@ static EnumPropertyItem clnors_pointto_mode_items[] = {
};
/* Initialize loop normal data */
-static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static bool point_normals_init(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -7740,14 +7963,29 @@ static int point_normals_init(bContext *C, wmOperator *op, const wmEvent *UNUSED
op->customdata = lnors_ed_arr;
- return lnors_ed_arr->totloop;
+ return (lnors_ed_arr->totloop != 0);
}
-static void point_normals_free(bContext *C, wmOperator *op)
+static bool point_normals_ensure(bContext *C, wmOperator *op)
{
- BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- op->customdata = NULL;
+ if (op->customdata != NULL) {
+ return true;
+ }
+ return point_normals_init(C, op);
+}
+
+static void point_normals_free(wmOperator *op)
+{
+ if (op->customdata != NULL) {
+ BMLoopNorEditDataArray *lnors_ed_arr = op->customdata;
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ op->customdata = NULL;
+ }
+}
+
+static void point_normals_cancel(bContext *C, wmOperator *op)
+{
+ point_normals_free(op);
ED_area_status_text(CTX_wm_area(C), NULL);
}
@@ -7864,6 +8102,13 @@ static void point_normals_apply(bContext *C, wmOperator *op, float target[3], co
static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ /* As this operator passes events through, we can't be sure the user didn't exit edit-mode.
+ * or performed some other operation. */
+ if (!WM_operator_poll(C, op->type)) {
+ point_normals_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
@@ -8034,23 +8279,37 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent *
if (!ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
RNA_property_float_set_array(op->ptr, prop_target, target);
}
- point_normals_apply(C, op, target, do_reset);
- EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
- point_normals_update_header(C, op);
+ if (point_normals_ensure(C, op)) {
+ point_normals_apply(C, op, target, do_reset);
+ EDBM_update_generic(obedit->data, true, false); /* Recheck bools. */
+ point_normals_update_header(C, op);
+ }
+ else {
+ ret = OPERATOR_CANCELLED;
+ }
}
if (ELEM(ret, OPERATOR_CANCELLED, OPERATOR_FINISHED)) {
- point_normals_free(C, op);
+ point_normals_cancel(C, op);
}
+ /* If we allow other tools to run, we can't be sure if they will re-allocate
+ * the data this operator uses, see: T68159.
+ * 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)) {
+ point_normals_free(op);
+ }
+ }
return ret;
}
-static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (!point_normals_init(C, op, event)) {
- point_normals_free(C, op);
+ if (!point_normals_init(C, op)) {
+ point_normals_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -8067,8 +8326,8 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
- if (!point_normals_init(C, op, NULL)) {
- point_normals_free(C, op);
+ if (!point_normals_init(C, op)) {
+ point_normals_cancel(C, op);
return OPERATOR_CANCELLED;
}
@@ -8081,7 +8340,7 @@ static int edbm_point_normals_exec(bContext *C, wmOperator *op)
point_normals_apply(C, op, target, false);
EDBM_update_generic(obedit->data, true, false);
- point_normals_free(C, op);
+ point_normals_cancel(C, op);
return OPERATOR_FINISHED;
}
@@ -8126,7 +8385,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot)
ot->modal = edbm_point_normals_modal;
ot->poll = ED_operator_editmesh;
ot->ui = edbm_point_normals_ui;
- ot->cancel = point_normals_free;
+ ot->cancel = point_normals_cancel;
/* flags */
ot->flag = OPTYPE_BLOCKING | OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -8171,7 +8430,7 @@ void MESH_OT_point_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Split/Merge Loop Normals
+/** \name Split/Merge Loop Normals Operator
* \{ */
static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
@@ -8185,6 +8444,8 @@ static void normals_merge(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr)
BM_normals_loops_edges_tag(bm, false);
for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(clnors));
+
if (BM_elem_flag_test(lnor_ed->loop, BM_ELEM_TAG)) {
continue;
}
@@ -8227,8 +8488,12 @@ static void normals_split(BMesh *bm)
BM_normals_loops_edges_tag(bm, true);
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+
l_curr = l_first = BM_FACE_FIRST_LOOP(f);
do {
if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
@@ -8250,7 +8515,6 @@ static void normals_split(BMesh *bm)
lfan_pivot = l_curr;
e_next = lfan_pivot->e;
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
float avg_normal[3] = {0.0f};
while (true) {
@@ -8262,7 +8526,7 @@ static void normals_split(BMesh *bm)
e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
}
- BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+ BLI_SMALLSTACK_PUSH(loop_stack, lfan_pivot);
add_v3_v3(avg_normal, lfan_pivot->f->no);
if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
@@ -8274,7 +8538,7 @@ static void normals_split(BMesh *bm)
/* If avg normal is nearly 0, set clnor to default value. */
zero_v3(avg_normal);
}
- while ((l = BLI_SMALLSTACK_POP(loops))) {
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
BKE_lnor_space_custom_normal_to_data(
@@ -8382,7 +8646,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Average Loop Normals
+/** \name Average Loop Normals Operator
* \{ */
enum {
@@ -8416,7 +8680,13 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
const float absweight = (float)RNA_int_get(op->ptr, "weight");
const float threshold = RNA_float_get(op->ptr, "threshold");
+ HeapSimple *loop_weight = BLI_heapsimple_new();
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+ BLI_assert(BLI_heapsimple_is_empty(loop_weight));
+
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -8443,8 +8713,6 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
BM_normals_loops_edges_tag(bm, true);
- HeapSimple *loop_weight = BLI_heapsimple_new();
-
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
l_curr = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -8494,7 +8762,6 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
lfan_pivot = lfan_pivot_next;
}
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
float wnor[3], avg_normal[3] = {0.0f}, count = 0;
float val = BLI_heapsimple_top_value(loop_weight);
@@ -8505,7 +8772,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
val = cur_val;
}
l = BLI_heapsimple_pop_min(loop_weight);
- BLI_SMALLSTACK_PUSH(loops, l);
+ BLI_SMALLSTACK_PUSH(loop_stack, l);
const float n_weight = pow(weight, count);
@@ -8526,7 +8793,7 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
/* If avg normal is nearly 0, set clnor to default value. */
zero_v3(avg_normal);
}
- while ((l = BLI_SMALLSTACK_POP(loops))) {
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
BKE_lnor_space_custom_normal_to_data(
@@ -8537,10 +8804,11 @@ static int edbm_average_normals_exec(bContext *C, wmOperator *op)
} while ((l_curr = l_curr->next) != l_first);
}
- BLI_heapsimple_free(loop_weight, NULL);
EDBM_update_generic(obedit->data, true, false);
}
+ BLI_heapsimple_free(loop_weight, NULL);
+
MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8614,7 +8882,7 @@ void MESH_OT_average_normals(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Custom Normal Interface Tools
+/** \name Custom Normal Interface Tools Operator
* \{ */
enum {
@@ -8850,6 +9118,12 @@ void MESH_OT_normals_tools(struct wmOperatorType *ot)
"Copy Absolute coordinates or Normal vector");
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Normals from Faces Operator
+ * \{ */
+
static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -8957,7 +9231,13 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
RNA_def_boolean(ot->srna, "keep_sharp", 0, "Keep Sharp Edges", "Do not set sharp edges to face");
}
-static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Smooth Normal Vectors Operator
+ * \{ */
+
+static int edbm_smooth_normals_exec(bContext *C, wmOperator *op)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
uint objects_len = 0;
@@ -9010,7 +9290,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
float current_normal[3];
if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
+ /* Skip in case the smooth normal is invalid. */
continue;
}
@@ -9024,7 +9304,7 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
add_v3_v3(current_normal, smooth_normal[i]);
if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
+ /* Skip in case the smoothed normal is invalid. */
continue;
}
@@ -9042,15 +9322,15 @@ static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void MESH_OT_smoothen_normals(struct wmOperatorType *ot)
+void MESH_OT_smooth_normals(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Smooth Normals Vectors";
- ot->description = "Smoothen custom normals based on adjacent vertex normals";
- ot->idname = "MESH_OT_smoothen_normals";
+ ot->description = "Smooth custom normals based on adjacent vertex normals";
+ ot->idname = "MESH_OT_smooth_normals";
/* api callbacks */
- ot->exec = edbm_smoothen_normals_exec;
+ ot->exec = edbm_smooth_normals_exec;
ot->poll = ED_operator_editmesh;
/* flags */
diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c
index 1f857ad4710..e4ecfa9c680 100644
--- a/source/blender/editors/mesh/editmesh_undo.c
+++ b/source/blender/editors/mesh/editmesh_undo.c
@@ -397,9 +397,7 @@ struct UMArrayData {
UndoMesh *um;
const UndoMesh *um_ref; /* can be NULL */
};
-static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
struct UMArrayData *um_data = taskdata;
um_arraystore_compact_with_info(um_data->um, um_data->um_ref);
@@ -541,16 +539,14 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key)
# ifdef USE_ARRAY_STORE_THREAD
if (um_arraystore.task_pool == NULL) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
- um_arraystore.task_pool = BLI_task_pool_create_background(scheduler, NULL);
+ um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW);
}
struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__);
um_data->um = um;
um_data->um_ref = um_ref;
- BLI_task_pool_push(
- um_arraystore.task_pool, um_arraystore_compact_cb, um_data, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(um_arraystore.task_pool, um_arraystore_compact_cb, um_data, true, NULL);
# else
um_arraystore_compact_with_info(um, um_ref);
# endif
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index f44a94a63f8..b5346a9061a 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -52,6 +52,7 @@
#include "ED_mesh.h"
#include "ED_screen.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -370,8 +371,7 @@ void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
* cycles.
*/
#if 0
- for (Object *other_object = bmain->objects.first; other_object != NULL;
- other_object = other_object->id.next) {
+ for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) {
if (other_object->data == ob->data) {
BKE_object_free_derived_caches(other_object);
}
@@ -406,10 +406,10 @@ void EDBM_mesh_load(Main *bmain, Object *ob)
void EDBM_mesh_free(BMEditMesh *em)
{
/* These tables aren't used yet, so it's not strictly necessary
- * to 'end' them (with 'e' param) but if someone tries to start
- * using them, having these in place will save a lot of pain */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ * to 'end' them but if someone tries to start using them,
+ * having these in place will save a lot of pain. */
+ ED_mesh_mirror_spatial_table_end(NULL);
+ ED_mesh_mirror_topo_table_end(NULL);
BKE_editmesh_free(em);
}
@@ -539,7 +539,7 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm,
UvVertMap *vmap;
UvMapVert *buf;
MLoopUV *luv;
- unsigned int a;
+ uint a;
int totverts, i, totuv, totfaces;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
bool *winding = NULL;
@@ -669,7 +669,7 @@ UvVertMap *BM_uv_vert_map_create(BMesh *bm,
return vmap;
}
-UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v)
+UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
{
return vmap->vert[v];
}
@@ -832,7 +832,7 @@ UvElementMap *BM_uv_element_map_create(BMesh *bm,
}
if (do_islands) {
- unsigned int *map;
+ uint *map;
BMFace **stack;
int stacksize = 0;
UvElement *islandbuf;
@@ -1224,7 +1224,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
BMLoop *l_iter, *l_first;
- unsigned int i = 0;
+ uint i = 0;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
@@ -1639,3 +1639,47 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree,
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name BMesh Vertex Projection API
+ * \{ */
+
+void EDBM_project_snap_verts(
+ bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
+{
+ BMIter iter;
+ BMVert *eve;
+
+ ED_view3d_init_mats_rv3d(obedit, region->regiondata);
+
+ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
+ CTX_data_scene(C), 0, region, CTX_wm_view3d(C));
+
+ BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ float mval[2], co_proj[3];
+ if (ED_view3d_project_float_object(region, eve->co, mval, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ if (ED_transform_snap_object_project_view3d(snap_context,
+ depsgraph,
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_NOT_ACTIVE,
+ .use_object_edit_cage = false,
+ .use_occlusion_test = true,
+ },
+ mval,
+ NULL,
+ NULL,
+ co_proj,
+ NULL)) {
+ mul_v3_m4v3(eve->co, obedit->imat, co_proj);
+ }
+ }
+ }
+ }
+
+ ED_transform_snap_object_context_destroy(snap_context);
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 594429d4925..5e70069456b 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -248,7 +248,7 @@ void MESH_OT_split_normals(struct wmOperatorType *ot);
void MESH_OT_normals_tools(struct wmOperatorType *ot);
void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot);
void MESH_OT_average_normals(struct wmOperatorType *ot);
-void MESH_OT_smoothen_normals(struct wmOperatorType *ot);
+void MESH_OT_smooth_normals(struct wmOperatorType *ot);
void MESH_OT_mod_weighted_strength(struct wmOperatorType *ot);
/* *** editmesh_mask_extract.c *** */
diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c
index 9b599d8df7f..0bbc8b0df76 100644
--- a/source/blender/editors/mesh/mesh_mirror.c
+++ b/source/blender/editors/mesh/mesh_mirror.c
@@ -44,73 +44,71 @@ static struct {
void *tree;
} MirrKdStore = {NULL};
-/* mode is 's' start, or 'e' end, or 'u' use */
-/* if end, ob can be NULL */
-int ED_mesh_mirror_spatial_table(
- Object *ob, BMEditMesh *em, Mesh *me_eval, const float co[3], char mode)
+void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *me_eval)
{
- if (mode == 'u') { /* use table */
- if (MirrKdStore.tree == NULL) {
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
- }
-
- if (MirrKdStore.tree) {
- KDTreeNearest_3d nearest;
- const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest);
+ Mesh *me = ob->data;
+ const bool use_em = (!me_eval && em && me->edit_mesh == em);
+ const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert;
- if (i != -1) {
- if (nearest.dist < KD_THRESH) {
- return i;
- }
- }
- }
- return -1;
+ if (MirrKdStore.tree) { /* happens when entering this call without ending it */
+ ED_mesh_mirror_spatial_table_end(ob);
}
- else if (mode == 's') { /* start table */
- Mesh *me = ob->data;
- const bool use_em = (!me_eval && em && me->edit_mesh == em);
- const int totvert = use_em ? em->bm->totvert : me_eval ? me_eval->totvert : me->totvert;
-
- if (MirrKdStore.tree) { /* happens when entering this call without ending it */
- ED_mesh_mirror_spatial_table(ob, em, me_eval, co, 'e');
- }
- MirrKdStore.tree = BLI_kdtree_3d_new(totvert);
+ MirrKdStore.tree = BLI_kdtree_3d_new(totvert);
- if (use_em) {
- BMVert *eve;
- BMIter iter;
- int i;
+ if (use_em) {
+ BMVert *eve;
+ BMIter iter;
+ int i;
- /* this needs to be valid for index lookups later (callers need) */
- BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ /* this needs to be valid for index lookups later (callers need) */
+ BM_mesh_elem_table_ensure(em->bm, BM_VERT);
- BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
- BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co);
- }
+ BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+ BLI_kdtree_3d_insert(MirrKdStore.tree, i, eve->co);
}
- else {
- MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
- int i;
+ }
+ 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);
- }
+ for (i = 0; i < totvert; i++, mvert++) {
+ BLI_kdtree_3d_insert(MirrKdStore.tree, i, mvert->co);
}
+ }
+
+ BLI_kdtree_3d_balance(MirrKdStore.tree);
+}
- BLI_kdtree_3d_balance(MirrKdStore.tree);
+int ED_mesh_mirror_spatial_table_lookup(Object *ob,
+ BMEditMesh *em,
+ Mesh *me_eval,
+ const float co[3])
+{
+ if (MirrKdStore.tree == NULL) {
+ ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
}
- else if (mode == 'e') { /* end table */
- if (MirrKdStore.tree) {
- BLI_kdtree_3d_free(MirrKdStore.tree);
- MirrKdStore.tree = NULL;
+
+ if (MirrKdStore.tree) {
+ KDTreeNearest_3d nearest;
+ const int i = BLI_kdtree_3d_find_nearest(MirrKdStore.tree, co, &nearest);
+
+ if (i != -1) {
+ if (nearest.dist < KD_THRESH) {
+ return i;
+ }
}
}
- else {
- BLI_assert(0);
- }
+ return -1;
+}
- return 0;
+void ED_mesh_mirror_spatial_table_end(Object *UNUSED(ob))
+{
+ /* TODO: store this in object/object-data (keep unused argument for now). */
+ if (MirrKdStore.tree) {
+ BLI_kdtree_3d_free(MirrKdStore.tree);
+ MirrKdStore.tree = NULL;
+ }
}
/** \} */
@@ -119,7 +117,7 @@ int ED_mesh_mirror_spatial_table(
/** \name Mesh Topology Mirror API
* \{ */
-typedef unsigned int MirrTopoHash_t;
+typedef uint MirrTopoHash_t;
typedef struct MirrTopoVert_t {
MirrTopoHash_t hash;
@@ -231,7 +229,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
medge = me->medge;
for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
+ const uint i1 = med->v1, i2 = med->v2;
topo_hash[i1]++;
topo_hash[i2]++;
}
@@ -257,7 +255,7 @@ void ED_mesh_mirrtopo_init(BMEditMesh *em,
}
else {
for (a = 0, med = medge; a < totedge; a++, med++) {
- const unsigned int i1 = med->v1, i2 = med->v2;
+ const uint i1 = med->v1, i2 = med->v2;
topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index c61fe39b5fd..c52a5956ac4 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -203,7 +203,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_normals_tools);
WM_operatortype_append(MESH_OT_set_normals_from_faces);
WM_operatortype_append(MESH_OT_average_normals);
- WM_operatortype_append(MESH_OT_smoothen_normals);
+ WM_operatortype_append(MESH_OT_smooth_normals);
WM_operatortype_append(MESH_OT_mod_weighted_strength);
}
@@ -277,6 +277,18 @@ void ED_operatormacros_mesh(void)
RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+ ot = WM_operatortype_append_macro(
+ "MESH_OT_extrude_region_dissolve_move_intersect",
+ "Extrude, Dissolve, Move and Intersect",
+ "Extrude, dissolves edges whose faces form a flat surface and intersect new edges",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
+ RNA_boolean_set(otmacro->ptr, "use_dissolve_ortho_edges", true);
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+ RNA_boolean_set(otmacro->ptr, "use_automerge_and_split", true);
+
ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move",
"Extrude Region and Move",
"Extrude region together along the average normal",
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 6c5106d3eec..917bbe61e3d 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -161,7 +161,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
*/
if (key) {
/* if this mesh has any shapekeys, check first, otherwise just copy coordinates */
- for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
/* get pointer to where to write data for this mesh in shapekey's data array */
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
@@ -191,7 +191,7 @@ static void join_mesh_single(Depsgraph *depsgraph,
* - otherwise, copy across plain coordinates (no need to transform coordinates)
*/
if (key) {
- for (KeyBlock *kb = key->block.first; kb; kb = kb->next) {
+ LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
/* get pointer to where to write data for this mesh in shapekey's data array */
float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
@@ -314,7 +314,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
int totloop = 0, totpoly = 0, vertofs, *matmap = NULL;
int i, haskey = 0, edgeofs, loopofs, polyofs;
- bool ok = false;
+ bool ok = false, join_parent = false;
bDeformGroup *dg, *odg;
CustomData vdata, edata, fdata, ldata, pdata;
@@ -346,6 +346,10 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ok = true;
}
+ if ((ob->parent != NULL) && (ob_iter == ob->parent)) {
+ join_parent = true;
+ }
+
/* check for shapekeys */
if (me->key) {
haskey++;
@@ -354,6 +358,13 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
+ /* Apply parent transform if the active object's parent was joined to it.
+ * Note: This doesn't apply recursive parenting. */
+ if (join_parent) {
+ ob->parent = NULL;
+ BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false);
+ }
+
/* that way the active object is always selected */
if (ok == false) {
BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
@@ -440,7 +451,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
/* Join this object's face maps to the base one's. */
- for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ LISTBASE_FOREACH (bFaceMap *, fmap, &ob_iter->fmaps) {
/* See if this group exists in the object (if it doesn't, add it to the end) */
if (BKE_object_facemap_find_name(ob, fmap->name) == NULL) {
bFaceMap *fmap_new = MEM_mallocN(sizeof(bFaceMap), "join faceMap");
@@ -786,62 +797,73 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op)
}
/* -------------------------------------------------------------------- */
-/* Mesh Mirror (Topology) */
-
/** \name Mesh Topology Mirror API
* \{ */
static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1};
+BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob,
+ Mesh *me_eval,
+ Mesh **r_me_mirror,
+ BMEditMesh **r_em_mirror)
+{
+ Mesh *me_mirror = NULL;
+ BMEditMesh *em_mirror = NULL;
+
+ Mesh *me = ob->data;
+ if (me_eval != NULL) {
+ me_mirror = me_eval;
+ }
+ else if (me->edit_mesh != NULL) {
+ em_mirror = me->edit_mesh;
+ }
+ else {
+ me_mirror = me;
+ }
+
+ *r_me_mirror = me_mirror;
+ *r_em_mirror = em_mirror;
+}
+
/**
* Mode is 's' start, or 'e' end, or 'u' use
* if end, ob can be NULL.
* \note This is supposed return -1 on error,
* which callers are currently checking for, but is not used so far.
*/
-int ED_mesh_mirror_topo_table(Object *ob, Mesh *me_eval, char mode)
+void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
{
+ Mesh *me_mirror;
+ BMEditMesh *em_mirror;
+ mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
- Mesh *me_mirror = NULL;
- BMEditMesh *em_mirror = NULL;
+ ED_mesh_mirrtopo_init(em_mirror, me_mirror, &mesh_topo_store, false);
+}
- if (mode != 'e') {
- Mesh *me = ob->data;
- if (me_eval != NULL) {
- me_mirror = me_eval;
- }
- else if (me->edit_mesh != NULL) {
- em_mirror = me->edit_mesh;
- }
- else {
- me_mirror = me;
- }
- }
+void ED_mesh_mirror_topo_table_end(Object *UNUSED(ob))
+{
+ /* TODO: store this in object/object-data (keep unused argument for now). */
+ ED_mesh_mirrtopo_free(&mesh_topo_store);
+}
- if (mode == 'u') { /* use table */
- if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
- ED_mesh_mirror_topo_table(ob, me_eval, 's');
- }
- }
- else if (mode == 's') { /* start table */
- ED_mesh_mirrtopo_init(em_mirror, me_mirror, &mesh_topo_store, false);
- }
- else if (mode == 'e') { /* end table */
- ED_mesh_mirrtopo_free(&mesh_topo_store);
- }
- else {
- BLI_assert(0);
- }
+static int ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
+{
+ Mesh *me_mirror;
+ BMEditMesh *em_mirror;
+ mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
+ if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
+ ED_mesh_mirror_topo_table_begin(ob, me_eval);
+ }
return 0;
}
/** \} */
-static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index)
+static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
{
Mesh *me = ob->data;
- MVert *mvert = mesh ? mesh->mvert : me->mvert;
+ MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
float vec[3];
mvert = &mvert[index];
@@ -849,12 +871,12 @@ static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh, int index)
vec[1] = mvert->co[1];
vec[2] = mvert->co[2];
- return ED_mesh_mirror_spatial_table(ob, NULL, mesh, vec, 'u');
+ return ED_mesh_mirror_spatial_table_lookup(ob, NULL, me_eval, vec);
}
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
{
- if (ED_mesh_mirror_topo_table(ob, mesh, 'u') == -1) {
+ if (ed_mesh_mirror_topo_table_update(ob, mesh) == -1) {
return -1;
}
@@ -885,7 +907,7 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c
vec[1] = co[1];
vec[2] = co[2];
- i = ED_mesh_mirror_spatial_table(ob, em, NULL, vec, 'u');
+ i = ED_mesh_mirror_spatial_table_lookup(ob, em, NULL, vec);
if (i != -1) {
return BM_vert_at_index(em->bm, i);
}
@@ -898,7 +920,7 @@ static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob,
int index)
{
intptr_t poinval;
- if (ED_mesh_mirror_topo_table(ob, NULL, 'u') == -1) {
+ if (ed_mesh_mirror_topo_table_update(ob, NULL) == -1) {
return NULL;
}
@@ -1023,10 +1045,10 @@ static float *editmesh_get_mirror_uv(
#endif
-static unsigned int mirror_facehash(const void *ptr)
+static uint mirror_facehash(const void *ptr)
{
const MFace *mf = ptr;
- unsigned int v0, v1;
+ uint v0, v1;
if (mf->v4) {
v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4);
@@ -1098,13 +1120,13 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
mvert = me_eval ? me_eval->mvert : me->mvert;
mface = me_eval ? me_eval->mface : me->mface;
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 's');
+ ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
for (a = 0, mv = mvert; a < totvert; a++, mv++) {
mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology);
}
- ED_mesh_mirror_spatial_table(ob, em, me_eval, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
for (a = 0, mf = mface; a < totface; a++, mf++) {
@@ -1119,8 +1141,8 @@ int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
/* make sure v4 is not 0 if a quad */
if (mf->v4 && mirrormf.v4 == 0) {
- SWAP(unsigned int, mirrormf.v1, mirrormf.v3);
- SWAP(unsigned int, mirrormf.v2, mirrormf.v4);
+ SWAP(uint, mirrormf.v1, mirrormf.v3);
+ SWAP(uint, mirrormf.v2, mirrormf.v4);
}
hashmf = BLI_ghash_lookup(fhash, &mirrormf);
@@ -1174,7 +1196,7 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
*r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
}
- if ((*r_index) == 0 || (*r_index) > (unsigned int)me->totpoly) {
+ if ((*r_index) == 0 || (*r_index) > (uint)me->totpoly) {
return false;
}
@@ -1218,7 +1240,7 @@ bool ED_mesh_pick_face_vert(
bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- unsigned int poly_index;
+ uint poly_index;
Mesh *me = ob->data;
BLI_assert(me && GS(me->id.name) == ID_ME);
@@ -1241,7 +1263,7 @@ bool ED_mesh_pick_face_vert(
MPoly *me_eval_mpoly;
MLoop *me_eval_mloop;
MVert *me_eval_mvert;
- unsigned int me_eval_mpoly_len;
+ uint me_eval_mpoly_len;
const int *index_mp_to_orig;
me_eval_mpoly = me_eval->mpoly;
@@ -1254,7 +1276,7 @@ bool ED_mesh_pick_face_vert(
/* tag all verts using this face */
if (index_mp_to_orig) {
- unsigned int i;
+ uint i;
for (i = 0; i < me_eval_mpoly_len; i++) {
if (index_mp_to_orig[i] == poly_index) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index a64674deda4..9386c466f95 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -456,7 +456,7 @@ static int select_random_metaelems_exec(bContext *C, wmOperator *op)
RNG *rng = BLI_rng_new_srandom(seed_iter);
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (BLI_rng_get_float(rng) < randfac) {
if (select) {
ml->flag |= SELECT;
@@ -656,7 +656,7 @@ static int reveal_metaelems_exec(bContext *C, wmOperator *op)
const bool select = RNA_boolean_get(op->ptr, "select");
bool changed = false;
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (ml->flag & MB_HIDE) {
SET_FLAG_FROM_TEST(ml->flag, select, SELECT);
ml->flag &= ~MB_HIDE;
@@ -697,7 +697,7 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
- unsigned int buffer[MAXPICKBUF];
+ uint buffer[MAXPICKBUF];
rcti rect;
ED_view3d_viewcontext_init(C, &vc, depsgraph);
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index a5b6fa55aa9..fb273cf49a8 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../../blenfont
../../blenkernel
../../blenlib
../../blentranslation
@@ -33,6 +34,7 @@ set(INC
../../shader_fx
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index ac2958282c1..8289f52b0c8 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -53,8 +53,7 @@
#include "BLT_translation.h"
#include "BKE_action.h"
-#include "BKE_anim.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
@@ -62,9 +61,10 @@
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
+#include "BKE_duplilist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
-#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_hair.h"
#include "BKE_key.h"
#include "BKE_lattice.h"
@@ -146,7 +146,7 @@ static const EnumPropertyItem field_type_items[] = {
{PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""},
{PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""},
{PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""},
- {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""},
+ {PFIELD_FLUIDFLOW, "FLUID", ICON_FORCE_FLUIDFLOW, "Fluid Flow", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -303,10 +303,15 @@ void ED_object_add_unit_props_size(wmOperatorType *ot)
ot->srna, "size", 2.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Size", "", 0.001, 100.00);
}
-void ED_object_add_unit_props_radius(wmOperatorType *ot)
+void ED_object_add_unit_props_radius_ex(wmOperatorType *ot, float default_value)
{
RNA_def_float_distance(
- ot->srna, "radius", 1.0f, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+ ot->srna, "radius", default_value, 0.0, OBJECT_ADD_SIZE_MAXF, "Radius", "", 0.001, 100.00);
+}
+
+void ED_object_add_unit_props_radius(wmOperatorType *ot)
+{
+ ED_object_add_unit_props_radius_ex(ot, 1.0f);
}
void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
@@ -345,6 +350,18 @@ void ED_object_add_generic_props(wmOperatorType *ot, bool do_editmode)
DEG2RADF(-360.0f),
DEG2RADF(360.0f));
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_float_vector_xyz(ot->srna,
+ "scale",
+ 3,
+ NULL,
+ -OBJECT_ADD_SIZE_MAXF,
+ OBJECT_ADD_SIZE_MAXF,
+ "Scale",
+ "Scale for the newly added object",
+ -1000.0f,
+ 1000.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void ED_object_add_mesh_props(wmOperatorType *ot)
@@ -357,6 +374,7 @@ bool ED_object_add_generic_get_opts(bContext *C,
const char view_align_axis,
float loc[3],
float rot[3],
+ float scale[3],
bool *enter_editmode,
ushort *local_view_bits,
bool *is_view_aligned)
@@ -465,6 +483,26 @@ bool ED_object_add_generic_get_opts(bContext *C,
}
}
+ /* Scale! */
+ {
+ float _scale[3];
+ if (!scale) {
+ scale = _scale;
+ }
+
+ /* For now this is optional, we can make it always use. */
+ copy_v3_fl(scale, 1.0f);
+ if ((prop = RNA_struct_find_property(op->ptr, "scale"))) {
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, scale);
+ }
+ else {
+ copy_v3_fl(scale, 1.0f);
+ RNA_property_float_set_array(op->ptr, prop, scale);
+ }
+ }
+ }
+
return true;
}
@@ -530,7 +568,7 @@ static int object_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
radius = RNA_float_get(op->ptr, "radius");
@@ -604,7 +642,7 @@ static int lightprobe_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -663,7 +701,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
type = RNA_enum_get(op->ptr, "type");
@@ -741,7 +779,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
RNA_enum_set(op->ptr, "align", ALIGN_VIEW);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_CAMERA, NULL, loc, rot, false, local_view_bits);
@@ -802,7 +840,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit == NULL || obedit->type != OB_MBALL) {
@@ -814,7 +852,10 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
- dia = RNA_float_get(op->ptr, "radius");
+ /* Halving here is done to account for constant values from #BKE_mball_element_add.
+ * While the default radius of the resulting meta element is 2,
+ * we want to pass in 1 so other values such as resolution are scaled by 1.0. */
+ dia = RNA_float_get(op->ptr, "radius") / 2;
ED_mball_add_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
@@ -845,7 +886,7 @@ void OBJECT_OT_metaball_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_metaelem_type_items, 0, "Primitive", "");
- ED_object_add_unit_props_radius(ot);
+ ED_object_add_unit_props_radius_ex(ot, 2.0f);
ED_object_add_generic_props(ot, true);
}
@@ -864,7 +905,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (obedit && obedit->type == OB_FONT) {
@@ -916,7 +957,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(
- C, op, 'Z', loc, rot, &enter_editmode, &local_view_bits, NULL)) {
+ C, op, 'Z', loc, rot, NULL, &enter_editmode, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if ((obedit == NULL) || (obedit->type != OB_ARMATURE)) {
@@ -979,7 +1020,7 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, loc, rot, false, local_view_bits);
@@ -1039,7 +1080,8 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
ushort local_view_bits;
float rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', NULL, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(
+ C, op, 'Z', NULL, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_EMPTY, NULL, NULL, rot, false, local_view_bits);
@@ -1126,7 +1168,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
/* Note: We use 'Y' here (not 'Z'), as */
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Y', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
/* add new object if not currently editing a GP object,
@@ -1256,7 +1298,7 @@ static int object_light_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
WM_operator_view3d_unit_defaults(C, op);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_LAMP, get_light_defname(type), loc, rot, false, local_view_bits);
@@ -1341,7 +1383,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
collection = BLI_findlink(&bmain->collections, RNA_enum_get(op->ptr, "collection"));
}
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
if (collection) {
@@ -1357,6 +1399,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_add_type(
C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits);
ob->instance_collection = collection;
+ ob->empty_drawsize = U.collection_instance_empty_size;
ob->transflag |= OB_DUPLICOLLECTION;
id_us_plus(&collection->id);
@@ -1413,7 +1456,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op)
float loc[3], rot[3];
Scene *scene = CTX_data_scene(C);
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
ob = ED_object_add_type(C, OB_SPEAKER, NULL, loc, rot, false, local_view_bits);
@@ -1470,7 +1513,7 @@ static int object_hair_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_HAIR, NULL, loc, rot, false, local_view_bits);
@@ -1507,7 +1550,7 @@ static int object_pointcloud_add_exec(bContext *C, wmOperator *op)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return OPERATOR_CANCELLED;
}
Object *object = ED_object_add_type(C, OB_POINTCLOUD, NULL, loc, rot, false, local_view_bits);
@@ -1738,10 +1781,10 @@ static void copy_object_set_idnew(bContext *C)
* In other words, we consider each group of objects from a same item as being
* the 'local group' where to check for parents.
*/
-static unsigned int dupliobject_hash(const void *ptr)
+static uint dupliobject_hash(const void *ptr)
{
const DupliObject *dob = ptr;
- unsigned int hash = BLI_ghashutil_ptrhash(dob->ob);
+ uint hash = BLI_ghashutil_ptrhash(dob->ob);
if (dob->type == OB_DUPLICOLLECTION) {
for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
@@ -1760,10 +1803,10 @@ static unsigned int dupliobject_hash(const void *ptr)
* since its a unique index and we only want to know if the group objects are from the same
* dupli-group instance.
*/
-static unsigned int dupliobject_instancer_hash(const void *ptr)
+static uint dupliobject_instancer_hash(const void *ptr)
{
const DupliObject *dob = ptr;
- unsigned int hash = BLI_ghashutil_inthash(dob->persistent_id[0]);
+ uint hash = BLI_ghashutil_inthash(dob->persistent_id[0]);
for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) {
hash ^= (dob->persistent_id[i] ^ i);
}
@@ -2048,6 +2091,7 @@ static int object_duplicates_make_real_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE, scene);
WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -2255,7 +2299,7 @@ static int convert_exec(bContext *C, wmOperator *op)
* needed since re-evaluating single modifiers causes bugs if they depend
* on other objects data masks too, see: T50950. */
{
- for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ LISTBASE_FOREACH (CollectionPointerLink *, link, &selected_editable_bases) {
Base *base = link->ptr.data;
Object *ob = base->object;
@@ -2282,7 +2326,7 @@ static int convert_exec(bContext *C, wmOperator *op)
scene->customdata_mask = customdata_mask_prev;
}
- for (CollectionPointerLink *link = selected_editable_bases.first; link; link = link->next) {
+ LISTBASE_FOREACH (CollectionPointerLink *, link, &selected_editable_bases) {
Object *newob = NULL;
Base *base = link->ptr.data;
Object *ob = base->object;
@@ -2380,13 +2424,8 @@ static int convert_exec(bContext *C, wmOperator *op)
cu = newob->data;
- /* TODO(sergey): Ideally DAG will create nurbs list for a curve data
- * datablock, but for until we've got granular update
- * lets take care by selves.
- */
- /* XXX This may fail/crash, since BKE_vfont_to_curve()
- * accesses evaluated data in some cases (bastien). */
- BKE_vfont_to_curve(newob, FO_EDIT);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ BKE_vfont_to_curve_ex(ob_eval, ob_eval->data, FO_EDIT, &cu->nurb, NULL, NULL, NULL, NULL);
newob->type = OB_CURVE;
cu->type = OB_CURVE;
@@ -2543,7 +2582,12 @@ static int convert_exec(bContext *C, wmOperator *op)
}
if (!keep_original && (ob->flag & OB_DONE)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ /* NOTE: Tag transform for update because object parenting to curve with path is handled
+ * differently from all other cases. Converting curve to mesh and mesh to curve will likely
+ * affect the way children are evaluated.
+ * It is not enough to tag only geometry and rely on the curve parenting relations because
+ * this relation is lost when curve is converted to mesh. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM);
((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */
}
}
@@ -2855,6 +2899,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 2cb0229126d..baa24ab2f4e 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -156,7 +156,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op)
ok = mmd->totlvl > 0;
for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
ok = false;
}
}
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 7d39d2546b6..e84dbca2469 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -96,6 +96,7 @@ typedef struct BakeAPIRender {
bool is_cage;
float cage_extrusion;
+ float max_ray_distance;
int normal_space;
eBakeNormalSwizzle normal_swizzle[3];
@@ -116,7 +117,7 @@ typedef struct BakeAPIRender {
short *do_update;
/* for redrawing */
- ScrArea *sa;
+ ScrArea *area;
} BakeAPIRender;
/* callbacks */
@@ -161,10 +162,10 @@ static int bake_break(void *UNUSED(rjv))
return 0;
}
-static void bake_update_image(ScrArea *sa, Image *image)
+static void bake_update_image(ScrArea *area, Image *image)
{
- if (sa && sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
- SpaceImage *sima = sa->spacedata.first;
+ if (area && area->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
+ SpaceImage *sima = area->spacedata.first;
if (sima) {
sima->image = image;
}
@@ -234,7 +235,7 @@ static bool write_internal_bake_pixels(Image *image,
ibuf->x);
}
else {
- IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -259,7 +260,7 @@ static bool write_internal_bake_pixels(Image *image,
mask_buffer);
}
else {
- IMB_buffer_byte_from_float_mask((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float_mask((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -359,7 +360,7 @@ static bool write_external_bake_pixels(const char *filepath,
buffer, ibuf->x, ibuf->y, ibuf->channels, from_colorspace, to_colorspace, false);
}
- IMB_buffer_byte_from_float((unsigned char *)ibuf->rect,
+ IMB_buffer_byte_from_float((uchar *)ibuf->rect,
buffer,
ibuf->channels,
ibuf->dither,
@@ -446,7 +447,8 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep
for (i = 0; i < ob->totcol; i++) {
bNodeTree *ntree = NULL;
bNode *node = NULL;
- ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree);
+ const int mat_nr = i + 1;
+ ED_object_get_active_image(ob, mat_nr, &image, NULL, &node, &ntree);
if (image) {
ImBuf *ibuf;
@@ -481,7 +483,7 @@ static bool bake_object_check(ViewLayer *view_layer, Object *ob, ReportList *rep
}
}
else {
- Material *mat = BKE_object_material_get(ob, i);
+ Material *mat = BKE_object_material_get(ob, mat_nr);
if (mat != NULL) {
BKE_reportf(reports,
RPT_INFO,
@@ -736,6 +738,7 @@ static int bake(Render *re,
const bool is_selected_to_active,
const bool is_cage,
const float cage_extrusion,
+ const float max_ray_distance,
const int normal_space,
const eBakeNormalSwizzle normal_swizzle[],
const char *custom_cage,
@@ -743,7 +746,7 @@ static int bake(Render *re,
const int width,
const int height,
const char *identifier,
- ScrArea *sa,
+ ScrArea *area,
const char *uv_layer)
{
/* We build a depsgraph for the baking,
@@ -894,7 +897,7 @@ static int bake(Render *re,
/* for multires bake, use linear UV subdivision to match low res UVs */
if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT &&
!is_selected_to_active) {
- mmd_low = (MultiresModifierData *)modifiers_findByType(ob_low, eModifierType_Multires);
+ mmd_low = (MultiresModifierData *)BKE_modifiers_findby_type(ob_low, eModifierType_Multires);
if (mmd_low) {
mmd_flags_low = mmd_low->flags;
mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE;
@@ -944,7 +947,7 @@ static int bake(Render *re,
if (md->type == eModifierType_EdgeSplit) {
BLI_remlink(&ob_low_eval->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
is_changed = true;
}
md = md_next;
@@ -1009,6 +1012,7 @@ static int bake(Render *re,
num_pixels,
ob_cage != NULL,
cage_extrusion,
+ max_ray_distance,
ob_low_eval->obmat,
(ob_cage ? ob_cage->obmat : ob_low_eval->obmat),
me_cage)) {
@@ -1023,7 +1027,7 @@ static int bake(Render *re,
highpoly[i].ob,
i,
pixel_array_high,
- num_pixels,
+ &bake_images,
depth,
pass_type,
pass_filter,
@@ -1045,7 +1049,7 @@ static int bake(Render *re,
ob_low_eval,
0,
pixel_array_low,
- num_pixels,
+ &bake_images,
depth,
pass_type,
pass_filter,
@@ -1095,7 +1099,7 @@ static int bake(Render *re,
int mode;
BKE_object_eval_reset(ob_low_eval);
- md = modifiers_findByType(ob_low_eval, eModifierType_Multires);
+ md = BKE_modifiers_findby_type(ob_low_eval, eModifierType_Multires);
if (md) {
mode = md->mode;
@@ -1146,7 +1150,7 @@ static int bake(Render *re,
is_noncolor);
/* might be read by UI to set active image for display */
- bake_update_image(sa, bk_image->image);
+ bake_update_image(area, bk_image->image);
if (!ok) {
BKE_reportf(reports,
@@ -1283,13 +1287,13 @@ cleanup:
static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
{
bool is_save_internal;
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
bkr->ob = CTX_data_active_object(C);
bkr->main = CTX_data_main(C);
bkr->view_layer = CTX_data_view_layer(C);
bkr->scene = CTX_data_scene(C);
- bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
+ bkr->area = screen ? BKE_screen_find_big_area(screen, SPACE_IMAGE, 10) : NULL;
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter");
@@ -1304,6 +1308,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage");
bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion");
+ bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance");
bkr->normal_space = RNA_enum_get(op->ptr, "normal_space");
bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r");
@@ -1393,6 +1398,7 @@ static int bake_exec(bContext *C, wmOperator *op)
true,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1400,7 +1406,7 @@ static int bake_exec(bContext *C, wmOperator *op)
bkr.width,
bkr.height,
bkr.identifier,
- bkr.sa,
+ bkr.area,
bkr.uv_layer);
}
else {
@@ -1425,6 +1431,7 @@ static int bake_exec(bContext *C, wmOperator *op)
false,
bkr.is_cage,
bkr.cage_extrusion,
+ bkr.max_ray_distance,
bkr.normal_space,
bkr.normal_swizzle,
bkr.custom_cage,
@@ -1432,7 +1439,7 @@ static int bake_exec(bContext *C, wmOperator *op)
bkr.width,
bkr.height,
bkr.identifier,
- bkr.sa,
+ bkr.area,
bkr.uv_layer);
}
}
@@ -1494,6 +1501,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
true,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1501,7 +1509,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
bkr->width,
bkr->height,
bkr->identifier,
- bkr->sa,
+ bkr->area,
bkr->uv_layer);
}
else {
@@ -1526,6 +1534,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
false,
bkr->is_cage,
bkr->cage_extrusion,
+ bkr->max_ray_distance,
bkr->normal_space,
bkr->normal_swizzle,
bkr->custom_cage,
@@ -1533,7 +1542,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa
bkr->width,
bkr->height,
bkr->identifier,
- bkr->sa,
+ bkr->area,
bkr->uv_layer);
if (bkr->result == OPERATOR_CANCELLED) {
@@ -1585,6 +1594,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0);
}
+ prop = RNA_struct_find_property(op->ptr, "max_ray_distance");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_set(op->ptr, prop, bake->max_ray_distance);
+ }
+
prop = RNA_struct_find_property(op->ptr, "cage_extrusion");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_float_set(op->ptr, prop, bake->cage_extrusion);
@@ -1765,12 +1779,23 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Selected to Active",
"Bake shading on the surface of selected objects to the active object");
RNA_def_float(ot->srna,
+ "max_ray_distance",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Max Ray Distance",
+ "The maximum ray distance for matching points between the active and selected "
+ "objects. If zero, there is no limit",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
"cage_extrusion",
0.0f,
0.0f,
FLT_MAX,
"Cage Extrusion",
- "Distance to use for the inward ray cast when using selected to active",
+ "Inflate the active object by the specified distance for baking. This helps "
+ "matching to points nearer to the outside of the selected object meshes",
0.0f,
1.0f);
RNA_def_string(ot->srna,
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index 7c12a4839f0..7a83d582299 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -302,8 +302,8 @@ static int collection_objects_remove_all_exec(bContext *C, wmOperator *UNUSED(op
void COLLECTION_OT_objects_remove_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Remove from All Unlinked Collections";
- ot->description = "Remove selected objects from all collections not used in a scene";
+ ot->name = "Remove from All Collections";
+ ot->description = "Remove selected objects from all collections";
ot->idname = "COLLECTION_OT_objects_remove_all";
/* api callbacks */
@@ -481,9 +481,21 @@ static int collection_link_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+ /* Currently this should not be allowed (might be supported in the future though...). */
+ if (ID_IS_OVERRIDE_LIBRARY(&collection->id)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the collection because it is overridden.");
+ return OPERATOR_CANCELLED;
+ }
+ /* Linked collections are already checked for by using RNA_collection_local_itemf
+ * but operator can be called without invoke */
+ if (ID_IS_LINKED(&collection->id)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the collection because it is linked.");
+ return OPERATOR_CANCELLED;
+ }
+
/* Adding object to collection which is used as dupli-collection for self is bad idea.
*
- * It is also bad idea to add object to collection which is in collection which
+ * It is also bad idea to add object to collection which is in collection which
* contains our current object.
*/
if (BKE_collection_object_cyclic_check(bmain, ob, collection)) {
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index ba641fb2a39..76e95b0105a 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -81,7 +81,7 @@
* \{ */
/* if object in posemode, active bone constraints, else object constraints */
-ListBase *get_active_constraints(Object *ob)
+ListBase *ED_object_constraint_list_from_context(Object *ob)
{
if (ob == NULL) {
return NULL;
@@ -104,7 +104,9 @@ ListBase *get_active_constraints(Object *ob)
/* Find the list that a given constraint belongs to,
* and/or also get the posechannel this is from (if applicable) */
-ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan)
+ListBase *ED_object_constraint_list_from_constraint(Object *ob,
+ bConstraint *con,
+ bPoseChannel **r_pchan)
{
if (r_pchan) {
*r_pchan = NULL;
@@ -143,9 +145,9 @@ ListBase *get_constraint_lb(Object *ob, bConstraint *con, bPoseChannel **r_pchan
}
/* single constraint */
-bConstraint *get_active_constraint(Object *ob)
+bConstraint *ED_object_constraint_active_get(Object *ob)
{
- return BKE_constraints_active_get(get_active_constraints(ob));
+ return BKE_constraints_active_get(ED_object_constraint_list_from_context(ob));
}
/** \} */
@@ -721,7 +723,7 @@ static int edit_constraint_invoke_properties(bContext *C, wmOperator *op)
con = ptr.data;
RNA_string_set(op->ptr, "constraint", con->name);
- list = get_constraint_lb(ob, con, NULL);
+ list = ED_object_constraint_list_from_constraint(ob, con, NULL);
if (&ob->constraints == list) {
RNA_enum_set(op->ptr, "owner", EDIT_CONSTRAINT_OWNER_OBJECT);
@@ -769,7 +771,7 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
printf("edit_constraint_property_get: defaulting to getting list in the standard way\n");
}
#endif
- list = get_active_constraints(ob);
+ list = ED_object_constraint_list_from_context(ob);
}
con = BKE_constraints_find_name(list, constraint_name);
@@ -1061,7 +1063,7 @@ static int followpath_path_animate_exec(bContext *C, wmOperator *op)
Curve *cu = (Curve *)data->tar->data;
if (ELEM(NULL, cu->adt, cu->adt->action) ||
- (list_find_fcurve(&cu->adt->action->curves, "eval_time", 0) == NULL)) {
+ (BKE_fcurve_find(&cu->adt->action->curves, "eval_time", 0) == NULL)) {
/* create F-Curve for path animation */
act = ED_id_action_ensure(bmain, &cu->id);
fcu = ED_action_fcurve_ensure(bmain, act, NULL, NULL, "eval_time", 0);
@@ -1305,9 +1307,9 @@ void CONSTRAINT_OT_objectsolver_clear_inverse(wmOperatorType *ot)
/** \name Constraint Management Utilities
* \{ */
-void ED_object_constraint_set_active(Object *ob, bConstraint *con)
+void ED_object_constraint_active_set(Object *ob, bConstraint *con)
{
- ListBase *lb = get_constraint_lb(ob, con, NULL);
+ ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* lets be nice and escape if its active already */
/* NOTE: this assumes that the stack doesn't have other active ones set... */
@@ -1409,7 +1411,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *UNUSED(op))
PointerRNA ptr = CTX_data_pointer_get_type(C, "constraint", &RNA_Constraint);
Object *ob = (Object *)ptr.owner_id;
bConstraint *con = ptr.data;
- ListBase *lb = get_constraint_lb(ob, con, NULL);
+ ListBase *lb = ED_object_constraint_list_from_constraint(ob, con, NULL);
/* free the constraint */
if (BKE_constraint_remove_ex(lb, ob, con, true)) {
@@ -1459,7 +1461,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op)
bConstraint *con = edit_constraint_property_get(op, ob, 0);
if (con && con->next) {
- ListBase *conlist = get_constraint_lb(ob, con, NULL);
+ ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
bConstraint *nextCon = con->next;
/* insert the nominated constraint after the one that used to be after it */
@@ -1515,7 +1517,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op)
bConstraint *con = edit_constraint_property_get(op, ob, 0);
if (con && con->prev) {
- ListBase *conlist = get_constraint_lb(ob, con, NULL);
+ ListBase *conlist = ED_object_constraint_list_from_constraint(ob, con, NULL);
bConstraint *prevCon = con->prev;
/* insert the nominated constraint before the one that used to be before it */
@@ -2055,7 +2057,8 @@ static int pose_constraint_add_exec(bContext *C, wmOperator *op)
with_targets = 1;
}
- return constraint_add_exec(C, op, ob, get_active_constraints(ob), type, with_targets);
+ return constraint_add_exec(
+ C, op, ob, ED_object_constraint_list_from_context(ob), type, with_targets);
}
/* ------------------ */
@@ -2256,8 +2259,12 @@ static int pose_ik_add_exec(bContext *C, wmOperator *op)
/* add the constraint - all necessary checks should have
* been done by the invoke() callback already... */
- return constraint_add_exec(
- C, op, ob, get_active_constraints(ob), CONSTRAINT_TYPE_KINEMATIC, with_targets);
+ return constraint_add_exec(C,
+ op,
+ ob,
+ ED_object_constraint_list_from_context(ob),
+ CONSTRAINT_TYPE_KINEMATIC,
+ with_targets);
}
void POSE_OT_ik_add(wmOperatorType *ot)
diff --git a/source/blender/editors/object/object_data_transform.c b/source/blender/editors/object/object_data_transform.c
index fc91cbb9666..54fd1fe6671 100644
--- a/source/blender/editors/object/object_data_transform.c
+++ b/source/blender/editors/object/object_data_transform.c
@@ -92,7 +92,7 @@ static struct ElemData_Armature *armature_coords_and_quats_get_recurse(
const ListBase *bone_base, struct ElemData_Armature *elem_array)
{
struct ElemData_Armature *elem = elem_array;
- for (const Bone *bone = bone_base->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (const Bone *, bone, bone_base) {
#define COPY_PTR(member) memcpy(elem->member, bone->member, sizeof(bone->member))
#define COPY_VAL(member) memcpy(&elem->member, &bone->member, sizeof(bone->member))
@@ -125,7 +125,7 @@ static const struct ElemData_Armature *armature_coords_and_quats_apply_with_mat4
ListBase *bone_base, const struct ElemData_Armature *elem_array, const float mat[4][4])
{
const struct ElemData_Armature *elem = elem_array;
- for (Bone *bone = bone_base->first; bone; bone = bone->next) {
+ LISTBASE_FOREACH (Bone *, bone, bone_base) {
#define COPY_PTR(member) memcpy(bone->member, elem->member, sizeof(bone->member))
#define COPY_VAL(member) memcpy(&bone->member, &elem->member, sizeof(bone->member))
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 7faad5cdd0e..d522dcabae3 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -54,7 +54,7 @@
#include "IMB_imbuf_types.h"
-#include "BKE_anim.h"
+#include "BKE_anim_visualization.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
@@ -100,6 +100,8 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "CLG_log.h"
+
/* for menu/popup icons etc etc*/
#include "UI_interface.h"
@@ -112,21 +114,17 @@
#include "object_intern.h" // own include
+static CLG_LogRef LOG = {"ed.object.edit"};
+
/* prototypes */
typedef struct MoveToCollectionData MoveToCollectionData;
static void move_to_collection_menus_items(struct uiLayout *layout,
struct MoveToCollectionData *menu);
static ListBase selected_objects_get(bContext *C);
-/* ************* XXX **************** */
-static void error(const char *UNUSED(arg))
-{
-}
-
-/* port over here */
-static void error_libdata(void)
-{
-}
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
Object *ED_object_context(bContext *C)
{
@@ -147,7 +145,11 @@ Object *ED_object_active_context(bContext *C)
return ob;
}
-/* ********************** object hiding *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Hide Operator
+ * \{ */
static bool object_hide_poll(bContext *C)
{
@@ -166,7 +168,7 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *op)
const bool select = RNA_boolean_get(op->ptr, "select");
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_HIDDEN) {
base->flag &= ~BASE_HIDDEN;
changed = true;
@@ -217,7 +219,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
bool changed = false;
/* Hide selected or unselected objects. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (!(base->flag & BASE_VISIBLE_VIEWLAYER)) {
continue;
}
@@ -321,7 +323,7 @@ void ED_collection_hide_menu_draw(const bContext *C, uiLayout *layout)
uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN);
- for (LayerCollection *lc = lc_scene->layer_collections.first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, &lc_scene->layer_collections) {
int index = BKE_layer_collection_findindex(view_layer, lc);
uiLayout *row = uiLayoutRow(layout, false);
@@ -401,7 +403,11 @@ void OBJECT_OT_hide_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
-/* ******************* toggle editmode operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Edit-Mode Operator
+ * \{ */
static bool mesh_needs_keyindex(Main *bmain, const Mesh *me)
{
@@ -414,7 +420,7 @@ static bool mesh_needs_keyindex(Main *bmain, const Mesh *me)
return true;
}
if (ob->data == me) {
- for (const ModifierData *md = ob->modifiers.first; md; md = md->next) {
+ LISTBASE_FOREACH (const ModifierData *, md, &ob->modifiers) {
if (md->type == eModifierType_Hook) {
return true;
}
@@ -441,7 +447,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
}
if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) {
- error("Too many vertices");
+ /* This used to be warned int the UI, we could warn again although it's quite rare. */
+ CLOG_WARN(&LOG,
+ "Too many vertices for mesh '%s' (%d)",
+ me->id.name + 2,
+ me->edit_mesh->bm->totvert);
return false;
}
@@ -454,8 +464,8 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f
}
/* will be recalculated as needed. */
{
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(obedit);
+ ED_mesh_mirror_topo_table_end(obedit);
}
}
else if (obedit->type == OB_ARMATURE) {
@@ -600,7 +610,8 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag
}
if (BKE_object_obdata_is_libdata(ob)) {
- error_libdata();
+ /* Ideally the caller should check this. */
+ CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2);
return false;
}
@@ -777,7 +788,11 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* *************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Pose-Mode Operator
+ * \{ */
static int posemode_exec(bContext *C, wmOperator *op)
{
@@ -861,12 +876,16 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ******************* force field toggle operator ***************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Force Field Toggle Operator
+ * \{ */
void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
{
PartDeflect *pd = object->pd;
- ModifierData *md = modifiers_findByType(object, eModifierType_Surface);
+ ModifierData *md = BKE_modifiers_findby_type(object, eModifierType_Surface);
/* add/remove modifier as needed */
if (!md) {
@@ -924,8 +943,11 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************************************** */
-/* Motion Paths */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Calculate Motion Paths Operator
+ * \{ */
static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
{
@@ -1019,7 +1041,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv
}
/* show popup dialog to allow editing of range... */
- /* FIXME: hardcoded dimensions here are just arbitrary */
+ /* FIXME: hard-coded dimensions here are just arbitrary. */
return WM_operator_props_dialog_popup(C, op, 200);
}
@@ -1088,7 +1110,11 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot)
MAXFRAME / 2.0);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Operator
+ * \{ */
static bool object_update_paths_poll(bContext *C)
{
@@ -1132,7 +1158,11 @@ void OBJECT_OT_paths_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Motion Paths Operator
+ * \{ */
/* Helper for ED_objects_clear_paths() */
static void object_clear_mpath(Object *ob)
@@ -1151,14 +1181,14 @@ static void object_clear_mpath(Object *ob)
void ED_objects_clear_paths(bContext *C, bool only_selected)
{
if (only_selected) {
- /* loop over all selected + sedtiable objects in scene */
+ /* Loop over all selected + editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
object_clear_mpath(ob);
}
CTX_DATA_END;
}
else {
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
object_clear_mpath(ob);
}
@@ -1210,13 +1240,17 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
}
-/* --------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Update Motion Paths Range from Scene Operator
+ * \{ */
static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
- /* loop over all edtiable objects in scene */
+ /* Loop over all editable objects in scene. */
CTX_DATA_BEGIN (C, Object *, ob, editable_objects) {
/* use Preview Range or Full Frame Range - whichever is in use */
ob->avs.path_sf = PSFRA;
@@ -1246,63 +1280,99 @@ void OBJECT_OT_paths_range_update(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** Smooth/Flat *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Shade Smooth/Flat Operator
+ * \{ */
static int shade_smooth_exec(bContext *C, wmOperator *op)
{
- ID *data;
- Curve *cu;
- Nurb *nu;
- int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat"));
- bool done = false, linked_data = false;
+ const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth");
+ bool changed_multi = false;
+ bool has_linked_data = false;
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
- data = ob->data;
+ ListBase ctx_objects = {NULL, NULL};
+ CollectionPointerLink ctx_ob_single_active = {NULL};
+
+ /* 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);
+ if (obact && ((obact->mode & OB_MODE_ALL_PAINT))) {
+ ctx_ob_single_active.ptr.data = obact;
+ BLI_addtail(&ctx_objects, &ctx_ob_single_active);
+ }
+ }
+
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ CTX_data_selected_editable_objects(C, &ctx_objects);
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if (data != NULL) {
+ data->tag |= LIB_TAG_DOIT;
+ }
+ }
+
+ for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) {
+ /* Always un-tag all object data-blocks irrespective of our ability to operate on them. */
+ Object *ob = ctx_ob->ptr.data;
+ ID *data = ob->data;
+ if ((data == NULL) || ((data->tag & LIB_TAG_DOIT) == 0)) {
+ continue;
+ }
+ data->tag &= ~LIB_TAG_DOIT;
+ /* Finished un-tagging, continue with regular logic. */
if (data && ID_IS_LINKED(data)) {
- linked_data = true;
+ has_linked_data = true;
continue;
}
+ bool changed = false;
if (ob->type == OB_MESH) {
- BKE_mesh_smooth_flag_set(ob->data, !clear);
-
+ BKE_mesh_smooth_flag_set(ob->data, use_smooth);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
+ changed = true;
}
else if (ELEM(ob->type, OB_SURF, OB_CURVE)) {
- cu = ob->data;
+ BKE_curve_smooth_flag_set(ob->data, use_smooth);
+ changed = true;
+ }
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (!clear) {
- nu->flag |= ME_SMOOTH;
- }
- else {
- nu->flag &= ~ME_SMOOTH;
- }
- }
+ if (changed) {
+ changed_multi = true;
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- done = true;
}
}
- CTX_DATA_END;
- if (linked_data) {
+ if (ctx_objects.first != &ctx_ob_single_active) {
+ BLI_freelistN(&ctx_objects);
+ }
+
+ if (has_linked_data) {
BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data");
}
- return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static bool shade_poll(bContext *C)
{
- return (CTX_data_edit_object(C) == NULL);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obact = OBACT(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)) {
+ return false;
+ }
+ }
+ return true;
}
void OBJECT_OT_shade_flat(wmOperatorType *ot)
@@ -1335,7 +1405,11 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ********************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Mode Set Operator
+ * \{ */
static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
PointerRNA *UNUSED(ptr),
@@ -1355,7 +1429,8 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
if (ob) {
const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) ||
(ob->soft != NULL) ||
- (modifiers_findByType(ob, eModifierType_Cloth) != NULL);
+ (BKE_modifiers_findby_type(ob, eModifierType_Cloth) !=
+ NULL);
while (input->identifier) {
if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) ||
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
@@ -1393,67 +1468,84 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
static bool object_mode_set_poll(bContext *C)
{
- /* Since Grease Pencil editmode is also handled here,
- * we have a special exception for allowing this operator
- * to still work in that case when there's no active object
- * so that users can exit editmode this way as per normal.
- */
- if (ED_operator_object_active_editable(C)) {
- return true;
- }
- else {
- return (CTX_data_gpencil_data(C) != NULL);
- }
+ /* Needed as #ED_operator_object_active_editable doesn't call use 'active_object'. */
+ Object *ob = CTX_data_active_object(C);
+ return ED_operator_object_active_editable_ex(C, ob);
}
static int object_mode_set_exec(bContext *C, wmOperator *op)
{
- bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
+ const bool use_submode = STREQ(op->idname, "OBJECT_OT_mode_set_with_submode");
Object *ob = CTX_data_active_object(C);
eObjectMode mode = RNA_enum_get(op->ptr, "mode");
- eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT;
const bool toggle = RNA_boolean_get(op->ptr, "toggle");
/* by default the operator assume is a mesh, but if gp object change mode */
- if ((ob != NULL) && (ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
mode = OB_MODE_EDIT_GPENCIL;
}
- if (!ob || !ED_object_mode_compat_test(ob, mode)) {
+ if (!ED_object_mode_compat_test(ob, mode)) {
return OPERATOR_PASS_THROUGH;
}
- if (ob->mode != mode) {
- /* we should be able to remove this call, each operator calls */
- ED_object_mode_compat_set(C, ob, mode, op->reports);
- }
-
- /* Exit current mode if it's not the mode we're setting */
- if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) {
- /* Enter new mode */
- ED_object_mode_toggle(C, mode);
- }
-
- if (toggle) {
- /* Special case for Object mode! */
- if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT &&
- ob->restore_mode != OB_MODE_OBJECT) {
- ED_object_mode_toggle(C, ob->restore_mode);
- }
- else if (ob->mode == mode) {
- /* For toggling, store old mode so we know what to go back to */
- ob->restore_mode = restore_mode;
- }
- else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) {
- ED_object_mode_toggle(C, ob->restore_mode);
+ /**
+ * Mode Switching Logic (internal details).
+ *
+ * Notes:
+ * - Code below avoids calling mode switching functions more than once,
+ * as this causes unnecessary calculations and undo steps to be added.
+ * - The previous mode (#Object.restore_mode) is object mode by default.
+ *
+ * Supported Cases:
+ * - Setting the mode (when the 'toggle' setting is off).
+ * - Toggle the mode:
+ * - Toggle between object mode and non-object mode property.
+ * - Toggle between the previous mode (#Object.restore_mode) and the mode property.
+ * - Toggle object mode.
+ * While this is similar to regular toggle,
+ * this operator depends on there being a previous mode set
+ * (this isn't bound to a key with the default key-map).
+ */
+ if (toggle == false) {
+ if (ob->mode != mode) {
+ ED_object_mode_set_ex(C, mode, true, op->reports);
}
}
-
- /* if type is OB_GPENCIL, set cursor mode */
- if ((ob) && (ob->type == OB_GPENCIL)) {
- if (ob->data) {
- bGPdata *gpd = (bGPdata *)ob->data;
- ED_gpencil_setup_modes(C, gpd, ob->mode);
+ else {
+ const eObjectMode mode_prev = ob->mode;
+ /* When toggling object mode, we always use the restore mode,
+ * otherwise there is nothing to do. */
+ if (mode == OB_MODE_OBJECT) {
+ if (ob->mode != OB_MODE_OBJECT) {
+ if (ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports)) {
+ /* Store old mode so we know what to go back to. */
+ ob->restore_mode = mode_prev;
+ }
+ }
+ else {
+ if (ob->restore_mode != OB_MODE_OBJECT) {
+ ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports);
+ }
+ }
+ }
+ else {
+ /* Non-object modes, enter the 'mode' unless it's already set,
+ * in that case use restore mode. */
+ if (ob->mode != mode) {
+ if (ED_object_mode_set_ex(C, mode, true, op->reports)) {
+ /* Store old mode so we know what to go back to. */
+ ob->restore_mode = mode_prev;
+ }
+ }
+ else {
+ if (ob->restore_mode != OB_MODE_OBJECT) {
+ ED_object_mode_set_ex(C, ob->restore_mode, true, op->reports);
+ }
+ else {
+ ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports);
+ }
+ }
}
}
@@ -1485,8 +1577,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_mode_set_exec;
-
- ot->poll = object_mode_set_poll; // ED_operator_object_active_editable;
+ ot->poll = object_mode_set_poll;
/* flags */
ot->flag = 0; /* no register/undo here, leave it to operators being called */
@@ -1516,6 +1607,12 @@ void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Link/Move to Collection Operator
+ * \{ */
+
static ListBase selected_objects_get(bContext *C)
{
ListBase objects = {NULL};
@@ -1593,7 +1690,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- for (LinkData *link = objects.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &objects) {
Object *ob = link->data;
if (!is_link) {
@@ -1856,3 +1953,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->prop = prop;
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 5bf5c4bd95a..6d0f53cfa1e 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -65,7 +65,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
{
GpencilModifierData *new_md = NULL;
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
if (ob->type != OB_GPENCIL) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
@@ -73,7 +73,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add(
}
if (mti->flags & eGpencilModifierTypeFlag_Single) {
- if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return NULL;
}
@@ -214,7 +214,7 @@ int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports),
static int gpencil_modifier_apply_obdata(
ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
{
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
if (mti->isDisabled && mti->isDisabled(md, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -281,18 +281,18 @@ int ED_object_gpencil_modifier_apply(Main *bmain,
int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
{
GpencilModifierData *nmd;
- const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
+ const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
GpencilModifierType type = md->type;
if (mti->flags & eGpencilModifierTypeFlag_Single) {
- if (BKE_gpencil_modifiers_findByType(ob, type)) {
+ if (BKE_gpencil_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return 0;
}
}
nmd = BKE_gpencil_modifier_new(md->type);
- BKE_gpencil_modifier_copyData(md, nmd);
+ BKE_gpencil_modifier_copydata(md, nmd);
BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
@@ -335,7 +335,7 @@ static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C,
for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
if (md_item->identifier[0]) {
- mti = BKE_gpencil_modifierType_getInfo(md_item->value);
+ mti = BKE_gpencil_modifier_get_info(md_item->value);
if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) {
continue;
@@ -455,7 +455,7 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
GpencilModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
- md = BKE_gpencil_modifiers_findByName(ob, modifier_name);
+ md = BKE_gpencil_modifiers_findby_name(ob, modifier_name);
if (md && type != 0 && md->type != type) {
md = NULL;
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 4414acff115..9d2e5e74352 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -552,14 +552,14 @@ static int add_hook_object(const bContext *C,
}
md = obedit->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
- hmd = (HookModifierData *)modifier_new(eModifierType_Hook);
+ hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook);
BLI_insertlinkbefore(&obedit->modifiers, md, hmd);
BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2);
- modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
+ BKE_modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd);
hmd->object = ob;
hmd->indexar = indexar;
@@ -725,7 +725,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op)
/* remove functionality */
BLI_remlink(&ob->modifiers, (ModifierData *)hmd);
- modifier_free((ModifierData *)hmd);
+ BKE_modifier_free((ModifierData *)hmd);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 559bb434f9d..d7a7b4ca110 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot);
void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
+void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot);
+void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot);
@@ -291,6 +293,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
/* object_remesh.c */
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
+void OBJECT_OT_voxel_size_edit(struct wmOperatorType *ot);
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
/* object_transfer_data.c */
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index f06b6a4db2a..c518fd32c7f 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -167,41 +167,6 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, eObjectMode mode, Report
return ok;
}
-void ED_object_mode_toggle(bContext *C, eObjectMode mode)
-{
- if (mode != OB_MODE_OBJECT) {
- const char *opstring = object_mode_op_string(mode);
-
- if (opstring) {
- wmOperatorType *ot = WM_operatortype_find(opstring, false);
- WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL);
- }
- }
-}
-
-/* Wrapper for operator */
-void ED_object_mode_set(bContext *C, eObjectMode mode)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wm->op_undo_depth++;
- /* needed so we don't do undo pushes. */
- ED_object_mode_generic_enter(C, mode);
- wm->op_undo_depth--;
-}
-
-void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph)
-{
- struct Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- FOREACH_OBJECT_BEGIN (view_layer, ob) {
- if (ob->mode & OB_MODE_ALL_MODE_DATA) {
- ED_object_mode_generic_exit(bmain, depsgraph, scene, ob);
- }
- }
- FOREACH_OBJECT_END;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -212,23 +177,50 @@ void ED_object_mode_exit(bContext *C, Depsgraph *depsgraph)
*
* \{ */
-bool ED_object_mode_generic_enter(struct bContext *C, eObjectMode object_mode)
+bool ED_object_mode_set_ex(bContext *C, eObjectMode mode, bool use_undo, ReportList *reports)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
if (ob == NULL) {
- return (object_mode == OB_MODE_OBJECT);
+ return (mode == OB_MODE_OBJECT);
}
- if (ob->mode == object_mode) {
+
+ if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) {
+ mode = OB_MODE_EDIT_GPENCIL;
+ }
+
+ if (ob->mode == mode) {
return true;
}
- wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
- PointerRNA ptr;
- WM_operator_properties_create_ptr(&ptr, ot);
- RNA_enum_set(&ptr, "mode", object_mode);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
- WM_operator_properties_free(&ptr);
- return (ob->mode == object_mode);
+
+ if (!ED_object_mode_compat_test(ob, mode)) {
+ return false;
+ }
+
+ const char *opstring = object_mode_op_string((mode == OB_MODE_OBJECT) ? ob->mode : mode);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
+
+ if (!use_undo) {
+ wm->op_undo_depth++;
+ }
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_REGION_WIN, NULL);
+ if (!use_undo) {
+ wm->op_undo_depth--;
+ }
+
+ if (ob->mode != mode) {
+ BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name);
+ return false;
+ }
+
+ return true;
+}
+
+bool ED_object_mode_set(bContext *C, eObjectMode mode)
+{
+ /* Don't do undo push by default, since this may be called by lower level code. */
+ return ED_object_mode_set_ex(C, mode, true, NULL);
}
/**
@@ -282,6 +274,18 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain,
ED_object_posemode_exit_ex(bmain, ob);
}
}
+ else if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
+ }
+ else if (ob->mode & OB_MODE_PARTICLE_EDIT) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
+ }
else if (ob->type == OB_GPENCIL) {
/* Accounted for above. */
BLI_assert((ob->mode & OB_MODE_OBJECT) == 0);
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 0de2f114b94..9398a5f2ce7 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -86,6 +86,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_sculpt.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -134,23 +135,24 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph,
Object *object,
ModifierData *md)
{
- ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md);
+ ModifierData *md_eval = (ModifierData *)BKE_modifier_get_evaluated(depsgraph, object, md);
const int mode = md_eval->mode;
md_eval->mode |= eModifierMode_Realtime;
object_force_modifier_update_for_bind(depsgraph, object);
md_eval->mode = mode;
}
-/** Add a modifier to given object, including relevant extra processing needed by some physics
- * types (particles, simulations...).
+/**
+ * Add a modifier to given object, including relevant extra processing needed by some physics types
+ * (particles, simulations...).
*
- * \param scene is only used to set current frame in some cases, and may be NULL.
+ * \param scene: is only used to set current frame in some cases, and may be NULL.
*/
ModifierData *ED_object_modifier_add(
ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type)
{
ModifierData *md = NULL, *new_md = NULL;
- const ModifierTypeInfo *mti = modifierType_getInfo(type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(type);
/* Check compatibility of modifier [T25291, T50373]. */
if (!BKE_object_support_modifier_type_check(ob, type)) {
@@ -159,7 +161,7 @@ ModifierData *ED_object_modifier_add(
}
if (mti->flags & eModifierTypeFlag_Single) {
- if (modifiers_findByType(ob, type)) {
+ if (BKE_modifiers_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
return NULL;
}
@@ -173,12 +175,12 @@ ModifierData *ED_object_modifier_add(
}
else {
/* get new modifier data to add */
- new_md = modifier_new(type);
+ new_md = BKE_modifier_new(type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
md = ob->modifiers.first;
- while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) {
+ while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) {
md = md->next;
}
@@ -194,7 +196,7 @@ ModifierData *ED_object_modifier_add(
/* make sure modifier data has unique name */
- modifier_unique_name(&ob->modifiers, new_md);
+ BKE_modifier_unique_name(&ob->modifiers, new_md);
/* special cases */
if (type == eModifierType_Softbody) {
@@ -381,7 +383,7 @@ static bool object_modifier_remove(Main *bmain,
}
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
BKE_object_free_derived_caches(ob);
return 1;
@@ -431,10 +433,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob)
int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->prev) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->type != eModifierTypeType_OnlyDeform) {
- const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+ const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->prev->type);
if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) {
BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data");
@@ -452,10 +454,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md
int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md)
{
if (md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
if (mti->flags & eModifierTypeFlag_RequiresOriginalData) {
- const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+ const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->next->type);
if (nmti->type != eModifierTypeType_OnlyDeform) {
BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier");
@@ -618,7 +620,7 @@ static int modifier_apply_shape(Main *bmain,
Object *ob,
ModifierData *md_eval)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -642,7 +644,7 @@ static int modifier_apply_shape(Main *bmain,
Key *key = me->key;
KeyBlock *kb;
- if (!modifier_isSameTopology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) {
+ if (!BKE_modifier_is_same_topology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) {
BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to shapes");
return 0;
}
@@ -678,7 +680,7 @@ static int modifier_apply_shape(Main *bmain,
static int modifier_apply_obdata(
ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md_eval)
{
- const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type);
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type);
if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) {
BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
@@ -789,7 +791,7 @@ bool ED_object_modifier_apply(Main *bmain,
return false;
}
else if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) &&
- (modifier_isSameTopology(md) == false)) {
+ (BKE_modifier_is_same_topology(md) == false)) {
BKE_report(reports,
RPT_ERROR,
"Constructive modifier cannot be applied to multi-res data in sculpt mode");
@@ -803,7 +805,7 @@ bool ED_object_modifier_apply(Main *bmain,
/* Get evaluated modifier, so object links pointer to evaluated data,
* but still use original object it is applied to the original mesh. */
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md;
+ ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md;
/* allow apply of a not-realtime modifier, by first re-enabling realtime. */
prev_mode = md_eval->mode;
@@ -824,7 +826,7 @@ bool ED_object_modifier_apply(Main *bmain,
md_eval->mode = prev_mode;
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
BKE_object_free_derived_caches(ob);
@@ -835,10 +837,10 @@ int ED_object_modifier_copy(ReportList *UNUSED(reports), Object *ob, ModifierDat
{
ModifierData *nmd;
- nmd = modifier_new(md->type);
- modifier_copyData(md, nmd);
+ nmd = BKE_modifier_new(md->type);
+ BKE_modifier_copydata(md, nmd);
BLI_insertlinkafter(&ob->modifiers, md, nmd);
- modifier_unique_name(&ob->modifiers, nmd);
+ BKE_modifier_unique_name(&ob->modifiers, nmd);
return 1;
}
@@ -884,7 +886,7 @@ static const EnumPropertyItem *modifier_add_itemf(bContext *C,
md_item = &rna_enum_object_modifier_type_items[a];
if (md_item->identifier[0]) {
- mti = modifierType_getInfo(md_item->value);
+ mti = BKE_modifier_get_info(md_item->value);
if (mti->flags & eModifierTypeFlag_NoUserAdd) {
continue;
@@ -1018,7 +1020,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type)
ModifierData *md;
RNA_string_get(op->ptr, "modifier", modifier_name);
- md = modifiers_findByName(ob, modifier_name);
+ md = BKE_modifiers_findby_name(ob, modifier_name);
if (md && type != 0 && md->type != type) {
md = NULL;
@@ -1198,7 +1200,7 @@ static bool modifier_apply_poll(bContext *C)
}
else if (md != NULL) {
if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) &&
- (modifier_isSameTopology(md) == false)) {
+ (BKE_modifier_is_same_topology(md) == false)) {
CTX_wm_operator_poll_msg_set(
C, "Constructive modifier cannot be applied to multi-res data in sculpt mode");
return false;
@@ -1431,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot)
/** \name Multires Subdivide Operator
* \{ */
+static EnumPropertyItem prop_multires_subdivide_mode_type[] = {
+ {MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "CATMULL_CLARK",
+ 0,
+ "Catmull-Clark",
+ "Create a new level using Catmull-Clark subdivisions"},
+ {MULTIRES_SUBDIVIDE_SIMPLE,
+ "SIMPLE",
+ 0,
+ "Simple",
+ "Create a new level using simple subdivisions"},
+ {MULTIRES_SUBDIVIDE_LINEAR,
+ "LINEAR",
+ 0,
+ "Linear",
+ "Create a new level using linear interpolation of the sculpted displacement"},
+ {0, NULL, 0, NULL, NULL},
+};
+
static int multires_subdivide_exec(bContext *C, wmOperator *op)
{
Object *object = ED_object_active_context(C);
@@ -1441,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- multiresModifier_subdivide(object, mmd);
+ const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)(
+ RNA_enum_get(op->ptr, "mode"));
+ multiresModifier_subdivide(object, mmd, subdivide_mode);
ED_object_iter_other(
CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl);
@@ -1480,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_multires_subdivide_mode_type,
+ MULTIRES_SUBDIVIDE_CATMULL_CLARK,
+ "Subdivision Mode",
+ "How the mesh is going to be subdivided to create a new level");
}
/** \} */
@@ -1697,8 +1726,12 @@ static int multires_base_apply_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ ED_sculpt_undo_push_multires_mesh_begin(C, op->type->name);
+
multiresModifier_base_apply(depsgraph, object, mmd);
+ ED_sculpt_undo_push_multires_mesh_end(C, op->type->name);
+
DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
@@ -1726,6 +1759,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
ot->exec = multires_base_apply_exec;
/* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Multires Unsubdivide
+ * \{ */
+
+static int multires_unsubdivide_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level");
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_unsubdivide_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot)
+{
+ ot->name = "Unsubdivide";
+ ot->description = "Rebuild a lower subdivision level of the current base mesh";
+ ot->idname = "OBJECT_OT_multires_unsubdivide";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_unsubdivide_invoke;
+ ot->exec = multires_unsubdivide_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+/** \} */
+
+/* ------------------------------------------------------------------- */
+/** \name Multires Rebuild Subdivisions
+ * \{ */
+
+static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *object = ED_object_active_context(C);
+ MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(
+ op, object, eModifierType_Multires);
+
+ if (!mmd) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false);
+ if (new_levels == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels);
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object);
+
+ return OPERATOR_FINISHED;
+}
+
+static int multires_rebuild_subdiv_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ if (edit_modifier_invoke_properties(C, op)) {
+ return multires_rebuild_subdiv_exec(C, op);
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot)
+{
+ ot->name = "Rebuild Lower Subdivisions";
+ ot->description =
+ "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh";
+ ot->idname = "OBJECT_OT_multires_rebuild_subdiv";
+
+ ot->poll = multires_poll;
+ ot->invoke = multires_rebuild_subdiv_invoke;
+ ot->exec = multires_rebuild_subdiv_exec;
+
+ /* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
edit_modifier_properties(ot);
}
@@ -2066,7 +2212,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op)
arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob);
/* add a modifier to connect the new armature to the mesh */
- arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature);
+ arm_md = (ArmatureModifierData *)BKE_modifier_new(eModifierType_Armature);
if (arm_md) {
skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin);
BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md);
@@ -2130,7 +2276,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
+ if (!BKE_modifier_is_enabled(scene, &csmd->modifier, eModifierMode_Realtime)) {
BKE_report(op->reports, RPT_ERROR, "Modifier is disabled");
return OPERATOR_CANCELLED;
}
@@ -2147,8 +2293,8 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
else {
/* Signal to modifier to recalculate. */
CorrectiveSmoothModifierData *csmd_eval = (CorrectiveSmoothModifierData *)
- modifier_get_evaluated(depsgraph, ob, &csmd->modifier);
- csmd_eval->bind_coords_num = (unsigned int)-1;
+ BKE_modifier_get_evaluated(depsgraph, ob, &csmd->modifier);
+ csmd_eval->bind_coords_num = (uint)-1;
/* Force modifier to run, it will call binding routine
* (this has to happen outside of depsgraph evaluation). */
@@ -2226,7 +2372,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
else {
/* Force modifier to run, it will call binding routine
* (this has to happen outside of depsgraph evaluation). */
- MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)modifier_get_evaluated(
+ MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)BKE_modifier_get_evaluated(
depsgraph, ob, &mmd->modifier);
mmd_eval->bindfunc = ED_mesh_deform_bind_callback;
object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier);
@@ -2431,7 +2577,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
}
och = BKE_ocean_init_cache(omd->cachepath,
- modifier_path_relbase(bmain, ob),
+ BKE_modifier_path_relbase(bmain, ob),
omd->bakestart,
omd->bakeend,
omd->wave_scale,
@@ -2450,7 +2596,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op)
* No drivers or other modifier parameters. */
/* TODO(sergey): This operates on an original data, so no flush is needed. However, baking
* usually should happen on an evaluated objects, so this seems to be deeper issue here. */
- BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
+ BKE_animsys_evaluate_animdata((ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false);
och->time[i] = omd->time;
i++;
@@ -2554,8 +2700,8 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op)
lmd->flag |= MOD_LAPLACIANDEFORM_BIND;
}
- LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)modifier_get_evaluated(
- depsgraph, ob, &lmd->modifier);
+ LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)
+ BKE_modifier_get_evaluated(depsgraph, ob, &lmd->modifier);
lmd_eval->flag = lmd->flag;
/* Force modifier to run, it will call binding routine
@@ -2633,7 +2779,7 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op)
smd->flags |= MOD_SDEF_BIND;
}
- SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)modifier_get_evaluated(
+ SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)BKE_modifier_get_evaluated(
depsgraph, ob, &smd->modifier);
smd_eval->flags = smd->flags;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index cacf7b67777..819b6c18a44 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -137,6 +137,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_multires_reshape);
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
WM_operatortype_append(OBJECT_OT_multires_base_apply);
+ WM_operatortype_append(OBJECT_OT_multires_unsubdivide);
+ WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv);
WM_operatortype_append(OBJECT_OT_multires_external_save);
WM_operatortype_append(OBJECT_OT_multires_external_pack);
WM_operatortype_append(OBJECT_OT_skin_root_mark);
@@ -265,6 +267,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_hide_collection);
WM_operatortype_append(OBJECT_OT_voxel_remesh);
+ WM_operatortype_append(OBJECT_OT_voxel_size_edit);
+
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
}
diff --git a/source/blender/editors/object/object_random.c b/source/blender/editors/object/object_random.c
index 43aaecb887b..a6958c798f1 100644
--- a/source/blender/editors/object/object_random.c
+++ b/source/blender/editors/object/object_random.c
@@ -50,7 +50,7 @@ static bool object_rand_transverts(TransVertStore *tvs,
const float offset,
const float uniform,
const float normal_factor,
- const unsigned int seed)
+ const uint seed)
{
bool use_normal = (normal_factor != 0.0f);
struct RNG *rng;
@@ -100,7 +100,7 @@ static int object_rand_verts_exec(bContext *C, wmOperator *op)
const float offset = RNA_float_get(op->ptr, "offset");
const float uniform = RNA_float_get(op->ptr, "uniform");
const float normal_factor = RNA_float_get(op->ptr, "normal");
- const unsigned int seed = RNA_int_get(op->ptr, "seed");
+ const uint seed = RNA_int_get(op->ptr, "seed");
bool changed_multi = false;
uint objects_len = 0;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 3166c9ddea1..0e8545e07ba 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -55,7 +55,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_camera.h"
#include "BKE_collection.h"
@@ -557,7 +557,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
/* free modifier if match */
if (free) {
BLI_remlink(&ob->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
}
}
}
@@ -803,7 +803,7 @@ bool ED_object_parent_set(ReportList *reports,
switch (partype) {
case PAR_CURVE: /* curve deform */
- if (modifiers_isDeformedByCurve(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_curve(ob) != par) {
md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve);
if (md) {
((CurveModifierData *)md)->object = par;
@@ -814,7 +814,7 @@ bool ED_object_parent_set(ReportList *reports,
}
break;
case PAR_LATTICE: /* lattice deform */
- if (modifiers_isDeformedByLattice(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_lattice(ob) != par) {
md = ED_object_modifier_add(
reports, bmain, scene, ob, NULL, eModifierType_Lattice);
if (md) {
@@ -823,7 +823,7 @@ bool ED_object_parent_set(ReportList *reports,
}
break;
default: /* armature deform */
- if (modifiers_isDeformedByArmature(ob) != par) {
+ if (BKE_modifiers_is_deformed_by_armature(ob) != par) {
md = ED_object_modifier_add(
reports, bmain, scene, ob, NULL, eModifierType_Armature);
if (md) {
@@ -899,7 +899,10 @@ bool ED_object_parent_set(ReportList *reports,
invert_m4_m4(ob->parentinv, workob.obmat);
}
else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) {
- if (partype == PAR_ARMATURE_NAME) {
+ if (partype == PAR_ARMATURE) {
+ ED_gpencil_add_armature(C, reports, ob, par);
+ }
+ else if (partype == PAR_ARMATURE_NAME) {
ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME);
}
else if ((partype == PAR_ARMATURE_AUTO) || (partype == PAR_ARMATURE_ENVELOPE)) {
@@ -1424,7 +1427,7 @@ void OBJECT_OT_track_set(wmOperatorType *ot)
* \{ */
#if 0
-static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
+static void link_to_scene(Main *UNUSED(bmain), ushort UNUSED(nr))
{
Scene *sce = (Scene *)BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1);
Base *base, *nbase;
@@ -1753,7 +1756,7 @@ static void libblock_relink_collection(Collection *collection, const bool do_col
BKE_libblock_relink_to_newid(&cob->ob->id);
}
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
libblock_relink_collection(child->collection, true);
}
}
@@ -1772,7 +1775,7 @@ static Collection *single_object_users_collection(Main *bmain,
}
/* We do not remap to new objects here, this is done in separate step. */
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
Object *ob = cob->ob;
/* an object may be in more than one collection */
if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) {
@@ -2069,7 +2072,7 @@ void ED_object_single_users(Main *bmain,
/* Duplicating obdata and other IDs may require another update of the collections and objects
* pointers, especially regarding drivers and custom props, see T66641.
- * Note that this whole scene duplication code and 'make single user' functions have te be
+ * Note that this whole scene duplication code and 'make single user' functions have to be
* rewritten at some point to make use of proper modern ID management code,
* but that is no small task.
* For now we are doomed to that kind of band-aid to try to cover most of remapping cases. */
@@ -2106,7 +2109,7 @@ void ED_object_single_users(Main *bmain,
if (scene->nodetree) {
IDP_RelinkProperty(scene->nodetree->id.properties);
- for (bNode *node = scene->nodetree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &scene->nodetree->nodes) {
IDP_RelinkProperty(node->prop);
}
}
@@ -2245,7 +2248,7 @@ static void make_local_animdata_tag(AnimData *adt)
/* TODO: need to handle the ID-targets too? */
/* NLA Data */
- for (NlaTrack *nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) {
make_local_animdata_tag_strips(&nlt->strips);
}
}
@@ -2513,7 +2516,8 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
ViewLayer *view_layer = CTX_data_view_layer(C);
Collection *new_collection = (Collection *)collection->id.newid;
- BKE_collection_child_add(bmain, scene->master_collection, new_collection);
+ BKE_collection_add_from_object(bmain, scene, obcollection, new_collection);
+
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (new_collection, new_ob) {
if (new_ob != NULL && new_ob->id.override_library != NULL) {
if ((base = BKE_view_layer_base_find(view_layer, new_ob)) == NULL) {
@@ -2521,14 +2525,7 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
base = BKE_view_layer_base_find(view_layer, new_ob);
DEG_id_tag_update_ex(bmain, &new_ob->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
}
- /* parent to 'collection' empty */
- /* Disabled for now, according to some artist this is probably not really useful anyway.
- * And it breaks things like objects parented to bones
- * (most likely due to missing proper setting of inverse parent matrix?)... */
- /* Note: we might even actually want to get rid of that instantiating empty... */
- if (0 && new_ob->parent == NULL) {
- new_ob->parent = obcollection;
- }
+
if (new_ob == (Object *)obact->id.newid) {
/* TODO: is setting active needed? */
BKE_view_layer_base_select_and_set_active(view_layer, base);
@@ -2543,9 +2540,9 @@ static int make_override_library_exec(bContext *C, wmOperator *op)
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
- /* obcollection is no more duplicollection-ing,
- * it merely parents whole collection of overriding instantiated objects. */
- obcollection->instance_collection = NULL;
+ /* Remove the instance empty from this scene, the items now have an overridden collection
+ * instead. */
+ ED_object_base_free_and_unlink(bmain, scene, obcollection);
/* Also, we'd likely want to lock by default things like
* transformations of implicitly overridden objects? */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index a9f2319d926..22869748b22 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -37,6 +37,9 @@
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -61,22 +64,38 @@
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_space_api.h"
#include "ED_undo.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "GPU_draw.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
#include "WM_api.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "UI_interface.h"
+
+#include "BLF_api.h"
+
#include "object_intern.h" // own include
/* TODO(sebpa): unstable, can lead to unrecoverable errors. */
// #define USE_MESH_CURVATURE
+/* -------------------------------------------------------------------- */
+/** \name Voxel Remesh Operator
+ * \{ */
+
static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -95,7 +114,7 @@ static bool object_remesh_poll(bContext *C)
return false;
}
- if (modifiers_usesMultires(ob)) {
+ if (BKE_modifiers_uses_multires(ob)) {
CTX_wm_operator_poll_msg_set(
C, "The remesher cannot run with a Multires modifier in the modifier stack");
return false;
@@ -188,16 +207,413 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Voxel Size Operator
+ * \{ */
+
+#define VOXEL_SIZE_EDIT_MAX_GRIDS_LINES 500
+#define VOXEL_SIZE_EDIT_MAX_STR_LEN 20
+
+typedef struct VoxelSizeEditCustomData {
+ void *draw_handle;
+ Object *active_object;
+
+ float init_mval[2];
+ float slow_mval[2];
+
+ bool slow_mode;
+
+ float init_voxel_size;
+ float slow_voxel_size;
+ float voxel_size;
+
+ float preview_plane[4][3];
+
+ float text_mat[4][4];
+} VoxelSizeEditCustomData;
+
+static void voxel_size_parallel_lines_draw(uint pos3d,
+ const float initial_co[3],
+ const float end_co[3],
+ const float length_co[3],
+ const float spacing)
+{
+ const float total_len = len_v3v3(initial_co, end_co);
+ const int tot_lines = (int)(total_len / spacing);
+ const int tot_lines_half = (tot_lines / 2) + 1;
+ float spacing_dir[3], lines_start[3];
+ float line_dir[3];
+ sub_v3_v3v3(spacing_dir, end_co, initial_co);
+ normalize_v3(spacing_dir);
+
+ sub_v3_v3v3(line_dir, length_co, initial_co);
+
+ if (tot_lines > VOXEL_SIZE_EDIT_MAX_GRIDS_LINES || tot_lines <= 1) {
+ return;
+ }
+
+ mid_v3_v3v3(lines_start, initial_co, end_co);
+
+ immBegin(GPU_PRIM_LINES, (uint)tot_lines_half * 2);
+ for (int i = 0; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+
+ mul_v3_fl(spacing_dir, -1.0f);
+
+ immBegin(GPU_PRIM_LINES, (uint)(tot_lines_half - 1) * 2);
+ for (int i = 1; i < tot_lines_half; i++) {
+ float line_start[3];
+ float line_end[3];
+ madd_v3_v3v3fl(line_start, lines_start, spacing_dir, spacing * i);
+ add_v3_v3v3(line_end, line_start, line_dir);
+ immVertex3fv(pos3d, line_start);
+ immVertex3fv(pos3d, line_end);
+ }
+ immEnd();
+}
+
+static void voxel_size_edit_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ VoxelSizeEditCustomData *cd = arg;
+
+ GPU_blend(true);
+ GPU_line_smooth(true);
+
+ uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->active_object->obmat);
+
+ /* Draw Rect */
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f);
+ GPU_line_width(3.0f);
+
+ immBegin(GPU_PRIM_LINES, 8);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+
+ immVertex3fv(pos3d, cd->preview_plane[1]);
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+
+ immVertex3fv(pos3d, cd->preview_plane[2]);
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+
+ immVertex3fv(pos3d, cd->preview_plane[3]);
+ immVertex3fv(pos3d, cd->preview_plane[0]);
+ immEnd();
+
+ /* Draw Grid */
+ GPU_line_width(1.0f);
+
+ const float total_len = len_v3v3(cd->preview_plane[0], cd->preview_plane[1]);
+ const int tot_lines = (int)(total_len / cd->voxel_size);
+
+ /* Smoothstep to reduce the alpha of the grid as the line number increases. */
+ const float a = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES * 0.1f;
+ const float b = VOXEL_SIZE_EDIT_MAX_GRIDS_LINES;
+ const float x = clamp_f((tot_lines - a) / (b - a), 0.0f, 1.0);
+ const float alpha_factor = 1.0f - (x * x * (3.0f - 2.0f * x));
+
+ immUniformColor4f(0.9f, 0.9f, 0.9f, 0.75f * alpha_factor);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[3], cd->voxel_size);
+ voxel_size_parallel_lines_draw(
+ pos3d, cd->preview_plane[1], cd->preview_plane[2], cd->preview_plane[0], cd->voxel_size);
+
+ /* Draw text */
+ const uiStyle *style = UI_style_get();
+ const uiFontStyle *fstyle = &style->widget;
+ const int fontid = fstyle->uifont_id;
+ float strwidth, strheight;
+ short fstyle_points = fstyle->points;
+ char str[VOXEL_SIZE_EDIT_MAX_STR_LEN];
+ short strdrawlen = 0;
+
+ BLI_snprintf(str, VOXEL_SIZE_EDIT_MAX_STR_LEN, "%3.4f%%", cd->voxel_size);
+ strdrawlen = BLI_strlen_utf8(str);
+
+ immUnbindProgram();
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cd->text_mat);
+ BLF_size(fontid, 10.0f * fstyle_points, U.dpi);
+ BLF_color3f(fontid, 1.0f, 1.0f, 1.0f);
+ BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight);
+ BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f);
+ BLF_draw(fontid, str, strdrawlen);
+ GPU_matrix_pop();
+
+ GPU_matrix_pop();
+
+ GPU_blend(false);
+ GPU_line_smooth(false);
+}
+
+static void voxel_size_edit_cancel(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+
+ MEM_freeN(op->customdata);
+
+ ED_workspace_status_text(C, NULL);
+}
+
+static int voxel_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ VoxelSizeEditCustomData *cd = op->customdata;
+ Object *active_object = cd->active_object;
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ /* Cancel modal operator */
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ voxel_size_edit_cancel(C, op);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ /* Finish modal operator */
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+ ED_region_draw_cb_exit(ar->type, cd->draw_handle);
+ mesh->remesh_voxel_size = cd->voxel_size;
+ MEM_freeN(op->customdata);
+ ED_region_tag_redraw(ar);
+ return OPERATOR_FINISHED;
+ }
+
+ float mval[2] = {event->mval[0], event->mval[1]};
+
+ float d = cd->init_mval[0] - mval[0];
+
+ if (cd->slow_mode) {
+ d = cd->slow_mval[0] - mval[0];
+ }
+
+ if (event->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;
+ }
+ if (cd->slow_mode) {
+ cd->voxel_size = cd->slow_voxel_size + d * 0.05f;
+ }
+ else {
+ cd->voxel_size = cd->init_voxel_size + d;
+ }
+
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) {
+ cd->slow_mode = true;
+ copy_v2_v2(cd->slow_mval, mval);
+ cd->slow_voxel_size = cd->voxel_size;
+ }
+ if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) {
+ cd->slow_mode = false;
+ cd->slow_voxel_size = 0.0f;
+ }
+
+ cd->voxel_size = clamp_f(cd->voxel_size, 0.0001f, 1.0f);
+
+ ED_region_tag_redraw(ar);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Object *active_object = CTX_data_active_object(C);
+ Mesh *mesh = (Mesh *)active_object->data;
+
+ VoxelSizeEditCustomData *cd = MEM_callocN(sizeof(VoxelSizeEditCustomData),
+ "Voxel Size Edit OP Custom Data");
+
+ /* Initial operator Custom Data setup. */
+ cd->draw_handle = ED_region_draw_cb_activate(
+ ar->type, voxel_size_edit_draw, cd, REGION_DRAW_POST_VIEW);
+ cd->active_object = active_object;
+ cd->init_mval[0] = event->mval[0];
+ cd->init_mval[1] = event->mval[1];
+ cd->init_voxel_size = mesh->remesh_voxel_size;
+ cd->voxel_size = mesh->remesh_voxel_size;
+ op->customdata = cd;
+
+ /* Select the front facing face of the mesh boundig box. */
+ BoundBox *bb = BKE_mesh_boundbox_get(cd->active_object);
+
+ /* Indices of the Bounding Box faces. */
+ int BB_faces[6][4] = {
+ {3, 0, 4, 7},
+ {1, 2, 6, 5},
+ {3, 2, 1, 0},
+ {4, 5, 6, 7},
+ {0, 1, 5, 4},
+ {2, 3, 7, 6},
+ };
+
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[0][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[0][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[0][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[0][3]]);
+
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ float mat[3][3];
+ float current_normal[3];
+ float view_normal[3] = {0.0f, 0.0f, 1.0f};
+
+ /* Calculate the view normal. */
+ invert_m4_m4(active_object->imat, active_object->obmat);
+ copy_m3_m4(mat, rv3d->viewinv);
+ mul_m3_v3(mat, view_normal);
+ copy_m3_m4(mat, active_object->imat);
+ mul_m3_v3(mat, view_normal);
+ normalize_v3(view_normal);
+
+ normal_tri_v3(current_normal, cd->preview_plane[0], cd->preview_plane[1], cd->preview_plane[2]);
+
+ float min_dot = dot_v3v3(current_normal, view_normal);
+ float current_dot = 1;
+
+ /* Check if there is a face that is more aligned towards the view. */
+ for (int i = 0; i < 6; i++) {
+ normal_tri_v3(
+ current_normal, bb->vec[BB_faces[i][0]], bb->vec[BB_faces[i][1]], bb->vec[BB_faces[i][2]]);
+ current_dot = dot_v3v3(current_normal, view_normal);
+
+ if (current_dot < min_dot) {
+ min_dot = current_dot;
+ copy_v3_v3(cd->preview_plane[0], bb->vec[BB_faces[i][0]]);
+ copy_v3_v3(cd->preview_plane[1], bb->vec[BB_faces[i][1]]);
+ copy_v3_v3(cd->preview_plane[2], bb->vec[BB_faces[i][2]]);
+ copy_v3_v3(cd->preview_plane[3], bb->vec[BB_faces[i][3]]);
+ }
+ }
+
+ /* Matrix calculation to position the text in 3D space. */
+ float text_pos[3];
+ float scale_mat[4][4];
+
+ float d_a[3], d_b[3];
+ float d_a_proj[2], d_b_proj[2];
+ float preview_plane_proj[4][3];
+ float y_axis_proj[2] = {0.0f, 1.0f};
+
+ mid_v3_v3v3(text_pos, cd->preview_plane[0], cd->preview_plane[2]);
+
+ /* Project the selected face in the previous step of the Bounding Box. */
+ for (int i = 0; i < 4; i++) {
+ ED_view3d_project(ar, cd->preview_plane[i], preview_plane_proj[i]);
+ }
+
+ /* Get the initial X and Y axis of the basis from the edges of the Bounding Box face. */
+ sub_v3_v3v3(d_a, cd->preview_plane[1], cd->preview_plane[0]);
+ sub_v3_v3v3(d_b, cd->preview_plane[3], cd->preview_plane[0]);
+ normalize_v3(d_a);
+ normalize_v3(d_b);
+
+ /* Project the X and Y axis. */
+ sub_v2_v2v2(d_a_proj, preview_plane_proj[1], preview_plane_proj[0]);
+ sub_v2_v2v2(d_b_proj, preview_plane_proj[3], preview_plane_proj[0]);
+ normalize_v2(d_a_proj);
+ normalize_v2(d_b_proj);
+
+ unit_m4(cd->text_mat);
+
+ /* Select the axis that is aligned with the view Y axis to use it as the basis Y. */
+ if (fabsf(dot_v2v2(d_a_proj, y_axis_proj)) > fabsf(dot_v2v2(d_b_proj, y_axis_proj))) {
+ copy_v3_v3(cd->text_mat[0], d_b);
+ copy_v3_v3(cd->text_mat[1], d_a);
+
+ /* Flip the X and Y basis vectors to make sure they always point upwards and to the right. */
+ if (d_b_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_a_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+ else {
+ copy_v3_v3(cd->text_mat[0], d_a);
+ copy_v3_v3(cd->text_mat[1], d_b);
+ if (d_a_proj[0] < 0.0f) {
+ mul_v3_fl(cd->text_mat[0], -1.0f);
+ }
+ if (d_b_proj[1] < 0.0f) {
+ mul_v3_fl(cd->text_mat[1], -1.0f);
+ }
+ }
+
+ /* 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]);
+
+ /* Write the text position into the matrix. */
+ copy_v3_v3(cd->text_mat[3], text_pos);
+
+ /* Scale the text. */
+ unit_m4(scale_mat);
+ scale_m4_fl(scale_mat, 0.0008f);
+ mul_m4_m4_post(cd->text_mat, scale_mat);
+
+ WM_event_add_modal_handler(C, op);
+
+ ED_region_tag_redraw(ar);
+
+ const char *status_str = TIP_(
+ "Move the mouse to change the voxel size. LMB: confirm size, ESC/RMB: cancel");
+ ED_workspace_status_text(C, status_str);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void OBJECT_OT_voxel_size_edit(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Edit Voxel Size";
+ ot->description = "Modify the mesh voxel size interactively used in the voxel remesher";
+ ot->idname = "OBJECT_OT_voxel_size_edit";
+
+ /* api callbacks */
+ ot->poll = object_remesh_poll;
+ ot->invoke = voxel_size_edit_invoke;
+ ot->modal = voxel_size_edit_modal;
+ ot->cancel = voxel_size_edit_cancel;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Quadriflow Remesh Operator
+ * \{ */
+
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
enum {
QUADRIFLOW_REMESH_RATIO = 1,
QUADRIFLOW_REMESH_EDGE_LENGTH,
QUADRIFLOW_REMESH_FACES,
};
-/****************** quadriflow remesh operator *********************/
-
-#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
-
typedef enum eSymmetryAxes {
SYMMETRY_AXES_X = (1 << 0),
SYMMETRY_AXES_Y = (1 << 1),
@@ -237,13 +653,13 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
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(unsigned int), "remesh_consistent_check");
+ mesh->totedge, sizeof(uint), "remesh_consistent_check");
- for (unsigned int i = 0; i < mesh->totedge; i++) {
+ for (uint i = 0; i < mesh->totedge; i++) {
edge_vert[i] = -1;
}
- for (unsigned int loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
+ 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) {
@@ -263,7 +679,7 @@ static bool mesh_is_manifold_consistent(Mesh *mesh)
if (is_manifold_consistent) {
/* check for wire edges */
- for (unsigned int i = 0; i < mesh->totedge; i++) {
+ for (uint i = 0; i < mesh->totedge; i++) {
if (edge_faces[i] == 0) {
is_manifold_consistent = false;
break;
@@ -764,3 +1180,5 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
0,
255);
}
+
+/** \} */
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 8f01adb202e..5f9799710dc 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -246,7 +246,7 @@ Base *ED_object_find_first_by_data_id(ViewLayer *view_layer, ID *id)
Base *base_best = NULL;
int priority_best = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object && base->object->data == id) {
if (base->flag & BASE_SELECTED) {
return base;
@@ -1325,7 +1325,7 @@ static bool object_select_more_less(bContext *C, const bool select)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
ob->flag &= ~OB_DONE;
ob->id.tag &= ~LIB_TAG_DOIT;
diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c
index cd71ab674ba..30fcdfc88bc 100644
--- a/source/blender/editors/object/object_shader_fx.c
+++ b/source/blender/editors/object/object_shader_fx.c
@@ -66,7 +66,7 @@ ShaderFxData *ED_object_shaderfx_add(
ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
{
ShaderFxData *new_fx = NULL;
- const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
+ const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type);
if (ob->type != OB_GPENCIL) {
BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
@@ -74,7 +74,7 @@ ShaderFxData *ED_object_shaderfx_add(
}
if (fxi->flags & eShaderFxTypeFlag_Single) {
- if (BKE_shaderfx_findByType(ob, type)) {
+ if (BKE_shaderfx_findby_type(ob, type)) {
BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
return NULL;
}
@@ -236,7 +236,7 @@ static const EnumPropertyItem *shaderfx_add_itemf(bContext *C,
for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
fx_item = &rna_enum_object_shaderfx_type_items[a];
if (fx_item->identifier[0]) {
- mti = BKE_shaderfxType_getInfo(fx_item->value);
+ mti = BKE_shaderfx_get_info(fx_item->value);
if (mti->flags & eShaderFxTypeFlag_NoUserAdd) {
continue;
@@ -356,7 +356,7 @@ static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int
ShaderFxData *fx;
RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
- fx = BKE_shaderfx_findByName(ob, shaderfx_name);
+ fx = BKE_shaderfx_findby_name(ob, shaderfx_name);
if (fx && type != 0 && fx->type != type) {
fx = NULL;
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index abce985b65a..26d33bbc375 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -126,7 +126,7 @@ static bool object_shape_key_mirror(
float *fp1, *fp2;
float tvec[3];
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table_begin(ob, NULL, NULL);
for (i1 = 0, mv = me->mvert; i1 < me->totvert; i1++, mv++) {
i2 = mesh_get_x_mirror_vert(ob, NULL, i1, use_topology);
@@ -157,7 +157,7 @@ static bool object_shape_key_mirror(
}
}
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 28bb28a0298..132b530455e 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1608,6 +1608,7 @@ struct XFormAxisItem {
float rot_mat[3][3];
void *obtfm;
float xform_dist;
+ bool is_z_flip;
#ifdef USE_RELATIVE_ROTATION
/* use when translating multiple */
@@ -1727,14 +1728,19 @@ static void object_apply_location(Object *ob, const float loc[3])
copy_v3_v3(ob->loc, mat[3]);
}
-static void object_orient_to_location(Object *ob,
+static bool object_orient_to_location(Object *ob,
const float rot_orig[3][3],
const float axis[3],
- const float location[3])
+ const float location[3],
+ const bool z_flip)
{
float delta[3];
sub_v3_v3v3(delta, ob->obmat[3], location);
if (normalize_v3(delta) != 0.0f) {
+ if (z_flip) {
+ negate_v3(delta);
+ }
+
if (len_squared_v3v3(delta, axis) > FLT_EPSILON) {
float delta_rot[3][3];
float final_rot[3][3];
@@ -1744,9 +1750,10 @@ static void object_orient_to_location(Object *ob,
object_apply_rotation(ob, final_rot);
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ return true;
}
}
+ return false;
}
static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
@@ -1840,6 +1847,11 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons
for (int i = 0; i < xfd->object_data_len; i++, item++) {
item->obtfm = BKE_object_tfm_backup(item->ob);
BKE_object_rot_to_mat3(item->ob, item->rot_mat, true);
+
+ /* Detect negative scale matrix. */
+ float full_mat3[3][3];
+ BKE_object_to_mat3(item->ob, full_mat3);
+ item->is_z_flip = dot_v3v3(item->rot_mat[2], full_mat3[2]) < 0.0f;
}
}
@@ -1860,8 +1872,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
if (event->type == MOUSEMOVE || is_translate_init) {
const ViewDepths *depths = xfd->vc.rv3d->depths;
- if (depths && ((unsigned int)event->mval[0] < depths->w) &&
- ((unsigned int)event->mval[1] < depths->h)) {
+ if (depths && ((uint)event->mval[0] < depths->w) && ((uint)event->mval[1] < depths->h)) {
double depth = (double)ED_view3d_depth_read_cached(&xfd->vc, event->mval);
float location_world[3];
if (depth == 1.0f) {
@@ -1894,9 +1905,9 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
normal_found = true;
/* cheap attempt to smooth normals out a bit! */
- const uint ofs = 2;
- for (uint x = -ofs; x <= ofs; x += ofs / 2) {
- for (uint y = -ofs; y <= ofs; y += ofs / 2) {
+ const int ofs = 2;
+ for (int x = -ofs; x <= ofs; x += ofs / 2) {
+ for (int y = -ofs; y <= ofs; y += ofs / 2) {
if (x != 0 && y != 0) {
int mval_ofs[2] = {event->mval[0] + x, event->mval[1] + y};
float n[3];
@@ -1913,7 +1924,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
normal_found = true;
}
- if (normal_found) {
+ {
#ifdef USE_RELATIVE_ROTATION
if (is_translate_init && xfd->object_data_len > 1) {
float xform_rot_offset_inv_first[3][3];
@@ -1942,16 +1953,26 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
item->xform_dist = len_v3v3(item->ob->obmat[3], location_world);
normalize_v3_v3(ob_axis, item->ob->obmat[2]);
/* Scale to avoid adding distance when moving between surfaces. */
- float scale = fabsf(dot_v3v3(ob_axis, normal));
- item->xform_dist *= scale;
+ if (normal_found) {
+ float scale = fabsf(dot_v3v3(ob_axis, normal));
+ item->xform_dist *= scale;
+ }
}
float target_normal[3];
- copy_v3_v3(target_normal, normal);
+
+ if (normal_found) {
+ copy_v3_v3(target_normal, normal);
+ }
+ else {
+ normalize_v3_v3(target_normal, item->ob->obmat[2]);
+ }
#ifdef USE_RELATIVE_ROTATION
- if (i != 0) {
- mul_m3_v3(item->xform_rot_offset, target_normal);
+ if (normal_found) {
+ if (i != 0) {
+ mul_m3_v3(item->xform_rot_offset, target_normal);
+ }
}
#endif
{
@@ -1965,18 +1986,28 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const
}
object_orient_to_location(
- item->ob, item->rot_mat, item->rot_mat[2], location_world);
+ item->ob, item->rot_mat, item->rot_mat[2], location_world, item->is_z_flip);
+
+ DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
}
- copy_v3_v3(xfd->prev.normal, normal);
- xfd->prev.is_normal_valid = true;
+ if (normal_found) {
+ copy_v3_v3(xfd->prev.normal, normal);
+ xfd->prev.is_normal_valid = true;
+ }
}
}
else {
struct XFormAxisItem *item = xfd->object_data;
for (int i = 0; i < xfd->object_data_len; i++, item++) {
- object_orient_to_location(item->ob, item->rot_mat, item->rot_mat[2], location_world);
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ if (object_orient_to_location(item->ob,
+ item->rot_mat,
+ item->rot_mat[2],
+ location_world,
+ item->is_z_flip)) {
+ DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM);
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob);
+ }
}
xfd->prev.is_normal_valid = false;
}
diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c
index d6056f85932..00aafc2120f 100644
--- a/source/blender/editors/object/object_utils.c
+++ b/source/blender/editors/object/object_utils.c
@@ -28,6 +28,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -193,7 +194,7 @@ void ED_object_xform_skip_child_container_item_ensure_from_array(
BLI_gset_add(objects_in_transdata, ob);
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->parent != NULL) {
if (!BLI_gset_haskey(objects_in_transdata, ob)) {
@@ -223,7 +224,7 @@ void ED_object_xform_skip_child_container_item_ensure_from_array(
}
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (BLI_gset_haskey(objects_in_transdata, ob)) {
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index 3ec55d42849..fb79cfb910e 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -3945,7 +3945,7 @@ 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) {
- Object *armobj = modifiers_isDeformedByArmature(ob);
+ Object *armobj = BKE_modifiers_is_deformed_by_armature(ob);
if (armobj != NULL) {
bArmature *armature = armobj->data;
bonebase = &armature->bonebase;
diff --git a/source/blender/editors/object/object_volume.c b/source/blender/editors/object/object_volume.c
index 92fb0788f6b..4cdbbea492b 100644
--- a/source/blender/editors/object/object_volume.c
+++ b/source/blender/editors/object/object_volume.c
@@ -59,7 +59,7 @@ static Object *object_volume_add(bContext *C, wmOperator *op, const char *name)
ushort local_view_bits;
float loc[3], rot[3];
- if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, &local_view_bits, NULL)) {
+ if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, NULL, NULL, &local_view_bits, NULL)) {
return false;
}
return ED_object_add_type(C, OB_VOLUME, name, loc, rot, false, local_view_bits);
@@ -96,7 +96,7 @@ static int volume_import_exec(bContext *C, wmOperator *op)
bool imported = false;
ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, false);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
char filename[FILE_MAX];
BLI_split_file_part(range->filepath, filename, sizeof(filename));
BLI_path_extension_replace(filename, sizeof(filename), "");
@@ -109,11 +109,6 @@ static int volume_import_exec(bContext *C, wmOperator *op)
BLI_path_rel(volume->filepath, BKE_main_blendfile_path(bmain));
}
- volume->is_sequence = (range->length > 1);
- volume->frame_duration = (volume->is_sequence) ? range->length : 0;
- volume->frame_start = 1;
- volume->frame_offset = (volume->is_sequence) ? range->offset - 1 : 0;
-
if (!BKE_volume_load(volume, bmain)) {
BKE_reportf(op->reports,
RPT_WARNING,
@@ -134,10 +129,19 @@ static int volume_import_exec(bContext *C, wmOperator *op)
continue;
}
+ /* Set sequence parameters after trying to load the first frame, for file validation we want
+ * to use a consistent frame rather than whatever corresponds to the current scene frame. */
+ volume->is_sequence = (range->length > 1);
+ volume->frame_duration = (volume->is_sequence) ? range->length : 0;
+ volume->frame_start = 1;
+ volume->frame_offset = (volume->is_sequence) ? range->offset - 1 : 0;
+
if (BKE_volume_is_y_up(volume)) {
object->rot[0] += M_PI_2;
}
+ BKE_volume_unload(volume);
+
imported = true;
}
BLI_freelistN(&ranges);
diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c
index 37845e8d74e..6922a03b12f 100644
--- a/source/blender/editors/physics/dynamicpaint_ops.c
+++ b/source/blender/editors/physics/dynamicpaint_ops.c
@@ -72,7 +72,7 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
DynamicPaintSurface *surface;
/* Make sure we're dealing with a canvas */
- pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint);
+ pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(cObject, eModifierType_DynamicPaint);
if (!pmd || !pmd->canvas) {
return OPERATOR_CANCELLED;
}
@@ -117,7 +117,7 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op))
int id = 0;
/* Make sure we're dealing with a canvas */
- pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint);
+ pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(obj_ctx, eModifierType_DynamicPaint);
if (!pmd || !pmd->canvas) {
return OPERATOR_CANCELLED;
}
@@ -162,7 +162,7 @@ static int type_toggle_exec(bContext *C, wmOperator *op)
Object *cObject = ED_object_context(C);
Scene *scene = CTX_data_scene(C);
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
cObject, eModifierType_DynamicPaint);
int type = RNA_enum_get(op->ptr, "type");
@@ -222,7 +222,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
DynamicPaintSurface *surface;
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
ob, eModifierType_DynamicPaint);
int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */
@@ -483,7 +483,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op)
/*
* Get modifier data
*/
- DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType(
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(
object_eval, eModifierType_DynamicPaint);
if (pmd == NULL) {
BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found");
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 8a40f65fc8a..ef5ed806c1e 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -135,10 +135,10 @@ bool PE_hair_poll(bContext *C)
bool PE_poll_view3d(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- return (PE_poll(C) && (sa && sa->spacetype == SPACE_VIEW3D) &&
+ return (PE_poll(C) && (area && area->spacetype == SPACE_VIEW3D) &&
(region && region->regiontype == RGN_TYPE_WINDOW));
}
@@ -849,7 +849,6 @@ static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selec
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
}
@@ -1229,7 +1228,6 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
}
@@ -1278,7 +1276,6 @@ static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
}
@@ -1353,7 +1350,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
@@ -2256,7 +2252,7 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
/************************ lasso select operator ************************/
-int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
+int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
@@ -2300,7 +2296,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -2319,7 +2316,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
const bool is_inside =
((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) &&
key_test_depth(&data, co, screen_co));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
@@ -2833,8 +2831,8 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
if (pe_x_mirror(ob)) {
/* mirror key tags */
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
- depsgraph, ob, &psmd->modifier);
+ ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)
+ BKE_modifier_get_evaluated(depsgraph, ob, &psmd->modifier);
LOOP_POINTS {
LOOP_TAGGED_KEYS {
@@ -3232,17 +3230,17 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata)
}
}
-static void toggle_particle_cursor(bContext *C, int enable)
+static void toggle_particle_cursor(Scene *scene, bool enable)
{
- ParticleEditSettings *pset = PE_settings(CTX_data_scene(C));
+ ParticleEditSettings *pset = PE_settings(scene);
if (pset->paintcursor && !enable) {
- WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
+ WM_paint_cursor_end(pset->paintcursor);
pset->paintcursor = NULL;
}
else if (enable) {
pset->paintcursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL);
+ SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL);
}
}
@@ -4084,7 +4082,6 @@ typedef struct BrushAddCountIterData {
short size;
float imat[4][4];
ParticleData *add_pars;
- int num_added;
} BrushAddCountIterData;
typedef struct BrushAddCountIterTLSData {
@@ -4113,7 +4110,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
dmy = size;
if (tls->rng == NULL) {
tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] +
- tls_v->thread_id);
+ BLI_task_parallel_thread_id(tls_v));
}
/* rejection sampling to get points in circle */
while (dmx * dmx + dmy * dmy > size2) {
@@ -4176,12 +4173,19 @@ static void brush_add_count_iter(void *__restrict iter_data_v,
}
}
-static void brush_add_count_iter_finalize(void *__restrict userdata_v,
- void *__restrict userdata_chunk_v)
+static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict join_v,
+ void *__restrict chunk_v)
+{
+ BrushAddCountIterTLSData *join = (BrushAddCountIterTLSData *)join_v;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
+ join->num_added += tls->num_added;
+}
+
+static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v),
+ void *__restrict chunk_v)
{
- BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
- BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
- iter_data->num_added += tls->num_added;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v;
if (tls->rng != NULL) {
BLI_rng_free(tls->rng);
}
@@ -4245,23 +4249,22 @@ static int brush_add(const bContext *C, PEData *data, short number)
iter_data.number = number;
iter_data.size = size;
iter_data.add_pars = add_pars;
- iter_data.num_added = 0;
copy_m4_m4(iter_data.imat, imat);
BrushAddCountIterTLSData tls = {NULL};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
settings.userdata_chunk = &tls;
settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
- settings.func_finalize = brush_add_count_iter_finalize;
+ settings.func_reduce = brush_add_count_iter_reduce;
+ settings.func_free = brush_add_count_iter_free;
BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
/* Convert add_parse to a dense array, where all new particles are in the
* beginning of the array.
*/
- n = iter_data.num_added;
+ n = tls.num_added;
for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
continue;
@@ -5124,7 +5127,8 @@ void PE_create_particle_edit(
int totpoint;
if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval,
+ psmd->modifier.name);
}
/* no psmd->dm happens in case particle system modifier is not enabled */
@@ -5247,12 +5251,9 @@ static bool particle_edit_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
- return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) ||
- modifiers_findByType(ob, eModifierType_Softbody));
+ return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) ||
+ BKE_modifiers_findby_type(ob, eModifierType_Softbody));
}
static void free_all_psys_edit(Object *object)
@@ -5267,10 +5268,60 @@ static void free_all_psys_edit(Object *object)
}
}
+void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ PTCacheEdit *edit;
+
+ ob->mode |= OB_MODE_PARTICLE_EDIT;
+
+ edit = PE_create_current(depsgraph, scene, ob);
+
+ /* Mesh may have changed since last entering editmode.
+ * note, this may have run before if the edit data was just created,
+ * so could avoid this and speed up a little. */
+ if (edit && edit->psys) {
+ /* Make sure pointer to the evaluated modifier data is up to date,
+ * with possible changes applied when object was outside of the
+ * edit mode. */
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(
+ object_eval, edit->psmd->modifier.name);
+ recalc_emitter_field(depsgraph, ob, edit->psys);
+ }
+
+ toggle_particle_cursor(scene, true);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
+}
+
+void ED_object_particle_edit_mode_enter(bContext *C)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
+}
+
+void ED_object_particle_edit_mode_exit_ex(Scene *scene, Object *ob)
+{
+ ob->mode &= ~OB_MODE_PARTICLE_EDIT;
+ toggle_particle_cursor(scene, false);
+ free_all_psys_edit(ob);
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+}
+
+void ED_object_particle_edit_mode_exit(bContext *C)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
+}
+
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
{
struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_PARTICLE_EDIT;
@@ -5283,37 +5334,13 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
}
if (!is_mode_set) {
- PTCacheEdit *edit;
-
- ob->mode |= mode_flag;
-
- edit = PE_create_current(depsgraph, scene, ob);
-
- /* Mesh may have changed since last entering editmode.
- * note, this may have run before if the edit data was just created,
- * so could avoid this and speed up a little. */
- if (edit && edit->psys) {
- /* Make sure pointer to the evaluated modifier data is up to date,
- * with possible changes applied when object was outside of the
- * edit mode. */
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(
- object_eval, edit->psmd->modifier.name);
- recalc_emitter_field(depsgraph, ob, edit->psys);
- }
-
- toggle_particle_cursor(C, 1);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ ED_object_particle_edit_mode_enter_ex(depsgraph, scene, ob);
}
else {
- ob->mode &= ~mode_flag;
- toggle_particle_cursor(C, 0);
- free_all_psys_edit(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ ED_object_particle_edit_mode_exit_ex(scene, ob);
}
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
-
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_toolsystem_update_from_context_view3d(C);
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 5b363bdca78..205c04f54a9 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -253,7 +253,7 @@ static void particle_undosys_step_decode(struct bContext *C,
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
/* TODO(campbell): undo_system: use low-level API to set mode. */
- ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
+ ED_object_mode_set_ex(C, OB_MODE_PARTICLE_EDIT, false, NULL);
BLI_assert(particle_undosys_poll(C));
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index f37a20bf43e..e75169a476b 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1064,7 +1064,7 @@ static void remove_particle_systems_from_object(Object *ob_to)
eModifierType_DynamicPaint,
eModifierType_Fluid)) {
BLI_remlink(&ob_to->modifiers, md);
- modifier_free(md);
+ BKE_modifier_free(md);
}
}
@@ -1138,13 +1138,13 @@ static bool copy_particle_systems_to_object(const bContext *C,
psys_unique_name(ob_to, psys, psys->name);
/* add a particle system modifier for each system */
- md = modifier_new(eModifierType_ParticleSystem);
+ md = BKE_modifier_new(eModifierType_ParticleSystem);
psmd = (ParticleSystemModifierData *)md;
/* push on top of the stack, no use trying to reproduce old stack order */
BLI_addtail(&ob_to->modifiers, md);
BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
- modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
+ BKE_modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
psmd->psys = psys;
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index eb808398254..8524870c15e 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -52,6 +52,7 @@
#include "DEG_depsgraph.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "PIL_time.h"
@@ -154,9 +155,9 @@ static bool fluid_initjob(
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size);
return false;
@@ -170,7 +171,7 @@ static bool fluid_initjob(
job->bmain = CTX_data_main(C);
job->scene = CTX_data_scene(C);
job->depsgraph = CTX_data_depsgraph_pointer(C);
- job->ob = CTX_data_active_object(C);
+ job->ob = ob;
job->mmd = mmd;
job->type = op->type->idname;
job->name = op->type->name;
@@ -185,13 +186,13 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
temp_dir[0] = '\0';
bool is_relative = false;
- const char *relbase = modifier_path_relbase(job->bmain, job->ob);
+ const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob);
/* We do not accept empty paths, they can end in random places silently, see T51176. */
if (mds->cache_directory[0] == '\0') {
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
+ BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
BKE_reportf(reports,
RPT_WARNING,
"Fluid: Empty cache path, reset to default '%s'",
@@ -209,7 +210,7 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports)
if (!dir_exists) {
char cache_name[64];
BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name);
- modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
+ BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name);
BKE_reportf(reports,
RPT_ERROR,
@@ -361,7 +362,7 @@ static void fluid_bake_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the bake */
@@ -376,7 +377,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update,
FluidDomainSettings *mds = job->mmd->domain;
char temp_dir[FILE_MAX];
- const char *relbase = modifier_path_relbase_from_global(job->ob);
+ const char *relbase = BKE_modifier_path_relbase_from_global(job->ob);
job->stop = stop;
job->do_update = do_update;
@@ -473,7 +474,7 @@ static void fluid_free_endjob(void *customdata)
RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start);
}
else {
- if (mds->error != NULL && mds->error[0] != '\0') {
+ if (mds->error[0] != '\0') {
WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error);
}
else { /* User canceled the free job */
@@ -616,13 +617,13 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
Scene *scene = CTX_data_scene(C);
/*
* Get modifier data
*/
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
return OPERATOR_CANCELLED;
@@ -679,12 +680,12 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op)
{
FluidModifierData *mmd = NULL;
FluidDomainSettings *mds;
- Object *ob = CTX_data_active_object(C);
+ Object *ob = ED_object_active_context(C);
/*
* Get modifier data
*/
- mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid);
+ mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid);
if (!mmd) {
BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 8a8fd703845..1db7bf5a766 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -112,7 +112,7 @@ typedef struct RenderJob {
ReportList *reports;
int orig_layer;
int last_layer;
- ScrArea *sa;
+ ScrArea *area;
ColorManagedViewSettings view_settings;
ColorManagedDisplaySettings display_settings;
bool supports_glsl_draw;
@@ -349,7 +349,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_SetReports(re, op->reports);
- BLI_threaded_malloc_begin();
if (is_animation) {
RE_RenderAnim(re,
mainp,
@@ -363,7 +362,6 @@ static int screen_render_exec(bContext *C, wmOperator *op)
else {
RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still);
}
- BLI_threaded_malloc_end();
RE_SetReports(re, NULL);
@@ -391,16 +389,14 @@ static void make_renderinfo_string(const RenderStats *rs,
char *str)
{
char info_time_str[32]; // used to be extern to header_info.c
- uintptr_t mem_in_use, mmap_in_use, peak_memory;
- float megs_used_memory, mmap_used_memory, megs_peak_memory;
+ uintptr_t mem_in_use, peak_memory;
+ float megs_used_memory, megs_peak_memory;
char *spos = str;
mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
peak_memory = MEM_get_peak_memory();
- megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0);
- mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0);
+ megs_used_memory = (mem_in_use) / (1024.0 * 1024.0);
megs_peak_memory = (peak_memory) / (1024.0 * 1024.0);
/* local view */
@@ -441,7 +437,7 @@ static void make_renderinfo_string(const RenderStats *rs,
}
}
else {
- if (rs->totvert || rs->totface || rs->tothalo || rs->totstrand || rs->totlamp) {
+ if (rs->totvert || rs->totface || rs->totlamp) {
spos += sprintf(spos, "| ");
}
@@ -451,38 +447,16 @@ static void make_renderinfo_string(const RenderStats *rs,
if (rs->totface) {
spos += sprintf(spos, TIP_("Fa:%d "), rs->totface);
}
- if (rs->tothalo) {
- spos += sprintf(spos, TIP_("Ha:%d "), rs->tothalo);
- }
- if (rs->totstrand) {
- spos += sprintf(spos, TIP_("St:%d "), rs->totstrand);
- }
if (rs->totlamp) {
spos += sprintf(spos, TIP_("Li:%d "), rs->totlamp);
}
if (rs->mem_peak == 0.0f) {
- spos += sprintf(spos,
- TIP_("| Mem:%.2fM (%.2fM, Peak %.2fM) "),
- megs_used_memory,
- mmap_used_memory,
- megs_peak_memory);
+ spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory);
}
else {
spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak);
}
-
- if (rs->curfield) {
- spos += sprintf(spos, TIP_("Field %d "), rs->curfield);
- }
- if (rs->curblur) {
- spos += sprintf(spos, TIP_("Blur %d "), rs->curblur);
- }
- }
-
- /* full sample */
- if (rs->curfsa) {
- spos += sprintf(spos, TIP_("| Full Sample %d "), rs->curfsa);
}
/* extra info */
@@ -543,24 +517,24 @@ static void render_progress_update(void *rjv, float progress)
static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser)
{
wmWindowManager *wm;
- ScrArea *first_sa = NULL, *matched_sa = NULL;
+ ScrArea *first_area = NULL, *matched_area = NULL;
/* image window, compo node users */
- for (wm = rj->main->wm.first; wm && matched_sa == NULL; wm = wm->id.next) { /* only 1 wm */
+ for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */
wmWindow *win;
- for (win = wm->windows.first; win && matched_sa == NULL; win = win->next) {
+ for (win = wm->windows.first; win && matched_area == NULL; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
- // sa->spacedata might be empty when toggling fullscreen mode.
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
+ // area->spacedata might be empty when toggling fullscreen mode.
if (sima != NULL && sima->image == rj->image) {
- if (first_sa == NULL) {
- first_sa = sa;
+ if (first_area == NULL) {
+ first_area = area;
}
- if (sa == rj->sa) {
- matched_sa = sa;
+ if (area == rj->area) {
+ matched_area = area;
break;
}
}
@@ -569,12 +543,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr,
}
}
- if (matched_sa == NULL) {
- matched_sa = first_sa;
+ if (matched_area == NULL) {
+ matched_area = first_area;
}
- if (matched_sa) {
- SpaceImage *sima = matched_sa->spacedata.first;
+ if (matched_area) {
+ SpaceImage *sima = matched_area->spacedata.first;
RenderResult *main_rr = RE_AcquireResultRead(rj->re);
/* TODO(sergey): is there faster way to get the layer index? */
@@ -689,10 +663,10 @@ static void render_image_restore_layer(RenderJob *rj)
for (win = wm->windows.first; win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa == rj->sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area == rj->area) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (RE_HasSingleLayer(rj->re)) {
/* For single layer renders keep the active layer
@@ -748,7 +722,7 @@ static void render_endjob(void *rjv)
WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene);
}
- if (rj->sa) {
+ if (rj->area) {
render_image_restore_layer(rj);
}
@@ -887,7 +861,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene)
/* Go over all the visible objects. */
for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
for (base = view_layer->object_bases.first; base; base = base->next) {
@@ -920,7 +894,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL;
struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL;
const char *name;
- ScrArea *sa;
+ ScrArea *area;
/* Cannot do render if there is not this function. */
if (re_type->render == NULL) {
@@ -945,6 +919,12 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
return OPERATOR_CANCELLED;
}
+ /* Reports are done inside check function, and it will return false if there are other strips to
+ * render. */
+ if ((scene->r.scemode & R_DOSEQ) && BKE_sequencer_check_scene_recursion(scene, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+
/* stop all running jobs, except screen one. currently previews frustrate Render */
WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C));
@@ -970,7 +950,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
// store spare
/* ensure at least 1 area shows result */
- sa = render_view_open(C, event->x, event->y, op->reports);
+ area = render_view_open(C, event->x, event->y, op->reports);
/* job custom data */
rj = MEM_callocN(sizeof(RenderJob), "render job");
@@ -991,14 +971,14 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even
rj->reports = op->reports;
rj->orig_layer = 0;
rj->last_layer = 0;
- rj->sa = sa;
+ rj->area = area;
rj->supports_glsl_draw = IMB_colormanagement_support_glsl_draw(&scene->view_settings);
BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings);
- if (sa) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area) {
+ SpaceImage *sima = area->spacedata.first;
rj->orig_layer = sima->iuser.layer;
}
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 442f700ad6f..2861e851282 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -43,7 +43,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_camera.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
@@ -144,14 +144,13 @@ typedef struct OGLRender {
wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/
void **movie_ctx_arr;
- TaskScheduler *task_scheduler;
TaskPool *task_pool;
bool pool_ok;
bool is_animation;
eImageFormatDepth color_depth;
SpinLock reports_lock;
- unsigned int num_scheduled_frames;
+ uint num_scheduled_frames;
ThreadMutex task_mutex;
ThreadCondition task_condition;
@@ -296,7 +295,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
const short view_context = (v3d != NULL);
bool draw_sky = (scene->r.alphamode == R_ADDSKY);
float *rectf = NULL;
- unsigned char *rect = NULL;
+ uchar *rect = NULL;
const char *viewname = RE_GetActiveRenderView(oglrender->re);
ImBuf *ibuf_result = NULL;
@@ -334,9 +333,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
if (gpd) {
int i;
- unsigned char *gp_rect;
- unsigned char *render_rect =
- (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
+ uchar *gp_rect;
+ uchar *render_rect = (uchar *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32;
DRW_opengl_context_enable();
GPU_offscreen_bind(oglrender->ofs, true);
@@ -352,7 +350,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ);
G.f &= ~G_FLAG_RENDER_VIEWPORT;
- gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
+ gp_rect = MEM_mallocN(sizex * sizey * sizeof(uchar) * 4, "offscreen rect");
GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
for (i = 0; i < sizex * sizey * 4; i += 4) {
@@ -414,7 +412,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R
rectf = ibuf_view->rect_float;
}
else {
- rect = (unsigned char *)ibuf_view->rect;
+ rect = (uchar *)ibuf_view->rect;
}
}
else {
@@ -496,7 +494,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender)
scene,
oglrender->sizex,
oglrender->sizey,
- 100.0f,
+ 100,
false,
&context);
@@ -631,6 +629,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
case ID_HA: /* Hair */
case ID_PT: /* PointCloud */
case ID_VO: /* Volume */
+ case ID_SIM: /* Simulation */
break;
/* Blacklist: */
@@ -856,21 +855,16 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
gather_frames_to_render(C, oglrender);
}
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
if (BKE_imtype_is_movie(scene->r.im_format.imtype)) {
- task_scheduler = BLI_task_scheduler_create(1);
- oglrender->task_scheduler = task_scheduler;
- oglrender->task_pool = BLI_task_pool_create_background(task_scheduler, oglrender);
+ oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW);
}
else {
- oglrender->task_scheduler = NULL;
- oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender);
+ oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW);
}
oglrender->pool_ok = true;
BLI_spin_init(&oglrender->reports_lock);
}
else {
- oglrender->task_scheduler = NULL;
oglrender->task_pool = NULL;
}
oglrender->num_scheduled_frames = 0;
@@ -909,10 +903,6 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender)
}
BLI_task_pool_work_and_wait(oglrender->task_pool);
BLI_task_pool_free(oglrender->task_pool);
- /* Depending on various things we might or might not use global scheduler. */
- if (oglrender->task_scheduler != NULL) {
- BLI_task_scheduler_free(oglrender->task_scheduler);
- }
BLI_spin_end(&oglrender->reports_lock);
}
BLI_mutex_end(&oglrender->task_mutex);
@@ -1032,9 +1022,9 @@ typedef struct WriteTaskData {
Scene tmp_scene;
} WriteTaskData;
-static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id))
+static void write_result_func(TaskPool *__restrict pool, void *task_data_v)
{
- OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool);
+ OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool);
WriteTaskData *task_data = (WriteTaskData *)task_data_v;
Scene *scene = &task_data->tmp_scene;
RenderResult *rr = task_data->rr;
@@ -1124,7 +1114,7 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr)
BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex);
}
BLI_mutex_unlock(&oglrender->task_mutex);
- BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL);
return true;
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 1427c6ed500..0432057bb47 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -167,7 +167,7 @@ typedef struct ShaderPreview {
float color[4];
int sizex, sizey;
- unsigned int *pr_rect;
+ uint *pr_rect;
int pr_method;
bool own_id_copy;
@@ -178,7 +178,7 @@ typedef struct ShaderPreview {
typedef struct IconPreviewSize {
struct IconPreviewSize *next, *prev;
int sizex, sizey;
- unsigned int *rect;
+ uint *rect;
} IconPreviewSize;
typedef struct IconPreview {
@@ -304,7 +304,7 @@ static void set_preview_visibility(Scene *scene,
}
/* Hide floor for icon renders. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (STREQ(base->object->id.name + 2, "Floor")) {
if (pr_method == PR_ICON_RENDER) {
base->object->restrictflag |= OB_RESTRICT_RENDER;
@@ -463,7 +463,7 @@ static Scene *preview_prepare_scene(
sce->display.render_aa = SCE_DISPLAY_AA_OFF;
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.name[2] == 'p') {
/* copy over object color, in case material uses it */
copy_v4_v4(base->object->color, sp->color);
@@ -522,7 +522,7 @@ static Scene *preview_prepare_scene(
sce->world->horb = 0.0f;
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.name[2] == 'p') {
if (base->object->type == OB_LAMP) {
base->object->data = la;
@@ -566,7 +566,7 @@ static Scene *preview_prepare_scene(
/* new UI convention: draw is in pixel space already. */
/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
-static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect, rcti *newrect)
+static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
RenderView *rv;
@@ -578,10 +578,10 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
bool ok = false;
if (!split || first) {
- sprintf(name, "Preview %p", (void *)sa);
+ sprintf(name, "Preview %p", (void *)area);
}
else {
- sprintf(name, "SecondPreview %p", (void *)sa);
+ sprintf(name, "SecondPreview %p", (void *)area);
}
if (split) {
@@ -621,14 +621,14 @@ static bool ed_preview_draw_rect(ScrArea *sa, int split, int first, rcti *rect,
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) {
- unsigned char *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
- "ed_preview_draw_rect");
+ uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int),
+ "ed_preview_draw_rect");
float fx = rect->xmin + offx;
float fy = rect->ymin;
/* material preview only needs monoscopy (view 0) */
if (re) {
- RE_AcquiredResultGet32(re, &rres, (unsigned int *)rect_byte, 0);
+ RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0);
}
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
@@ -661,12 +661,12 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
{
if (idp) {
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ID *id = (ID *)idp;
ID *parent = (ID *)parentp;
MTex *slot = (MTex *)slotp;
SpaceProperties *sbuts = CTX_wm_space_properties(C);
- ShaderPreview *sp = WM_jobs_customdata(wm, sa);
+ ShaderPreview *sp = WM_jobs_customdata(wm, area);
rcti newrect;
int ok;
int newx = BLI_rcti_size_x(rect);
@@ -678,11 +678,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
newrect.ymax = rect->ymin;
if (parent) {
- ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect);
- ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect);
+ ok = ed_preview_draw_rect(area, 1, 1, rect, &newrect);
+ ok &= ed_preview_draw_rect(area, 1, 0, rect, &newrect);
}
else {
- ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect);
+ ok = ed_preview_draw_rect(area, 0, 0, rect, &newrect);
}
if (ok) {
@@ -693,12 +693,12 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
* if no render result was found and no preview render job is running,
* or if the job is running and the size of preview changed */
if ((sbuts != NULL && sbuts->preview) ||
- (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) ||
+ (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) ||
(sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) {
if (sbuts != NULL) {
sbuts->preview = 0;
}
- ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER);
+ ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER);
}
}
}
@@ -1014,10 +1014,10 @@ static void shader_preview_free(void *customdata)
/* ************************* icon preview ********************** */
-static void icon_copy_rect(ImBuf *ibuf, unsigned int w, unsigned int h, unsigned int *rect)
+static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect)
{
struct ImBuf *ima;
- unsigned int *drect, *srect;
+ uint *drect, *srect;
float scaledx, scaledy;
short ex, ey, dx, dy;
@@ -1144,7 +1144,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat
br->icon_imbuf = get_brush_icon(br);
- memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(unsigned int));
+ memset(sp->pr_rect, 0x88, sp->sizex * sp->sizey * sizeof(uint));
if (!(br->icon_imbuf) || !(br->icon_imbuf->rect)) {
return;
@@ -1193,7 +1193,7 @@ static void common_preview_startjob(void *customdata,
/* exported functions */
-static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex, int sizey)
+static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey)
{
IconPreviewSize *cur_size = ip->sizes.first, *new_size;
@@ -1324,8 +1324,7 @@ static void icon_preview_free(void *customdata)
MEM_freeN(ip);
}
-void ED_preview_icon_render(
- Main *bmain, Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
+void ED_preview_icon_render(Main *bmain, Scene *scene, ID *id, uint *rect, int sizex, int sizey)
{
IconPreview ip = {NULL};
short stop = false, update = false;
@@ -1348,13 +1347,8 @@ void ED_preview_icon_render(
BLI_freelistN(&ip.sizes);
}
-void ED_preview_icon_job(const bContext *C,
- void *owner,
- ID *id,
- unsigned int *rect,
- int sizex,
- int sizey,
- const bool delay)
+void ED_preview_icon_job(
+ const bContext *C, void *owner, ID *id, uint *rect, int sizex, int sizey, const bool delay)
{
wmJob *wm_job;
IconPreview *ip, *old_ip;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index e1fa4caafbd..49ab2c485b1 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -42,6 +42,7 @@
#include "BLT_translation.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -100,15 +101,15 @@
*/
static Object **object_array_for_shading(bContext *C, uint *r_objects_len)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceProperties *sbuts = NULL;
View3D *v3d = NULL;
- if (sa != NULL) {
- if (sa->spacetype == SPACE_PROPERTIES) {
- sbuts = sa->spacedata.first;
+ if (area != NULL) {
+ if (area->spacetype == SPACE_PROPERTIES) {
+ sbuts = area->spacedata.first;
}
- else if (sa->spacetype == SPACE_VIEW3D) {
- v3d = sa->spacedata.first;
+ else if (area->spacetype == SPACE_VIEW3D) {
+ v3d = area->spacedata.first;
}
}
@@ -506,7 +507,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- unsigned int *slot_remap;
+ uint *slot_remap;
int index_pair[2];
int dir = RNA_enum_get(op->ptr, "direction");
@@ -531,7 +532,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- slot_remap = MEM_mallocN(sizeof(unsigned int) * ob->totcol, __func__);
+ slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__);
range_vn_u(slot_remap, ob->totcol, 0);
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index d2bb53de06f..10f69f3fe9d 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -105,18 +105,18 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
wm = bmain->wm.first;
for (win = wm->windows.first; win; win = win->next) {
- bScreen *sc = WM_window_get_active_screen(win);
- ScrArea *sa;
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *area;
ARegion *region;
CTX_wm_window_set(C, win);
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype != SPACE_VIEW3D) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype != SPACE_VIEW3D) {
continue;
}
- View3D *v3d = sa->spacedata.first;
- for (region = sa->regionbase.first; region; region = region->next) {
+ View3D *v3d = area->spacedata.first;
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW) {
continue;
}
@@ -127,8 +127,8 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
* time of the last update) */
if (engine && (updated || (engine->flag & RE_ENGINE_DO_UPDATE))) {
- CTX_wm_screen_set(C, sc);
- CTX_wm_area_set(C, sa);
+ CTX_wm_screen_set(C, screen);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
engine->flag &= ~RE_ENGINE_DO_UPDATE;
@@ -146,7 +146,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
.scene = scene,
.view_layer = view_layer,
.region = region,
- .v3d = (View3D *)sa->spacedata.first,
+ .v3d = (View3D *)area->spacedata.first,
.engine_type = engine_type,
}));
}
@@ -160,17 +160,17 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int update
recursive_check = false;
}
-void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
+void ED_render_engine_area_exit(Main *bmain, ScrArea *area)
{
/* clear all render engines in this area */
ARegion *region;
wmWindowManager *wm = bmain->wm.first;
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return;
}
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) {
continue;
}
@@ -181,9 +181,9 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *sa)
void ED_render_engine_changed(Main *bmain)
{
/* on changing the render engine type, clear all running render engines */
- for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_render_engine_area_exit(bmain, area);
}
}
RE_FreePersistentData();
@@ -204,10 +204,10 @@ void ED_render_engine_changed(Main *bmain)
}
}
-void ED_render_view_layer_changed(Main *bmain, bScreen *sc)
+void ED_render_view_layer_changed(Main *bmain, bScreen *screen)
{
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- ED_render_engine_area_exit(bmain, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_render_engine_area_exit(bmain, area);
}
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index a93ea343229..a9c855b14b0 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -56,23 +56,23 @@
/* would use BKE_screen_find_big_area(...) but this is too specific */
static ScrArea *biggest_non_image_area(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa, *big = NULL;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area, *big = NULL;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->winx > 30 && sa->winy > 30) {
- size = sa->winx * sa->winy;
- if (!sa->full && sa->spacetype == SPACE_PROPERTIES) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->winx > 30 && area->winy > 30) {
+ size = area->winx * area->winy;
+ if (!area->full && area->spacetype == SPACE_PROPERTIES) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
- big = sa;
+ big = area;
}
}
- else if (sa->spacetype != SPACE_IMAGE && size > maxsize) {
+ else if (area->spacetype != SPACE_IMAGE && size > maxsize) {
maxsize = size;
- big = sa;
+ big = area;
foundwin = 1;
}
}
@@ -84,7 +84,7 @@ static ScrArea *biggest_non_image_area(bContext *C)
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
SpaceImage *sima;
/* find an imagewindow showing render result */
@@ -92,40 +92,40 @@ static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow *
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ sima = area->spacedata.first;
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
}
}
}
- if (sa) {
+ if (area) {
break;
}
}
}
- return sa;
+ return area;
}
static ScrArea *find_area_image_empty(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa;
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area;
SpaceImage *sima;
/* find an imagewindow showing render result */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ sima = area->spacedata.first;
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
}
}
- return sa;
+ return area;
}
/********************** open image editor for render *************************/
@@ -136,7 +136,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
wmWindow *win = NULL;
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
SpaceImage *sima;
bool area_was_image = false;
@@ -163,34 +163,34 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
return NULL;
}
- sa = CTX_wm_area(C);
- if (BLI_listbase_is_single(&sa->spacedata) == false) {
- sima = sa->spacedata.first;
+ area = CTX_wm_area(C);
+ if (BLI_listbase_is_single(&area->spacedata) == false) {
+ sima = area->spacedata.first;
sima->flag |= SI_PREVSPACE;
}
}
else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
* unset the area, so that the fullscreen area is just changed later */
- if (sa && sa->full) {
- sa = NULL;
+ if (area && area->full) {
+ area = NULL;
}
else {
- if (sa && sa->spacetype == SPACE_IMAGE) {
+ if (area && area->spacetype == SPACE_IMAGE) {
area_was_image = true;
}
/* this function returns with changed context */
- sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ area = ED_screen_full_newspace(C, area, SPACE_IMAGE);
}
}
- if (!sa) {
- sa = find_area_showing_r_result(C, scene, &win);
- if (sa == NULL) {
- sa = find_area_image_empty(C);
+ if (!area) {
+ area = find_area_showing_r_result(C, scene, &win);
+ if (area == NULL) {
+ area = find_area_image_empty(C);
}
/* if area found in other window, we make that one show in front */
@@ -198,27 +198,27 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
wm_window_raise(win);
}
- if (sa == NULL) {
+ if (area == NULL) {
/* find largest open non-image area */
- sa = biggest_non_image_area(C);
- if (sa) {
- ED_area_newspace(C, sa, SPACE_IMAGE, true);
- sima = sa->spacedata.first;
+ area = biggest_non_image_area(C);
+ if (area) {
+ ED_area_newspace(C, area, SPACE_IMAGE, true);
+ sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- if (sa->full) {
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ if (area->full) {
+ area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
}
else {
/* use any area of decent size */
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
- if (sa->spacetype != SPACE_IMAGE) {
- // XXX newspace(sa, SPACE_IMAGE);
- sima = sa->spacedata.first;
+ area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
+ if (area->spacetype != SPACE_IMAGE) {
+ // XXX newspace(area, SPACE_IMAGE);
+ sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
@@ -226,7 +226,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
}
- sima = sa->spacedata.first;
+ sima = area->spacedata.first;
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
@@ -234,7 +234,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* If we're rendering to full screen, set appropriate hints on image editor
* so it can restore properly on pressing escape. */
- if (sa->full) {
+ if (area->full) {
sima->flag |= SI_FULLWINDOW;
/* Tell the image editor to revert to previous space in space list on close
@@ -253,7 +253,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
old_sl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
}
- return sa;
+ return area;
}
/*************************** cancel render viewer **********************/
@@ -261,11 +261,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceImage *sima = area->spacedata.first;
/* ensure image editor fullscreen and area fullscreen states are in sync */
- if ((sima->flag & SI_FULLWINDOW) && !sa->full) {
+ if ((sima->flag & SI_FULLWINDOW) && !area->full) {
sima->flag &= ~SI_FULLWINDOW;
}
@@ -275,17 +275,17 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
return OPERATOR_FINISHED;
}
else if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
+ ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
return OPERATOR_FINISHED;
}
else if (WM_window_is_temp_screen(win)) {
@@ -320,14 +320,14 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
else {
wmWindow *win, *winshow;
- ScrArea *sa = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
+ ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
- const bScreen *sc = WM_window_get_active_screen(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
- ((ScrArea *)sc->areabase.first)->spacetype == SPACE_IMAGE) ||
+ ((ScrArea *)screen->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur)) {
wm_window_raise(win);
return OPERATOR_FINISHED;
@@ -335,20 +335,20 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
/* determine if render already shows */
- if (sa) {
+ if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
}
}
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 114cb54636a..d78b1532a39 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -99,7 +99,7 @@ bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene)
return false;
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->parent != NULL) { /* We only care about main windows here... */
continue;
}
@@ -175,7 +175,7 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep
/* Remove from windows. */
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->scene == scene && STREQ(win->view_layer_name, layer->name)) {
ViewLayer *first_layer = BKE_view_layer_default_view(scene);
STRNCPY(win->view_layer_name, first_layer->name);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index ec875cfae2c..d403cdbc315 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -146,7 +146,7 @@ void ED_region_pixelspace(ARegion *region)
/* only exported for WM */
void ED_region_do_listen(
- wmWindow *win, ScrArea *sa, ARegion *region, wmNotifier *note, const Scene *scene)
+ wmWindow *win, ScrArea *area, ARegion *region, wmNotifier *note, const Scene *scene)
{
/* generic notes first */
switch (note->category) {
@@ -161,27 +161,27 @@ void ED_region_do_listen(
}
if (region->type && region->type->listener) {
- region->type->listener(win, sa, region, note, scene);
+ region->type->listener(win, area, region, note, scene);
}
}
/* only exported for WM */
-void ED_area_do_listen(wmWindow *win, ScrArea *sa, wmNotifier *note, Scene *scene)
+void ED_area_do_listen(wmWindow *win, ScrArea *area, wmNotifier *note, Scene *scene)
{
/* no generic notes? */
- if (sa->type && sa->type->listener) {
- sa->type->listener(win, sa, note, scene);
+ if (area->type && area->type->listener) {
+ area->type->listener(win, area, note, scene);
}
}
/* only exported for WM */
-void ED_area_do_refresh(bContext *C, ScrArea *sa)
+void ED_area_do_refresh(bContext *C, ScrArea *area)
{
/* no generic notes? */
- if (sa->type && sa->type->refresh) {
- sa->type->refresh(C, sa);
+ if (area->type && area->type->refresh) {
+ area->type->refresh(C, area);
}
- sa->do_refresh = false;
+ area->do_refresh = false;
}
/**
@@ -249,7 +249,9 @@ 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(true);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* 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);
immBegin(GPU_PRIM_TRI_FAN, 6);
@@ -267,7 +269,7 @@ static void draw_azone_arrow(float x1, float y1, float x2, float y2, AZEdge edge
GPU_blend(false);
}
-static void region_draw_azone_tab_arrow(AZone *az)
+static void region_draw_azone_tab_arrow(ScrArea *area, ARegion *region, AZone *az)
{
GPU_blend(true);
@@ -287,23 +289,25 @@ static void region_draw_azone_tab_arrow(AZone *az)
break;
}
- float color[4] = {0.05f, 0.05f, 0.05f, 0.4f};
+ /* Workaround for different color spaces between normal areas and the ones using GPUViewports. */
+ float alpha = WM_region_use_viewport(area, region) ? 0.6f : 0.4f;
+ float color[4] = {0.05f, 0.05f, 0.05f, alpha};
UI_draw_roundbox_aa(
true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color);
draw_azone_arrow((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, az->edge);
}
-static void area_azone_tag_update(ScrArea *sa)
+static void area_azone_tag_update(ScrArea *area)
{
- sa->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag |= AREA_FLAG_ACTIONZONES_UPDATE;
}
-static void region_draw_azones(ScrArea *sa, ARegion *region)
+static void region_draw_azones(ScrArea *area, ARegion *region)
{
AZone *az;
- if (!sa) {
+ if (!area) {
return;
}
@@ -315,7 +319,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
GPU_matrix_push();
GPU_matrix_translate_2f(-region->winrct.xmin, -region->winrct.ymin);
- for (az = sa->actionzones.first; az; az = az->next) {
+ for (az = area->actionzones.first; az; az = az->next) {
/* test if action zone is over this region */
rcti azrct;
BLI_rcti_init(&azrct, az->x1, az->x2, az->y1, az->y2);
@@ -328,7 +332,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
if (az->region) {
/* only display tab or icons when the region is hidden */
if (az->region->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- region_draw_azone_tab_arrow(az);
+ region_draw_azone_tab_arrow(area, region, az);
}
}
}
@@ -339,7 +343,7 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
}
}
if (!IS_EQF(az->alpha, 0.0f) && ELEM(az->type, AZONE_FULLSCREEN, AZONE_REGION_SCROLL)) {
- area_azone_tag_update(sa);
+ area_azone_tag_update(area);
}
}
@@ -348,9 +352,9 @@ static void region_draw_azones(ScrArea *sa, ARegion *region)
GPU_blend(false);
}
-static void region_draw_status_text(ScrArea *sa, ARegion *region)
+static void region_draw_status_text(ScrArea *area, ARegion *region)
{
- bool overlap = ED_region_is_overlap(sa->spacetype, region->regiontype);
+ bool overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
if (overlap) {
GPU_clear_color(0.0, 0.0, 0.0, 0.0);
@@ -421,8 +425,8 @@ void ED_area_do_msg_notify_tag_refresh(
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
{
- ScrArea *sa = msg_val->user_data;
- ED_area_tag_refresh(sa);
+ ScrArea *area = msg_val->user_data;
+ ED_area_tag_refresh(area);
}
void ED_area_do_mgs_subscribe_for_tool_header(
@@ -431,7 +435,7 @@ void ED_area_do_mgs_subscribe_for_tool_header(
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -451,7 +455,7 @@ void ED_area_do_mgs_subscribe_for_tool_ui(
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -483,20 +487,20 @@ static bool area_is_pseudo_minimized(const ScrArea *area)
void ED_region_do_layout(bContext *C, ARegion *region)
{
/* This is optional, only needed for dynamically sized regions. */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegionType *at = region->type;
if (!at->layout) {
return;
}
- if (at->do_lock || (sa && area_is_pseudo_minimized(sa))) {
+ if (at->do_lock || (area && area_is_pseudo_minimized(area))) {
return;
}
region->do_draw |= RGN_DRAWING;
- UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ UI_SetTheme(area ? area->spacetype : 0, at->regionid);
at->layout(C, region);
}
@@ -504,7 +508,7 @@ void ED_region_do_layout(bContext *C, ARegion *region)
void ED_region_do_draw(bContext *C, ARegion *region)
{
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegionType *at = region->type;
/* see BKE_spacedata_draw_locks() */
@@ -519,16 +523,16 @@ void ED_region_do_draw(bContext *C, ARegion *region)
wmOrtho2_region_pixelspace(region);
- UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ UI_SetTheme(area ? area->spacetype : 0, at->regionid);
- if (sa && area_is_pseudo_minimized(sa)) {
+ if (area && area_is_pseudo_minimized(area)) {
UI_ThemeClearColor(TH_EDITOR_OUTLINE);
glClear(GL_COLOR_BUFFER_BIT);
return;
}
/* optional header info instead? */
else if (region->headerstr) {
- region_draw_status_text(sa, region);
+ region_draw_status_text(area, region);
}
else if (at->draw) {
at->draw(C, region);
@@ -540,7 +544,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_PIXEL);
- region_draw_azones(sa, region);
+ region_draw_azones(area, region);
/* for debugging unneeded area redraws and partial redraw */
if (G.debug_value == 888) {
@@ -562,11 +566,11 @@ void ED_region_do_draw(bContext *C, ARegion *region)
UI_blocklist_free_inactive(C, &region->uiblocks);
- if (sa) {
+ if (area) {
const bScreen *screen = WM_window_get_active_screen(win);
/* Only region emboss for top-bar */
- if ((screen->state != SCREENFULL) && ED_area_is_global(sa)) {
+ if ((screen->state != SCREENFULL) && ED_area_is_global(area)) {
region_draw_emboss(region, &region->winrct, (REGION_EMBOSS_LEFT | REGION_EMBOSS_RIGHT));
}
else if ((region->regiontype == RGN_TYPE_WINDOW) && (region->alignment == RGN_ALIGN_QSPLIT)) {
@@ -604,7 +608,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
*/
if (ELEM(
region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) {
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr);
@@ -618,7 +622,7 @@ void ED_region_do_draw(bContext *C, ARegion *region)
WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__);
}
- ED_region_message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ ED_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
}
@@ -705,34 +709,34 @@ void ED_region_tag_redraw_partial(ARegion *region, const rcti *rct, bool rebuild
}
}
-void ED_area_tag_redraw(ScrArea *sa)
+void ED_area_tag_redraw(ScrArea *area)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw(region);
}
}
}
-void ED_area_tag_redraw_no_rebuild(ScrArea *sa)
+void ED_area_tag_redraw_no_rebuild(ScrArea *area)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw_no_rebuild(region);
}
}
}
-void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
+void ED_area_tag_redraw_regiontype(ScrArea *area, int regiontype)
{
ARegion *region;
- if (sa) {
- for (region = sa->regionbase.first; region; region = region->next) {
+ if (area) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == regiontype) {
ED_region_tag_redraw(region);
}
@@ -740,26 +744,26 @@ void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
}
}
-void ED_area_tag_refresh(ScrArea *sa)
+void ED_area_tag_refresh(ScrArea *area)
{
- if (sa) {
- sa->do_refresh = true;
+ if (area) {
+ area->do_refresh = true;
}
}
/* *************************************************************** */
/* use NULL to disable it */
-void ED_area_status_text(ScrArea *sa, const char *str)
+void ED_area_status_text(ScrArea *area, const char *str)
{
ARegion *region;
/* happens when running transform operators in background mode */
- if (sa == NULL) {
+ if (area == NULL) {
return;
}
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_HEADER) {
if (str) {
if (region->headerstr == NULL) {
@@ -799,9 +803,9 @@ void ED_workspace_status_text(bContext *C, const char *str)
}
/* Redraw status bar. */
- for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_STATUSBAR) {
- ED_area_tag_redraw(sa);
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
+ if (area->spacetype == SPACE_STATUSBAR) {
+ ED_area_tag_redraw(area);
break;
}
}
@@ -809,12 +813,12 @@ void ED_workspace_status_text(bContext *C, const char *str)
/* ************************************************************ */
-static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *sa)
+static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *area)
{
AZone *az;
/* reinitialize entirely, regions and fullscreen add azones too */
- BLI_freelistN(&sa->actionzones);
+ BLI_freelistN(&area->actionzones);
if (screen->state != SCREENNORMAL) {
return;
@@ -824,7 +828,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
return;
}
- if (ED_area_is_global(sa)) {
+ if (ED_area_is_global(area)) {
return;
}
@@ -834,25 +838,25 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
const float coords[4][4] = {
/* Bottom-left. */
- {sa->totrct.xmin - U.pixelsize,
- sa->totrct.ymin - U.pixelsize,
- sa->totrct.xmin + AZONESPOTW,
- sa->totrct.ymin + AZONESPOTH},
+ {area->totrct.xmin - U.pixelsize,
+ area->totrct.ymin - U.pixelsize,
+ area->totrct.xmin + AZONESPOTW,
+ area->totrct.ymin + AZONESPOTH},
/* Bottom-right. */
- {sa->totrct.xmax - AZONESPOTW,
- sa->totrct.ymin - U.pixelsize,
- sa->totrct.xmax + U.pixelsize,
- sa->totrct.ymin + AZONESPOTH},
+ {area->totrct.xmax - AZONESPOTW,
+ area->totrct.ymin - U.pixelsize,
+ area->totrct.xmax + U.pixelsize,
+ area->totrct.ymin + AZONESPOTH},
/* Top-left. */
- {sa->totrct.xmin - U.pixelsize,
- sa->totrct.ymax - AZONESPOTH,
- sa->totrct.xmin + AZONESPOTW,
- sa->totrct.ymax + U.pixelsize},
+ {area->totrct.xmin - U.pixelsize,
+ area->totrct.ymax - AZONESPOTH,
+ area->totrct.xmin + AZONESPOTW,
+ area->totrct.ymax + U.pixelsize},
/* Top-right. */
- {sa->totrct.xmax - AZONESPOTW,
- sa->totrct.ymax - AZONESPOTH,
- sa->totrct.xmax + U.pixelsize,
- sa->totrct.ymax + U.pixelsize},
+ {area->totrct.xmax - AZONESPOTW,
+ area->totrct.ymax - AZONESPOTH,
+ area->totrct.xmax + U.pixelsize,
+ area->totrct.ymax + U.pixelsize},
};
for (int i = 0; i < 4; i++) {
@@ -869,7 +873,7 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
/* set area action zones */
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_AREA;
az->x1 = coords[i][0];
az->y1 = coords[i][1];
@@ -879,16 +883,16 @@ static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea
}
}
-static void fullscreen_azone_initialize(ScrArea *sa, ARegion *region)
+static void fullscreen_azone_initialize(ScrArea *area, ARegion *region)
{
AZone *az;
- if (ED_area_is_global(sa) || (region->regiontype != RGN_TYPE_WINDOW)) {
+ if (ED_area_is_global(area) || (region->regiontype != RGN_TYPE_WINDOW)) {
return;
}
az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_FULLSCREEN;
az->region = region;
az->alpha = 0.0f;
@@ -942,7 +946,7 @@ static void region_azone_edge(AZone *az, ARegion *region)
}
/* region already made zero sized, in shape of edge */
-static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
+static void region_azone_tab_plus(ScrArea *area, AZone *az, ARegion *region)
{
AZone *azt;
int tot = 0, add;
@@ -952,7 +956,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
const float tab_size_x = 0.7f * U.widget_unit;
const float tab_size_y = 0.4f * U.widget_unit;
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
+ for (azt = area->actionzones.first; azt; azt = azt->next) {
if (azt->edge == az->edge) {
tot++;
}
@@ -960,7 +964,7 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *region)
switch (az->edge) {
case AE_TOP_TO_BOTTOMRIGHT:
- add = (region->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
+ add = (region->winrct.ymax == area->totrct.ymin) ? 1 : 0;
az->x1 = region->winrct.xmax - ((edge_offset + 1.0f) * tab_size_x);
az->y1 = region->winrct.ymax - add;
az->x2 = region->winrct.xmax - (edge_offset * tab_size_x);
@@ -1003,7 +1007,7 @@ static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscre
return true;
}
-static void region_azone_edge_initialize(ScrArea *sa,
+static void region_azone_edge_initialize(ScrArea *area,
ARegion *region,
AZEdge edge,
const bool is_fullscreen)
@@ -1016,27 +1020,27 @@ static void region_azone_edge_initialize(ScrArea *sa,
}
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
+ BLI_addtail(&(area->actionzones), az);
az->type = AZONE_REGION;
az->region = region;
az->edge = edge;
if (is_hidden) {
- region_azone_tab_plus(sa, az, region);
+ region_azone_tab_plus(area, az, region);
}
else {
region_azone_edge(az, region);
}
}
-static void region_azone_scrollbar_initialize(ScrArea *sa,
+static void region_azone_scrollbar_initialize(ScrArea *area,
ARegion *region,
AZScrollDirection direction)
{
rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? region->v2d.vert : region->v2d.hor;
AZone *az = MEM_callocN(sizeof(*az), __func__);
- BLI_addtail(&sa->actionzones, az);
+ BLI_addtail(&area->actionzones, az);
az->type = AZONE_REGION_SCROLL;
az->region = region;
az->direction = direction;
@@ -1057,21 +1061,21 @@ static void region_azone_scrollbar_initialize(ScrArea *sa,
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *region)
+static void region_azones_scrollbars_initialize(ScrArea *area, ARegion *region)
{
const View2D *v2d = &region->v2d;
if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES) == 0)) {
- region_azone_scrollbar_initialize(sa, region, AZ_SCROLL_VERT);
+ region_azone_scrollbar_initialize(area, region, AZ_SCROLL_VERT);
}
if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) &&
((v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES) == 0)) {
- region_azone_scrollbar_initialize(sa, region, AZ_SCROLL_HOR);
+ region_azone_scrollbar_initialize(area, region, AZ_SCROLL_HOR);
}
}
/* *************************************************************** */
-static void region_azones_add_edge(ScrArea *sa,
+static void region_azones_add_edge(ScrArea *area,
ARegion *region,
const int alignment,
const bool is_fullscreen)
@@ -1079,20 +1083,20 @@ static void region_azones_add_edge(ScrArea *sa,
/* edge code (t b l r) is along which area edge azone will be drawn */
if (alignment == RGN_ALIGN_TOP) {
- region_azone_edge_initialize(sa, region, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_BOTTOM) {
- region_azone_edge_initialize(sa, region, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_RIGHT) {
- region_azone_edge_initialize(sa, region, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
}
else if (alignment == RGN_ALIGN_LEFT) {
- region_azone_edge_initialize(sa, region, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(area, region, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
}
}
-static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *region)
+static void region_azones_add(const bScreen *screen, ScrArea *area, ARegion *region)
{
const bool is_fullscreen = screen->state == SCREENFULL;
@@ -1102,20 +1106,20 @@ static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *regio
return;
}
- region_azones_add_edge(sa, region, RGN_ALIGN_ENUM_FROM_MASK(region->alignment), is_fullscreen);
+ region_azones_add_edge(area, region, RGN_ALIGN_ENUM_FROM_MASK(region->alignment), is_fullscreen);
/* For a split region also continue the azone edge from the next region if this region is aligned
* with the next */
if ((region->alignment & RGN_SPLIT_PREV) && region->prev) {
region_azones_add_edge(
- sa, region, RGN_ALIGN_ENUM_FROM_MASK(region->prev->alignment), is_fullscreen);
+ area, region, RGN_ALIGN_ENUM_FROM_MASK(region->prev->alignment), is_fullscreen);
}
if (is_fullscreen) {
- fullscreen_azone_initialize(sa, region);
+ fullscreen_azone_initialize(area, region);
}
- region_azones_scrollbars_initialize(sa, region);
+ region_azones_scrollbars_initialize(area, region);
}
/* dir is direction to check, not the splitting edge direction! */
@@ -1133,7 +1137,7 @@ static int rct_fits(const rcti *rect, char dir, int size)
/* region should be overlapping */
/* function checks if some overlapping region was defined before - on same place */
-static void region_overlap_fix(ScrArea *sa, ARegion *region)
+static void region_overlap_fix(ScrArea *area, ARegion *region)
{
ARegion *ar1;
const int align = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
@@ -1168,7 +1172,7 @@ static void region_overlap_fix(ScrArea *sa, ARegion *region)
/* translate or close */
if (ar1) {
if (align1 == RGN_ALIGN_LEFT) {
- if (region->winrct.xmax + ar1->winx > sa->winx - U.widget_unit) {
+ if (region->winrct.xmax + ar1->winx > area->winx - U.widget_unit) {
region->flag |= RGN_FLAG_TOO_SMALL;
return;
}
@@ -1235,7 +1239,7 @@ bool ED_region_is_overlap(int spacetype, int regiontype)
}
static void region_rect_recursive(
- ScrArea *sa, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
+ ScrArea *area, ARegion *region, rcti *remainder, rcti *overlap_remainder, int quad)
{
rcti *remainder_prev = remainder;
@@ -1259,7 +1263,7 @@ static void region_rect_recursive(
int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
/* set here, assuming userpref switching forces to call this again */
- region->overlap = ED_region_is_overlap(sa->spacetype, region->regiontype);
+ region->overlap = ED_region_is_overlap(area->spacetype, region->regiontype);
/* clear state flags first */
region->flag &= ~(RGN_FLAG_TOO_SMALL | RGN_FLAG_SIZE_CLAMP_X | RGN_FLAG_SIZE_CLAMP_Y);
@@ -1300,7 +1304,7 @@ static void region_rect_recursive(
else if (region->regiontype == RGN_TYPE_FOOTER) {
prefsizey = ED_area_footersize();
}
- else if (ED_area_is_global(sa)) {
+ else if (ED_area_is_global(area)) {
prefsizey = ED_region_global_size_y();
}
else {
@@ -1501,7 +1505,7 @@ static void region_rect_recursive(
/* exception for multiple overlapping regions on same spot */
if (region->overlap && (alignment != RGN_ALIGN_FLOAT)) {
- region_overlap_fix(sa, region);
+ region_overlap_fix(area, region);
}
/* set winrect for azones */
@@ -1548,7 +1552,7 @@ static void region_rect_recursive(
BLI_assert(BLI_rcti_is_valid(&region->winrct));
- region_rect_recursive(sa, region->next, remainder, overlap_remainder, quad);
+ region_rect_recursive(area, region->next, remainder, overlap_remainder, quad);
/* Tag for redraw if size changes. */
if (region->winx != prev_winx || region->winy != prev_winy) {
@@ -1559,42 +1563,42 @@ static void region_rect_recursive(
memset(&region->runtime.visible_rect, 0, sizeof(region->runtime.visible_rect));
}
-static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
+static void area_calc_totrct(ScrArea *area, const rcti *window_rect)
{
short px = (short)U.pixelsize;
- sa->totrct.xmin = sa->v1->vec.x;
- sa->totrct.xmax = sa->v4->vec.x;
- sa->totrct.ymin = sa->v1->vec.y;
- sa->totrct.ymax = sa->v2->vec.y;
+ area->totrct.xmin = area->v1->vec.x;
+ area->totrct.xmax = area->v4->vec.x;
+ area->totrct.ymin = area->v1->vec.y;
+ area->totrct.ymax = area->v2->vec.y;
/* scale down totrct by 1 pixel on all sides not matching window borders */
- if (sa->totrct.xmin > window_rect->xmin) {
- sa->totrct.xmin += px;
+ if (area->totrct.xmin > window_rect->xmin) {
+ area->totrct.xmin += px;
}
- if (sa->totrct.xmax < (window_rect->xmax - 1)) {
- sa->totrct.xmax -= px;
+ if (area->totrct.xmax < (window_rect->xmax - 1)) {
+ area->totrct.xmax -= px;
}
- if (sa->totrct.ymin > window_rect->ymin) {
- sa->totrct.ymin += px;
+ if (area->totrct.ymin > window_rect->ymin) {
+ area->totrct.ymin += px;
}
- if (sa->totrct.ymax < (window_rect->ymax - 1)) {
- sa->totrct.ymax -= px;
+ if (area->totrct.ymax < (window_rect->ymax - 1)) {
+ area->totrct.ymax -= px;
}
/* Although the following asserts are correct they lead to a very unstable Blender.
* And the asserts would fail even in 2.7x
* (they were added in 2.8x as part of the top-bar commit).
* For more details see T54864. */
#if 0
- BLI_assert(sa->totrct.xmin >= 0);
- BLI_assert(sa->totrct.xmax >= 0);
- BLI_assert(sa->totrct.ymin >= 0);
- BLI_assert(sa->totrct.ymax >= 0);
+ BLI_assert(area->totrct.xmin >= 0);
+ BLI_assert(area->totrct.xmax >= 0);
+ BLI_assert(area->totrct.ymin >= 0);
+ BLI_assert(area->totrct.ymax >= 0);
#endif
/* for speedup */
- sa->winx = BLI_rcti_size_x(&sa->totrct) + 1;
- sa->winy = BLI_rcti_size_y(&sa->totrct) + 1;
+ area->winx = BLI_rcti_size_x(&area->totrct) + 1;
+ area->winy = BLI_rcti_size_y(&area->totrct) + 1;
}
/* used for area initialize below */
@@ -1617,12 +1621,12 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event)
}
/**
- * \param region: Region, may be NULL when adding handlers for \a sa.
+ * \param region: Region, may be NULL when adding handlers for \a area.
*/
static void ed_default_handlers(
- wmWindowManager *wm, ScrArea *sa, ARegion *region, ListBase *handlers, int flag)
+ wmWindowManager *wm, ScrArea *area, ARegion *region, ListBase *handlers, int flag)
{
- BLI_assert(region ? (&region->handlers == handlers) : (&sa->handlers == handlers));
+ BLI_assert(region ? (&region->handlers == handlers) : (&area->handlers == handlers));
/* note, add-handler checks if it already exists */
@@ -1641,7 +1645,7 @@ static void ed_default_handlers(
BLI_assert(&region->handlers == handlers);
if (region->gizmo_map == NULL) {
region->gizmo_map = WM_gizmomap_new_from_type(
- &(const struct wmGizmoMapType_Params){sa->spacetype, region->type->regionid});
+ &(const struct wmGizmoMapType_Params){area->spacetype, region->type->regionid});
}
WM_gizmomap_add_handlers(region, region->gizmo_map);
}
@@ -1668,9 +1672,9 @@ static void ed_default_handlers(
}
if (flag & ED_KEYMAP_TOOL) {
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, sa);
+ &region->handlers, WM_event_get_keymap_from_toolsystem_fallback, area);
WM_event_add_keymap_handler_dynamic(
- &region->handlers, WM_event_get_keymap_from_toolsystem, sa);
+ &region->handlers, WM_event_get_keymap_from_toolsystem, area);
}
if (flag & ED_KEYMAP_FRAMES) {
/* frame changing/jumping (for all spaces) */
@@ -1826,7 +1830,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
/* Dynamically sized regions may have changed region sizes, so we have to force azone update. */
area_azone_initialize(win, screen, area);
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
region_subwindow(region);
/* region size may have changed, init does necessary adjustments */
@@ -1843,7 +1847,7 @@ void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *ar
}
/* called in screen_refresh, or screens_init, also area size changes */
-void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
+void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *area)
{
WorkSpace *workspace = WM_window_get_active_workspace(win);
const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
@@ -1852,49 +1856,49 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
rcti rect, overlap_rect;
rcti window_rect;
- if (ED_area_is_global(sa) && (sa->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
+ if (ED_area_is_global(area) && (area->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
return;
}
WM_window_rect_calc(win, &window_rect);
/* set typedefinitions */
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ area->type = BKE_spacetype_from_id(area->spacetype);
- if (sa->type == NULL) {
- sa->spacetype = SPACE_VIEW3D;
- sa->type = BKE_spacetype_from_id(sa->spacetype);
+ if (area->type == NULL) {
+ area->spacetype = SPACE_VIEW3D;
+ area->type = BKE_spacetype_from_id(area->spacetype);
}
- for (region = sa->regionbase.first; region; region = region->next) {
- region->type = BKE_regiontype_from_id_or_first(sa->type, region->regiontype);
+ for (region = area->regionbase.first; region; region = region->next) {
+ region->type = BKE_regiontype_from_id_or_first(area->type, region->regiontype);
}
/* area sizes */
- area_calc_totrct(sa, &window_rect);
+ area_calc_totrct(area, &window_rect);
/* region rect sizes */
- rect = sa->totrct;
+ rect = area->totrct;
overlap_rect = rect;
- region_rect_recursive(sa, sa->regionbase.first, &rect, &overlap_rect, 0);
- sa->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
+ region_rect_recursive(area, area->regionbase.first, &rect, &overlap_rect, 0);
+ area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
/* default area handlers */
- ed_default_handlers(wm, sa, NULL, &sa->handlers, sa->type->keymapflag);
+ ed_default_handlers(wm, area, NULL, &area->handlers, area->type->keymapflag);
/* checks spacedata, adds own handlers */
- if (sa->type->init) {
- sa->type->init(wm, sa);
+ if (area->type->init) {
+ area->type->init(wm, area);
}
/* clear all azones, add the area triangle widgets */
- area_azone_initialize(win, screen, sa);
+ area_azone_initialize(win, screen, area);
/* region windows, default and own handlers */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
region_subwindow(region);
if (region->visible) {
/* default region handlers */
- ed_default_handlers(wm, sa, region, &region->handlers, region->type->keymapflag);
+ ed_default_handlers(wm, area, region, &region->handlers, region->type->keymapflag);
/* own handlers */
if (region->type->init) {
region->type->init(wm, region);
@@ -1906,18 +1910,18 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
}
/* Some AZones use View2D data which is only updated in region init, so call that first! */
- region_azones_add(screen, sa, region);
+ region_azones_add(screen, area, region);
}
/* Avoid re-initializing tools while resizing the window. */
if ((G.moving & G_TRANSFORM_WM) == 0) {
- if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
- WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
- sa->flag |= AREA_FLAG_ACTIVE_TOOL_UPDATE;
+ if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, area);
+ area->flag |= AREA_FLAG_ACTIVE_TOOL_UPDATE;
}
else {
- sa->runtime.tool = NULL;
- sa->runtime.is_tool_set = true;
+ area->runtime.tool = NULL;
+ area->runtime.is_tool_set = true;
}
}
}
@@ -1950,19 +1954,19 @@ void ED_region_floating_initialize(ARegion *region)
region_update_rect(region);
}
-void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *region)
+void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
{
if (region != NULL) {
if ((region->gizmo_map != NULL) && WM_gizmomap_cursor_set(region->gizmo_map, win)) {
return;
}
- if (sa && region->type && region->type->cursor) {
- region->type->cursor(win, sa, region);
+ if (area && region->type && region->type->cursor) {
+ region->type->cursor(win, area, region);
return;
}
}
- if (WM_cursor_set_from_tool(win, sa, region)) {
+ if (WM_cursor_set_from_tool(win, area, region)) {
return;
}
@@ -1970,29 +1974,29 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *region)
}
/* for use after changing visibility of regions */
-void ED_region_visibility_change_update(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
{
if (region->flag & RGN_FLAG_HIDDEN) {
WM_event_remove_handlers(C, &region->handlers);
}
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), area);
+ ED_area_tag_redraw(area);
}
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *region, const bool do_fade)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
region->flag ^= RGN_FLAG_HIDDEN;
if (do_fade && region->overlap) {
/* starts a timer, and in end calls the stuff below itself (region_sblend_invoke()) */
- ED_region_visibility_change_update_animated(C, sa, region);
+ ED_region_visibility_change_update_animated(C, area, region);
}
else {
- ED_region_visibility_change_update(C, sa, region);
+ ED_region_visibility_change_update(C, area, region);
}
}
@@ -2005,48 +2009,48 @@ void ED_region_toggle_hidden(bContext *C, ARegion *region)
/**
* we swap spaces for fullscreen to keep all allocated data area vertices were set
*/
-void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
{
SpaceType *st;
ARegion *region;
- const char spacetype = sa_dst->spacetype;
+ const char spacetype = area_dst->spacetype;
const short flag_copy = HEADER_NO_PULLDOWN;
- sa_dst->spacetype = sa_src->spacetype;
- sa_dst->type = sa_src->type;
+ area_dst->spacetype = area_src->spacetype;
+ area_dst->type = area_src->type;
- sa_dst->flag = (sa_dst->flag & ~flag_copy) | (sa_src->flag & flag_copy);
+ area_dst->flag = (area_dst->flag & ~flag_copy) | (area_src->flag & flag_copy);
/* area */
if (do_free) {
- BKE_spacedata_freelist(&sa_dst->spacedata);
+ BKE_spacedata_freelist(&area_dst->spacedata);
}
- BKE_spacedata_copylist(&sa_dst->spacedata, &sa_src->spacedata);
+ BKE_spacedata_copylist(&area_dst->spacedata, &area_src->spacedata);
/* Note; SPACE_EMPTY is possible on new screens */
/* regions */
if (do_free) {
st = BKE_spacetype_from_id(spacetype);
- for (region = sa_dst->regionbase.first; region; region = region->next) {
+ for (region = area_dst->regionbase.first; region; region = region->next) {
BKE_area_region_free(st, region);
}
- BLI_freelistN(&sa_dst->regionbase);
+ BLI_freelistN(&area_dst->regionbase);
}
- st = BKE_spacetype_from_id(sa_src->spacetype);
- for (region = sa_src->regionbase.first; region; region = region->next) {
+ st = BKE_spacetype_from_id(area_src->spacetype);
+ for (region = area_src->regionbase.first; region; region = region->next) {
ARegion *newar = BKE_area_region_copy(st, region);
- BLI_addtail(&sa_dst->regionbase, newar);
+ BLI_addtail(&area_dst->regionbase, newar);
}
}
-void ED_area_data_swap(ScrArea *sa_dst, ScrArea *sa_src)
+void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
{
- SWAP(char, sa_dst->spacetype, sa_src->spacetype);
- SWAP(SpaceType *, sa_dst->type, sa_src->type);
+ SWAP(char, area_dst->spacetype, area_src->spacetype);
+ SWAP(SpaceType *, area_dst->type, area_src->type);
- SWAP(ListBase, sa_dst->spacedata, sa_src->spacedata);
- SWAP(ListBase, sa_dst->regionbase, sa_src->regionbase);
+ SWAP(ListBase, area_dst->spacedata, area_src->spacedata);
+ SWAP(ListBase, area_dst->regionbase, area_src->regionbase);
}
/* *********** Space switching code *********** */
@@ -2078,18 +2082,18 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
}
/**
- * \param skip_ar_exit: Skip calling area exit callback. Set for opening temp spaces.
+ * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces.
*/
-void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exit)
+void ED_area_newspace(bContext *C, ScrArea *area, int type, const bool skip_region_exit)
{
wmWindow *win = CTX_wm_window(C);
- if (sa->spacetype != type) {
+ if (area->spacetype != type) {
SpaceType *st;
- SpaceLink *slold = sa->spacedata.first;
+ SpaceLink *slold = area->spacedata.first;
SpaceLink *sl;
- /* store sa->type->exit callback */
- void *sa_exit = sa->type ? sa->type->exit : NULL;
+ /* store area->type->exit callback */
+ void *area_exit = area->type ? area->type->exit : NULL;
/* When the user switches between space-types from the type-selector,
* changing the header-type is jarring (especially when using Ctrl-MouseWheel).
*
@@ -2100,34 +2104,34 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
* the space type defaults to in this case instead
* (needed for preferences to have space-type on bottom).
*/
- int header_alignment = ED_area_header_alignment_or_fallback(sa, -1);
+ int header_alignment = ED_area_header_alignment_or_fallback(area, -1);
const bool sync_header_alignment = ((header_alignment != -1) &&
((slold->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0));
/* in some cases (opening temp space) we don't want to
* call area exit callback, so we temporarily unset it */
- if (skip_ar_exit && sa->type) {
- sa->type->exit = NULL;
+ if (skip_region_exit && area->type) {
+ area->type->exit = NULL;
}
- ED_area_exit(C, sa);
+ ED_area_exit(C, area);
/* restore old area exit callback */
- if (skip_ar_exit && sa->type) {
- sa->type->exit = sa_exit;
+ if (skip_region_exit && area->type) {
+ area->type->exit = area_exit;
}
st = BKE_spacetype_from_id(type);
- sa->spacetype = type;
- sa->type = st;
+ area->spacetype = type;
+ area->type = st;
/* If st->new may be called, don't use context until then. The
- * sa->type->context() callback has changed but data may be invalid
+ * area->type->context() callback has changed but data may be invalid
* (e.g. with properties editor) until space-data is properly created */
/* check previously stored space */
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == type) {
break;
}
@@ -2136,7 +2140,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
/* old spacedata... happened during work on 2.50, remove */
if (sl && BLI_listbase_is_empty(&sl->regionbase)) {
st->free(sl);
- BLI_freelinkN(&sa->spacedata, sl);
+ BLI_freelinkN(&area->spacedata, sl);
if (slold == sl) {
slold = NULL;
}
@@ -2145,8 +2149,8 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
if (sl) {
/* swap regions */
- slold->regionbase = sa->regionbase;
- sa->regionbase = sl->regionbase;
+ slold->regionbase = area->regionbase;
+ area->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
/* SPACE_FLAG_TYPE_WAS_ACTIVE is only used to go back to a previously active space that is
* overlapped by temporary ones. It's now properly activated, so the flag should be cleared
@@ -2154,22 +2158,22 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
sl->link_flag &= ~SPACE_FLAG_TYPE_WAS_ACTIVE;
/* put in front of list */
- BLI_remlink(&sa->spacedata, sl);
- BLI_addhead(&sa->spacedata, sl);
+ BLI_remlink(&area->spacedata, sl);
+ BLI_addhead(&area->spacedata, sl);
}
else {
/* new space */
if (st) {
/* Don't get scene from context here which may depend on space-data. */
Scene *scene = WM_window_get_active_scene(win);
- sl = st->new (sa, scene);
- BLI_addhead(&sa->spacedata, sl);
+ sl = st->new (area, scene);
+ BLI_addhead(&area->spacedata, sl);
/* swap regions */
if (slold) {
- slold->regionbase = sa->regionbase;
+ slold->regionbase = area->regionbase;
}
- sa->regionbase = sl->regionbase;
+ area->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
}
}
@@ -2178,7 +2182,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
if (sync_header_alignment) {
/* Spaces with footer. */
if (st->spaceid == SPACE_TEXT) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
region->alignment = header_alignment;
}
@@ -2191,7 +2195,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
else {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
region->alignment = header_alignment;
break;
@@ -2200,24 +2204,24 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
- ED_area_initialize(CTX_wm_manager(C), win, sa);
+ ED_area_initialize(CTX_wm_manager(C), win, area);
/* tell WM to refresh, cursor types etc */
WM_event_add_mousemove(win);
/* send space change notifier */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, sa);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* also redraw when re-used */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
-static SpaceLink *area_get_prevspace(ScrArea *sa)
+static SpaceLink *area_get_prevspace(ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
/* First toggle to the next temporary space in the list. */
for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
@@ -2237,13 +2241,13 @@ static SpaceLink *area_get_prevspace(ScrArea *sa)
return sl->next;
}
-void ED_area_prevspace(bContext *C, ScrArea *sa)
+void ED_area_prevspace(bContext *C, ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
- SpaceLink *prevspace = sl ? area_get_prevspace(sa) : NULL;
+ SpaceLink *sl = area->spacedata.first;
+ SpaceLink *prevspace = sl ? area_get_prevspace(area) : NULL;
if (prevspace) {
- ED_area_newspace(C, sa, prevspace->spacetype, false);
+ ED_area_newspace(C, area, prevspace->spacetype, false);
/* We've exited the space, so it can't be considered temporary anymore. */
sl->link_flag &= ~SPACE_FLAG_TYPE_TEMPORARY;
}
@@ -2253,23 +2257,23 @@ void ED_area_prevspace(bContext *C, ScrArea *sa)
}
/* If this is a stacked fullscreen, changing to previous area exits it (meaning we're still in a
* fullscreen, but not in a stacked one). */
- sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
+ area->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* send space change notifier */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, sa);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, area);
}
/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
- ScrArea *sa = CTX_wm_area(C);
- bScreen *scr = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
PointerRNA areaptr;
int xco = 0.4 * U.widget_unit;
- RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
+ RNA_pointer_create(&(screen->id), &RNA_Area, area, &areaptr);
uiDefButR(block,
UI_BTYPE_MENU,
@@ -2343,26 +2347,44 @@ BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
return false;
}
+/**
+ * Builds the panel layout for the input \a panel or type \a pt.
+ *
+ * \param panel The panel to draw. Can be null, in which case a panel with the type of \a pt will
+ * be created.
+ * \param unique_panel_str A unique identifier for the name of the \a uiBlock associated with the
+ * panel. Used when the panel is an instanced panel so a unique identifier is needed to find the
+ * correct old \a uiBlock, and NULL otherwise.
+ */
static void ed_panel_draw(const bContext *C,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
ListBase *lb,
PanelType *pt,
Panel *panel,
int w,
int em,
- bool vertical)
+ bool vertical,
+ char *unique_panel_str)
{
const uiStyle *style = UI_style_get_dpi();
- /* draw panel */
- uiBlock *block = UI_block_begin(C, region, pt->idname, UI_EMBOSS);
+ /* Draw panel. */
+
+ char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN];
+ strncpy(block_name, pt->idname, BKE_ST_MAXNAME);
+ if (unique_panel_str != NULL) {
+ /* Instanced panels should have already been added at this point. */
+ strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN);
+ }
+ uiBlock *block = UI_block_begin(C, region, block_name, UI_EMBOSS);
bool open;
- panel = UI_panel_begin(sa, region, lb, block, pt, panel, &open);
+ panel = UI_panel_begin(area, region, lb, block, pt, panel, &open);
/* bad fixed values */
int xco, yco, h = 0;
+ int headerend = w - UI_UNIT_X;
if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
/* for preset menu */
@@ -2378,8 +2400,6 @@ static void ed_panel_draw(const bContext *C,
pt->draw_header_preset(C, panel);
- int headerend = w - UI_UNIT_X;
-
UI_block_layout_resolve(block, &xco, &yco);
UI_block_translate(block, headerend - xco, 0);
panel->layout = NULL;
@@ -2389,9 +2409,24 @@ static void ed_panel_draw(const bContext *C,
int labelx, labely;
UI_panel_label_offset(block, &labelx, &labely);
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ /* Unusual case: Use expanding layout (buttons stretch to available width). */
+ if (pt->flag & PNL_LAYOUT_HEADER_EXPAND) {
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ labelx,
+ labely,
+ headerend - 2 * style->panelspace,
+ 1,
+ 0,
+ style);
+ panel->layout = uiLayoutRow(layout, false);
+ }
+ /* Regular case: Normal panel with fixed size buttons. */
+ else {
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, labelx, labely, UI_UNIT_Y, 1, 0, style);
+ }
pt->draw_header(C, panel);
@@ -2442,17 +2477,26 @@ static void ed_panel_draw(const bContext *C,
/* Draw child panels. */
if (open) {
- for (LinkData *link = pt->children.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &pt->children) {
PanelType *child_pt = link->data;
Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
- ed_panel_draw(C, sa, region, &panel->children, child_pt, child_panel, w, em, vertical);
+ ed_panel_draw(C,
+ area,
+ region,
+ &panel->children,
+ child_pt,
+ child_panel,
+ w,
+ em,
+ vertical,
+ unique_panel_str);
}
}
}
- UI_panel_end(sa, region, block, w, h, open);
+ UI_panel_end(area, region, block, w, h, open);
}
/**
@@ -2501,7 +2545,7 @@ void ED_region_panels_layout_ex(const bContext *C,
region->runtime.category = NULL;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
View2D *v2d = &region->v2d;
int x, y, w, em;
@@ -2510,13 +2554,14 @@ void ED_region_panels_layout_ex(const bContext *C,
bool use_category_tabs = (category_override == NULL) &&
((((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) ||
(region->regiontype == RGN_TYPE_TOOLS &&
- sa->spacetype == SPACE_CLIP)));
+ area->spacetype == SPACE_CLIP)));
/* offset panels for small vertical tab area */
const char *category = NULL;
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
int margin_x = 0;
const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE;
const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false;
+ bool update_tot_size = true;
/* before setting the view */
if (vertical) {
@@ -2534,7 +2579,6 @@ void ED_region_panels_layout_ex(const bContext *C,
v2d->scroll |= (V2D_SCROLL_BOTTOM);
v2d->scroll &= ~(V2D_SCROLL_RIGHT);
}
- const int scroll = v2d->scroll;
/* collect categories */
if (use_category_tabs) {
@@ -2569,6 +2613,7 @@ void ED_region_panels_layout_ex(const bContext *C,
}
w -= margin_x;
+ int w_box_panel = w - UI_PANEL_BOX_STYLE_MARGIN * 2.0f;
/* create panels */
UI_panels_begin(C, region);
@@ -2576,8 +2621,14 @@ void ED_region_panels_layout_ex(const bContext *C,
/* set view2d view matrix - UI_block_begin() stores it */
UI_view2d_view_ortho(v2d);
+ bool has_instanced_panel = false;
for (LinkNode *pt_link = panel_types_stack; pt_link; pt_link = pt_link->next) {
PanelType *pt = pt_link->link;
+
+ if (pt->flag & PNL_INSTANCED) {
+ has_instanced_panel = true;
+ continue;
+ }
Panel *panel = UI_panel_find_by_type(&region->panels, pt);
if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
@@ -2586,7 +2637,51 @@ void ED_region_panels_layout_ex(const bContext *C,
}
}
- ed_panel_draw(C, sa, region, &region->panels, pt, panel, w, em, vertical);
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ pt,
+ panel,
+ (pt->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ NULL);
+ }
+
+ /* Draw "polyinstantaited" panels that don't have a 1 to 1 correspondence with their types. */
+ if (has_instanced_panel) {
+ LISTBASE_FOREACH (Panel *, panel, &region->panels) {
+ if (panel->type == NULL) {
+ continue; /* Some panels don't have a type.. */
+ }
+ if (panel->type->flag & PNL_INSTANCED) {
+ if (panel && UI_panel_is_dragging(panel)) {
+ /* Prevent View2d.tot rectangle size changes while dragging panels. */
+ update_tot_size = false;
+ }
+
+ /* Use a unique identifier for instanced panels, otherwise an old block for a different
+ * panel of the same type might be found. */
+ char unique_panel_str[8];
+ UI_list_panel_unique_str(panel, unique_panel_str);
+ ed_panel_draw(C,
+ area,
+ region,
+ &region->panels,
+ panel->type,
+ panel,
+ (panel->type->flag & PNL_DRAW_BOX) ? w_box_panel : w,
+ em,
+ vertical,
+ unique_panel_str);
+ }
+ }
}
/* align panels and return size */
@@ -2607,7 +2702,7 @@ void ED_region_panels_layout_ex(const bContext *C,
if ((region->sizex != size_dyn[0]) || (region->sizey != size_dyn[1])) {
region->sizex = size_dyn[0];
region->sizey = size_dyn[1];
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
y = fabsf(region->sizey * UI_DPI_FAC - 1);
}
@@ -2641,17 +2736,9 @@ void ED_region_panels_layout_ex(const bContext *C,
y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
-
- if (scroll != v2d->scroll) {
- /* Note: this code scales fine, but because of rounding differences, positions of elements
- * flip +1 or -1 pixel compared to redoing the entire layout again.
- * Leaving in commented code for future tests */
-#if 0
- UI_panels_scale(region, BLI_rctf_size_x(&v2d->cur));
- break;
-#endif
+ if (update_tot_size) {
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
}
if (use_category_tabs) {
@@ -2801,10 +2888,10 @@ void ED_region_header_layout(const bContext *C, ARegion *region)
if (region_layout_based && (region->sizex != new_sizex)) {
/* region size is layout based and needs to be updated */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
region->sizex = new_sizex;
- sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
UI_block_end(C, block);
@@ -2858,7 +2945,7 @@ int ED_area_headersize(void)
int ED_area_header_alignment_or_fallback(const ScrArea *area, int fallback)
{
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_HEADER) {
return region->alignment;
}
@@ -2879,7 +2966,7 @@ int ED_area_footersize(void)
int ED_area_footer_alignment_or_fallback(const ScrArea *area, int fallback)
{
- for (ARegion *region = area->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_FOOTER) {
return region->alignment;
}
@@ -3577,7 +3664,7 @@ void ED_region_message_subscribe(bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -3590,7 +3677,7 @@ void ED_region_message_subscribe(bContext *C,
}
if (region->type->message_subscribe != NULL) {
- region->type->message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ region->type->message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
}
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 739f1b93e07..d569e56e11b 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -73,19 +73,19 @@ bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2])
return false;
}
-bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar_gutter)
+bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter)
{
- *r_ar_gutter = region->winrct;
+ *r_region_gutter = region->winrct;
if (UI_panel_category_is_visible(region)) {
const int category_tabs_width = round_fl_to_int(UI_view2d_scale_get_x(&region->v2d) *
UI_PANEL_CATEGORY_MARGIN_WIDTH);
const int alignment = RGN_ALIGN_ENUM_FROM_MASK(region->alignment);
if (alignment == RGN_ALIGN_LEFT) {
- r_ar_gutter->xmax = r_ar_gutter->xmin + category_tabs_width;
+ r_region_gutter->xmax = r_region_gutter->xmin + category_tabs_width;
}
else if (alignment == RGN_ALIGN_RIGHT) {
- r_ar_gutter->xmin = r_ar_gutter->xmax - category_tabs_width;
+ r_region_gutter->xmin = r_region_gutter->xmax - category_tabs_width;
}
else {
BLI_assert(!"Unsupported alignment");
@@ -97,9 +97,9 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_ar
bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2])
{
- rcti ar_gutter;
- if (ED_region_panel_category_gutter_calc_rect(region, &ar_gutter)) {
- return BLI_rcti_isect_pt_v(&ar_gutter, event_xy);
+ rcti region_gutter;
+ if (ED_region_panel_category_gutter_calc_rect(region, &region_gutter)) {
+ return BLI_rcti_isect_pt_v(&region_gutter, event_xy);
}
return false;
}
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index cacd6b1edd7..075759f1120 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -46,7 +46,7 @@ void ED_region_generic_tools_region_message_subscribe(const struct bContext *UNU
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f757b856dcf..a9380debbdc 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -83,7 +83,7 @@ static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
/* To be used before calling immDrawPixelsTex
* Default shader is GPU_SHADER_2D_IMAGE_COLOR
* You can still set uniforms with :
- * GPU_shader_uniform_int(shader, GPU_shader_get_uniform_ensure(shader, "name"), 0);
+ * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0);
* */
IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
{
@@ -132,7 +132,7 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
float yzoom,
float color[4])
{
- unsigned char *uc_rect = (unsigned char *)rect;
+ uchar *uc_rect = (uchar *)rect;
const float *f_rect = (float *)rect;
int subpart_x, subpart_y, tex_w, tex_h;
int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
@@ -185,13 +185,13 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
}
- unsigned int pos = state->pos, texco = state->texco;
+ uint pos = state->pos, texco = state->texco;
/* optional */
/* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
* it does not need color.
*/
- if (state->shader != NULL && GPU_shader_get_uniform_ensure(state->shader, "color") != -1) {
+ if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
immUniformColor4fv((color) ? color : white);
}
@@ -650,7 +650,7 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf,
/* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */
if (need_fallback) {
- unsigned char *display_buffer;
+ uchar *display_buffer;
void *cache_handle;
display_buffer = IMB_display_buffer_acquire(
@@ -758,7 +758,7 @@ int ED_draw_imbuf_method(ImBuf *ibuf)
/* don't move to GPU_immediate_util.h because this uses user-prefs
* and isn't very low level */
-void immDrawBorderCorners(unsigned int pos, const rcti *border, float zoomx, float zoomy)
+void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy)
{
float delta_x = 4.0f * UI_DPI_FAC / zoomx;
float delta_y = 4.0f * UI_DPI_FAC / zoomy;
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 9536772be3d..3202dc68f37 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -27,6 +27,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -36,6 +37,7 @@
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
@@ -88,6 +90,7 @@ const char *screen_context_dir[] = {
"sequences",
"selected_sequences",
"selected_editable_sequences", /* sequencer */
+ "selected_nla_strips", /* nla editor */
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
"annotation_data",
@@ -111,12 +114,12 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
- Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL;
- Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL;
+ Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -127,7 +130,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "visible_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_VISIBLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -136,7 +139,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selectable_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -145,7 +148,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -154,7 +157,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
else if (CTX_data_equals(member, "selected_editable_objects")) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -164,7 +167,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "editable_objects")) {
/* Visible + Editable, but not necessarily selected */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
@@ -503,13 +506,38 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
return 1;
}
}
+ else if (CTX_data_equals(member, "selected_nla_strips")) {
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac) != 0) {
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+
+ ANIM_animdata_filter(&ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac.data, ac.datatype);
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ if (ale->datatype != ALE_NLASTRIP) {
+ continue;
+ }
+ NlaTrack *nlt = (NlaTrack *)ale->data;
+ NlaStrip *strip;
+ for (strip = nlt->strips.first; strip; strip = strip->next) {
+ if (strip->flag & NLASTRIP_FLAG_SELECT) {
+ CTX_data_list_add(result, &scene->id, &RNA_NlaStrip, strip);
+ }
+ }
+ }
+ ANIM_animdata_freelist(&anim_data);
+
+ CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
+ return 1;
+ }
+ }
else if (CTX_data_equals(member, "gpencil_data")) {
/* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these
* situations (as outlined above - see Campbell's #ifdefs).
* That causes the get_active function to fail when called from context.
* For that reason, we end up using an alternative where we pass everything in!
*/
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -523,7 +551,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* get pointer to Grease Pencil Data */
- gpd_ptr = ED_gpencil_data_get_pointers_direct(sa, obact, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers_direct(area, obact, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
@@ -531,7 +559,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "annotation_data")) {
- bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
@@ -544,7 +572,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
PointerRNA ptr;
/* Get pointer to Grease Pencil Data. */
- gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)sc, sa, scene, &ptr);
+ gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)screen, area, scene, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set(result, ptr.owner_id, ptr.type, ptr.data);
@@ -552,7 +580,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_layer")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -564,7 +592,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_annotation_layer")) {
- bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)sc, sa, scene);
+ bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -576,7 +604,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "active_gpencil_frame")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
@@ -588,7 +616,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "visible_gpencil_layers")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -603,7 +631,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_layers")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl;
@@ -618,7 +646,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
}
else if (CTX_data_equals(member, "editable_gpencil_strokes")) {
- bGPdata *gpd = ED_gpencil_data_get_active_direct(sa, obact);
+ bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd) {
@@ -636,7 +664,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
for (gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
for (gps = gpf->strokes.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ if (ED_gpencil_stroke_can_use_direct(area, gps)) {
/* check if the color is editable */
if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
continue;
@@ -701,7 +729,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_list_add(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
}
@@ -724,7 +752,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_pointer_set(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
break;
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index 3331f4db11b..2452302561b 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -41,10 +41,10 @@
* Draw horizontal shape visualizing future joining
* (left as well right direction of future joining).
*/
-static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_horizontal_join_shape(ScrArea *area, char dir, uint pos)
{
- const float width = screen_geom_area_width(sa) - 1;
- const float height = screen_geom_area_height(sa) - 1;
+ const float width = screen_geom_area_width(area) - 1;
+ const float height = screen_geom_area_height(area) - 1;
vec2f points[10];
short i;
float w, h;
@@ -58,43 +58,43 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
w = width / 4;
}
- points[0].x = sa->v1->vec.x;
- points[0].y = sa->v1->vec.y + height / 2;
+ points[0].x = area->v1->vec.x;
+ points[0].y = area->v1->vec.y + height / 2;
- points[1].x = sa->v1->vec.x;
- points[1].y = sa->v1->vec.y;
+ points[1].x = area->v1->vec.x;
+ points[1].y = area->v1->vec.y;
- points[2].x = sa->v4->vec.x - w;
- points[2].y = sa->v4->vec.y;
+ points[2].x = area->v4->vec.x - w;
+ points[2].y = area->v4->vec.y;
- points[3].x = sa->v4->vec.x - w;
- points[3].y = sa->v4->vec.y + height / 2 - 2 * h;
+ points[3].x = area->v4->vec.x - w;
+ points[3].y = area->v4->vec.y + height / 2 - 2 * h;
- points[4].x = sa->v4->vec.x - 2 * w;
- points[4].y = sa->v4->vec.y + height / 2;
+ points[4].x = area->v4->vec.x - 2 * w;
+ points[4].y = area->v4->vec.y + height / 2;
- points[5].x = sa->v4->vec.x - w;
- points[5].y = sa->v4->vec.y + height / 2 + 2 * h;
+ points[5].x = area->v4->vec.x - w;
+ points[5].y = area->v4->vec.y + height / 2 + 2 * h;
- points[6].x = sa->v3->vec.x - w;
- points[6].y = sa->v3->vec.y;
+ points[6].x = area->v3->vec.x - w;
+ points[6].y = area->v3->vec.y;
- points[7].x = sa->v2->vec.x;
- points[7].y = sa->v2->vec.y;
+ points[7].x = area->v2->vec.x;
+ points[7].y = area->v2->vec.y;
- points[8].x = sa->v4->vec.x;
- points[8].y = sa->v4->vec.y + height / 2 - h;
+ points[8].x = area->v4->vec.x;
+ points[8].y = area->v4->vec.y + height / 2 - h;
- points[9].x = sa->v4->vec.x;
- points[9].y = sa->v4->vec.y + height / 2 + h;
+ points[9].x = area->v4->vec.x;
+ points[9].y = area->v4->vec.y + height / 2 + h;
if (dir == 'l') {
/* when direction is left, then we flip direction of arrow */
- float cx = sa->v1->vec.x + width;
+ float cx = area->v1->vec.x + width;
for (i = 0; i < 10; i++) {
points[i].x -= cx;
points[i].x = -points[i].x;
- points[i].x += sa->v1->vec.x;
+ points[i].x += area->v1->vec.x;
}
}
@@ -122,10 +122,10 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos)
/**
* Draw vertical shape visualizing future joining (up/down direction).
*/
-static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_vertical_join_shape(ScrArea *area, char dir, uint pos)
{
- const float width = screen_geom_area_width(sa) - 1;
- const float height = screen_geom_area_height(sa) - 1;
+ const float width = screen_geom_area_width(area) - 1;
+ const float height = screen_geom_area_height(area) - 1;
vec2f points[10];
short i;
float w, h;
@@ -139,43 +139,43 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
w = width / 8;
}
- points[0].x = sa->v1->vec.x + width / 2;
- points[0].y = sa->v3->vec.y;
+ points[0].x = area->v1->vec.x + width / 2;
+ points[0].y = area->v3->vec.y;
- points[1].x = sa->v2->vec.x;
- points[1].y = sa->v2->vec.y;
+ points[1].x = area->v2->vec.x;
+ points[1].y = area->v2->vec.y;
- points[2].x = sa->v1->vec.x;
- points[2].y = sa->v1->vec.y + h;
+ points[2].x = area->v1->vec.x;
+ points[2].y = area->v1->vec.y + h;
- points[3].x = sa->v1->vec.x + width / 2 - 2 * w;
- points[3].y = sa->v1->vec.y + h;
+ points[3].x = area->v1->vec.x + width / 2 - 2 * w;
+ points[3].y = area->v1->vec.y + h;
- points[4].x = sa->v1->vec.x + width / 2;
- points[4].y = sa->v1->vec.y + 2 * h;
+ points[4].x = area->v1->vec.x + width / 2;
+ points[4].y = area->v1->vec.y + 2 * h;
- points[5].x = sa->v1->vec.x + width / 2 + 2 * w;
- points[5].y = sa->v1->vec.y + h;
+ points[5].x = area->v1->vec.x + width / 2 + 2 * w;
+ points[5].y = area->v1->vec.y + h;
- points[6].x = sa->v4->vec.x;
- points[6].y = sa->v4->vec.y + h;
+ points[6].x = area->v4->vec.x;
+ points[6].y = area->v4->vec.y + h;
- points[7].x = sa->v3->vec.x;
- points[7].y = sa->v3->vec.y;
+ points[7].x = area->v3->vec.x;
+ points[7].y = area->v3->vec.y;
- points[8].x = sa->v1->vec.x + width / 2 - w;
- points[8].y = sa->v1->vec.y;
+ points[8].x = area->v1->vec.x + width / 2 - w;
+ points[8].y = area->v1->vec.y;
- points[9].x = sa->v1->vec.x + width / 2 + w;
- points[9].y = sa->v1->vec.y;
+ points[9].x = area->v1->vec.x + width / 2 + w;
+ points[9].y = area->v1->vec.y;
if (dir == 'u') {
/* when direction is up, then we flip direction of arrow */
- float cy = sa->v1->vec.y + height;
+ float cy = area->v1->vec.y + height;
for (i = 0; i < 10; i++) {
points[i].y -= cy;
points[i].y = -points[i].y;
- points[i].y += sa->v1->vec.y;
+ points[i].y += area->v1->vec.y;
}
}
@@ -203,13 +203,13 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos)
/**
* Draw join shape due to direction of joining.
*/
-static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos)
+static void draw_join_shape(ScrArea *area, char dir, uint pos)
{
if (dir == 'u' || dir == 'd') {
- draw_vertical_join_shape(sa, dir, pos);
+ draw_vertical_join_shape(area, dir, pos);
}
else {
- draw_horizontal_join_shape(sa, dir, pos);
+ draw_horizontal_join_shape(area, dir, pos);
}
}
@@ -294,26 +294,26 @@ static GPUBatch *batch_screen_edges_get(int *corner_len)
/**
* Draw screen area darker with arrow (visualization of future joining).
*/
-static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos)
+static void scrarea_draw_shape_dark(ScrArea *area, char dir, uint pos)
{
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
immUniformColor4ub(0, 0, 0, 50);
- draw_join_shape(sa, dir, pos);
+ draw_join_shape(area, dir, pos);
}
/**
* Draw screen area lighter with arrow shape ("eraser" of previous dark shape).
*/
-static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir), unsigned int pos)
+static void scrarea_draw_shape_light(ScrArea *area, char UNUSED(dir), uint pos)
{
GPU_blend_set_func(GPU_DST_COLOR, GPU_SRC_ALPHA);
/* value 181 was hardly computed: 181~105 */
immUniformColor4ub(255, 255, 255, 50);
- /* draw_join_shape(sa, dir); */
+ /* draw_join_shape(area, dir); */
- immRectf(pos, sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
+ immRectf(pos, area->v1->vec.x, area->v1->vec.y, area->v3->vec.x, area->v3->vec.y);
}
static void drawscredge_area_draw(
@@ -350,12 +350,12 @@ static void drawscredge_area_draw(
/**
* \brief Screen edges drawing.
*/
-static void drawscredge_area(ScrArea *sa, int sizex, int sizey, float edge_thickness)
+static void drawscredge_area(ScrArea *area, int sizex, int sizey, float edge_thickness)
{
- short x1 = sa->v1->vec.x;
- short y1 = sa->v1->vec.y;
- short x2 = sa->v3->vec.x;
- short y2 = sa->v3->vec.y;
+ short x1 = area->v1->vec.x;
+ short y1 = area->v1->vec.y;
+ short x2 = area->v3->vec.x;
+ short y2 = area->v3->vec.y;
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, edge_thickness);
}
@@ -381,13 +381,13 @@ void ED_screen_draw_edges(wmWindow *win)
float col[4], corner_scale, edge_thickness;
int verts_per_corner = 0;
- ScrArea *sa;
+ ScrArea *area;
rcti scissor_rect;
BLI_rcti_init_minmax(&scissor_rect);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v1->vec.x, sa->v1->vec.y});
- BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){sa->v3->vec.x, sa->v3->vec.y});
+ for (area = screen->areabase.first; area; area = area->next) {
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){area->v1->vec.x, area->v1->vec.y});
+ BLI_rcti_do_minmax_v(&scissor_rect, (int[2]){area->v3->vec.x, area->v3->vec.y});
}
if (GPU_type_matches(GPU_DEVICE_INTEL_UHD, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
@@ -422,8 +422,8 @@ void ED_screen_draw_edges(wmWindow *win)
GPU_batch_uniform_1f(batch, "scale", corner_scale);
GPU_batch_uniform_4fv(batch, "color", col);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- drawscredge_area(sa, winsize_x, winsize_y, edge_thickness);
+ for (area = screen->areabase.first; area; area = area->next) {
+ drawscredge_area(area, winsize_x, winsize_y, edge_thickness);
}
GPU_blend(false);
@@ -480,7 +480,7 @@ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2)
immUnbindProgram();
}
-void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
+void ED_screen_draw_split_preview(ScrArea *area, const int dir, const float fac)
{
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -495,10 +495,10 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
if (dir == 'h') {
- const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax;
+ const float y = (1 - fac) * area->totrct.ymin + fac * area->totrct.ymax;
- immVertex2f(pos, sa->totrct.xmin, y);
- immVertex2f(pos, sa->totrct.xmax, y);
+ immVertex2f(pos, area->totrct.xmin, y);
+ immVertex2f(pos, area->totrct.xmax, y);
immEnd();
@@ -506,17 +506,17 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, sa->totrct.xmin, y + 1);
- immVertex2f(pos, sa->totrct.xmax, y + 1);
+ immVertex2f(pos, area->totrct.xmin, y + 1);
+ immVertex2f(pos, area->totrct.xmax, y + 1);
immEnd();
}
else {
BLI_assert(dir == 'v');
- const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax;
+ const float x = (1 - fac) * area->totrct.xmin + fac * area->totrct.xmax;
- immVertex2f(pos, x, sa->totrct.ymin);
- immVertex2f(pos, x, sa->totrct.ymax);
+ immVertex2f(pos, x, area->totrct.ymin);
+ immVertex2f(pos, x, area->totrct.ymax);
immEnd();
@@ -524,8 +524,8 @@ void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac)
immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x + 1, sa->totrct.ymin);
- immVertex2f(pos, x + 1, sa->totrct.ymax);
+ immVertex2f(pos, x + 1, area->totrct.ymin);
+ immVertex2f(pos, x + 1, area->totrct.ymax);
immEnd();
}
@@ -547,9 +547,9 @@ static void screen_preview_scale_get(
{
float max_x = 0, max_y = 0;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- max_x = MAX2(max_x, sa->totrct.xmax);
- max_y = MAX2(max_y, sa->totrct.ymax);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ max_x = MAX2(max_x, area->totrct.xmax);
+ max_y = MAX2(max_y, area->totrct.ymax);
}
r_scale[0] = (size_x * asp[0]) / max_x;
r_scale[1] = (size_y * asp[1]) / max_y;
@@ -566,12 +566,12 @@ static void screen_preview_draw_areas(const bScreen *screen,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4fv(col);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
rctf rect = {
- .xmin = sa->totrct.xmin * scale[0] + ofs_h,
- .xmax = sa->totrct.xmax * scale[0] - ofs_h,
- .ymin = sa->totrct.ymin * scale[1] + ofs_h,
- .ymax = sa->totrct.ymax * scale[1] - ofs_h,
+ .xmin = area->totrct.xmin * scale[0] + ofs_h,
+ .xmax = area->totrct.xmax * scale[0] - ofs_h,
+ .ymin = area->totrct.ymin * scale[1] + ofs_h,
+ .ymax = area->totrct.ymax * scale[1] - ofs_h,
};
immBegin(GPU_PRIM_TRI_FAN, 4);
@@ -608,7 +608,7 @@ static void screen_preview_draw(const bScreen *screen, int size_x, int size_y)
/**
* Render the preview for a screen layout in \a screen.
*/
-void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect)
+void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, uint *r_rect)
{
char err_out[256] = "unknown";
GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, true, false, err_out);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 0151a0fcb0d..6f004238522 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -70,19 +70,19 @@ static ScrArea *screen_addarea_ex(ScrAreaMap *area_map,
ScrVert *bottom_right,
short spacetype)
{
- ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea");
+ ScrArea *area = MEM_callocN(sizeof(ScrArea), "addscrarea");
- sa->v1 = bottom_left;
- sa->v2 = top_left;
- sa->v3 = top_right;
- sa->v4 = bottom_right;
- sa->spacetype = spacetype;
+ area->v1 = bottom_left;
+ area->v2 = top_left;
+ area->v3 = top_right;
+ area->v4 = bottom_right;
+ area->spacetype = spacetype;
- BLI_addtail(&area_map->areabase, sa);
+ BLI_addtail(&area_map->areabase, area);
- return sa;
+ return area;
}
-static ScrArea *screen_addarea(bScreen *sc,
+static ScrArea *screen_addarea(bScreen *screen,
ScrVert *left_bottom,
ScrVert *left_top,
ScrVert *right_top,
@@ -90,34 +90,35 @@ static ScrArea *screen_addarea(bScreen *sc,
short spacetype)
{
return screen_addarea_ex(
- AREAMAP_FROM_SCREEN(sc), left_bottom, left_top, right_top, right_bottom, spacetype);
+ AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, spacetype);
}
-static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
+static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
{
- ED_area_exit(C, sa);
+ ED_area_exit(C, area);
- BKE_screen_area_free(sa);
+ BKE_screen_area_free(area);
- BLI_remlink(&sc->areabase, sa);
- MEM_freeN(sa);
+ BLI_remlink(&screen->areabase, area);
+ MEM_freeN(area);
}
-ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
+ScrArea *area_split(
+ const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge)
{
ScrArea *newa = NULL;
ScrVert *sv1, *sv2;
short split;
rcti window_rect;
- if (sa == NULL) {
+ if (area == NULL) {
return NULL;
}
WM_window_rect_calc(win, &window_rect);
- split = screen_geom_find_area_split_point(sa, &window_rect, dir, fac);
+ split = screen_geom_find_area_split_point(area, &window_rect, dir, fac);
if (split == 0) {
return NULL;
}
@@ -128,73 +129,73 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo
if (dir == 'h') {
/* new vertices */
- sv1 = screen_geom_vertex_add(sc, sa->v1->vec.x, split);
- sv2 = screen_geom_vertex_add(sc, sa->v4->vec.x, split);
+ sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split);
+ sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split);
/* new edges */
- screen_geom_edge_add(sc, sa->v1, sv1);
- screen_geom_edge_add(sc, sv1, sa->v2);
- screen_geom_edge_add(sc, sa->v3, sv2);
- screen_geom_edge_add(sc, sv2, sa->v4);
- screen_geom_edge_add(sc, sv1, sv2);
+ screen_geom_edge_add(screen, area->v1, sv1);
+ screen_geom_edge_add(screen, sv1, area->v2);
+ screen_geom_edge_add(screen, area->v3, sv2);
+ screen_geom_edge_add(screen, sv2, area->v4);
+ screen_geom_edge_add(screen, sv1, sv2);
if (fac > 0.5f) {
/* new areas: top */
- newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->spacetype);
+ newa = screen_addarea(screen, sv1, area->v2, area->v3, sv2, area->spacetype);
/* area below */
- sa->v2 = sv1;
- sa->v3 = sv2;
+ area->v2 = sv1;
+ area->v3 = sv2;
}
else {
/* new areas: bottom */
- newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->spacetype);
+ newa = screen_addarea(screen, area->v1, sv1, sv2, area->v4, area->spacetype);
/* area above */
- sa->v1 = sv1;
- sa->v4 = sv2;
+ area->v1 = sv1;
+ area->v4 = sv2;
}
- ED_area_data_copy(newa, sa, true);
+ ED_area_data_copy(newa, area, true);
}
else {
/* new vertices */
- sv1 = screen_geom_vertex_add(sc, split, sa->v1->vec.y);
- sv2 = screen_geom_vertex_add(sc, split, sa->v2->vec.y);
+ sv1 = screen_geom_vertex_add(screen, split, area->v1->vec.y);
+ sv2 = screen_geom_vertex_add(screen, split, area->v2->vec.y);
/* new edges */
- screen_geom_edge_add(sc, sa->v1, sv1);
- screen_geom_edge_add(sc, sv1, sa->v4);
- screen_geom_edge_add(sc, sa->v2, sv2);
- screen_geom_edge_add(sc, sv2, sa->v3);
- screen_geom_edge_add(sc, sv1, sv2);
+ screen_geom_edge_add(screen, area->v1, sv1);
+ screen_geom_edge_add(screen, sv1, area->v4);
+ screen_geom_edge_add(screen, area->v2, sv2);
+ screen_geom_edge_add(screen, sv2, area->v3);
+ screen_geom_edge_add(screen, sv1, sv2);
if (fac > 0.5f) {
/* new areas: right */
- newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->spacetype);
+ newa = screen_addarea(screen, sv1, sv2, area->v3, area->v4, area->spacetype);
/* area left */
- sa->v3 = sv2;
- sa->v4 = sv1;
+ area->v3 = sv2;
+ area->v4 = sv1;
}
else {
/* new areas: left */
- newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->spacetype);
+ newa = screen_addarea(screen, area->v1, area->v2, sv2, sv1, area->spacetype);
/* area right */
- sa->v1 = sv1;
- sa->v2 = sv2;
+ area->v1 = sv1;
+ area->v2 = sv2;
}
- ED_area_data_copy(newa, sa, true);
+ ED_area_data_copy(newa, area, true);
}
/* remove double vertices en edges */
if (merge) {
- BKE_screen_remove_double_scrverts(sc);
+ BKE_screen_remove_double_scrverts(screen);
}
- BKE_screen_remove_double_scredges(sc);
- BKE_screen_remove_unused_scredges(sc);
+ BKE_screen_remove_double_scredges(screen);
+ BKE_screen_remove_unused_scredges(screen);
return newa;
}
@@ -204,34 +205,34 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo
*/
bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
- bScreen *sc;
+ bScreen *screen;
ScrVert *sv1, *sv2, *sv3, *sv4;
- sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
- sc->do_refresh = true;
- sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
+ screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
+ screen->do_refresh = true;
+ screen->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
- sv1 = screen_geom_vertex_add(sc, rect->xmin, rect->ymin);
- sv2 = screen_geom_vertex_add(sc, rect->xmin, rect->ymax - 1);
- sv3 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymax - 1);
- sv4 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymin);
+ sv1 = screen_geom_vertex_add(screen, rect->xmin, rect->ymin);
+ sv2 = screen_geom_vertex_add(screen, rect->xmin, rect->ymax - 1);
+ sv3 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymax - 1);
+ sv4 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymin);
- screen_geom_edge_add(sc, sv1, sv2);
- screen_geom_edge_add(sc, sv2, sv3);
- screen_geom_edge_add(sc, sv3, sv4);
- screen_geom_edge_add(sc, sv4, sv1);
+ screen_geom_edge_add(screen, sv1, sv2);
+ screen_geom_edge_add(screen, sv2, sv3);
+ screen_geom_edge_add(screen, sv3, sv4);
+ screen_geom_edge_add(screen, sv4, sv1);
/* dummy type, no spacedata */
- screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY);
+ screen_addarea(screen, sv1, sv2, sv3, sv4, SPACE_EMPTY);
- return sc;
+ return screen;
}
void screen_data_copy(bScreen *to, bScreen *from)
{
ScrVert *s1, *s2;
ScrEdge *se;
- ScrArea *sa, *saf;
+ ScrArea *area, *saf;
/* free contents of 'to', is from blenkernel screen.c */
BKE_screen_free(to);
@@ -255,18 +256,18 @@ void screen_data_copy(bScreen *to, bScreen *from)
}
saf = from->areabase.first;
- for (sa = to->areabase.first; sa; sa = sa->next, saf = saf->next) {
- sa->v1 = sa->v1->newv;
- sa->v2 = sa->v2->newv;
- sa->v3 = sa->v3->newv;
- sa->v4 = sa->v4->newv;
+ for (area = to->areabase.first; area; area = area->next, saf = saf->next) {
+ area->v1 = area->v1->newv;
+ area->v2 = area->v2->newv;
+ area->v3 = area->v3->newv;
+ area->v4 = area->v4->newv;
- BLI_listbase_clear(&sa->spacedata);
- BLI_listbase_clear(&sa->regionbase);
- BLI_listbase_clear(&sa->actionzones);
- BLI_listbase_clear(&sa->handlers);
+ BLI_listbase_clear(&area->spacedata);
+ BLI_listbase_clear(&area->regionbase);
+ BLI_listbase_clear(&area->actionzones);
+ BLI_listbase_clear(&area->handlers);
- ED_area_data_copy(sa, saf, true);
+ ED_area_data_copy(area, saf, true);
}
/* put at zero (needed?) */
@@ -285,48 +286,47 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
screen_new->do_draw = true;
}
-/* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
+/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
/* -1 = not valid check */
/* used with join operator */
-int area_getorientation(ScrArea *sa, ScrArea *sb)
+int area_getorientation(ScrArea *area, ScrArea *sb)
{
- if (sa == NULL || sb == NULL) {
+ if (area == NULL || sb == NULL) {
return -1;
}
- ScrVert *saBL = sa->v1;
- ScrVert *saTL = sa->v2;
- ScrVert *saTR = sa->v3;
- ScrVert *saBR = sa->v4;
+ ScrVert *saBL = area->v1;
+ ScrVert *saTL = area->v2;
+ ScrVert *saTR = area->v3;
+ ScrVert *saBR = area->v4;
ScrVert *sbBL = sb->v1;
ScrVert *sbTL = sb->v2;
ScrVert *sbTR = sb->v3;
ScrVert *sbBR = sb->v4;
- int tolerance = U.pixelsize * 4;
-
- if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* sa to right of sb = W */
- if ((abs(saBL->vec.y - sbBR->vec.y) <= tolerance) &&
- (abs(saTL->vec.y - sbTR->vec.y) <= tolerance)) {
+ if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */
+ if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) {
return 0;
}
}
- else if (saTL->vec.y == sbBL->vec.y && saTR->vec.y == sbBR->vec.y) { /* sa to bottom of sb = N */
- if ((abs(saTL->vec.x - sbBL->vec.x) <= tolerance) &&
- (abs(saTR->vec.x - sbBR->vec.x) <= tolerance)) {
+ else if (saTL->vec.y == sbBL->vec.y &&
+ saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */
+ if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) {
return 1;
}
}
- else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* sa to left of sb = E */
- if ((abs(saTR->vec.y - sbTL->vec.y) <= tolerance) &&
- (abs(saBR->vec.y - sbBL->vec.y) <= tolerance)) {
+ else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */
+ if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) {
return 2;
}
}
- else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* sa on top of sb = S*/
- if ((abs(saBL->vec.x - sbTL->vec.x) <= tolerance) &&
- (abs(saBR->vec.x - sbTR->vec.x) <= tolerance)) {
+ else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/
+ if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) &&
+ (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) {
return 3;
}
}
@@ -334,10 +334,73 @@ int area_getorientation(ScrArea *sa, ScrArea *sb)
return -1;
}
+/* Screen verts with horizontal position equal to from_x are moved to to_x. */
+static void screen_verts_halign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_x,
+ const short to_x)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.x == from_x) {
+ v1->vec.x = to_x;
+ }
+ }
+}
+
+/* Screen verts with vertical position equal to from_y are moved to to_y. */
+static void screen_verts_valign(const wmWindow *win,
+ const bScreen *screen,
+ const short from_y,
+ const short to_y)
+{
+ ED_screen_verts_iter(win, screen, v1)
+ {
+ if (v1->vec.y == from_y) {
+ v1->vec.y = to_y;
+ }
+ }
+}
+
+/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
+ */
+static void screen_areas_align(
+ bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir)
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ if (dir == 0 || dir == 2) {
+ /* horizontal join, use average for new top and bottom. */
+ int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
+ int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
+
+ /* Move edges exactly matching source top and bottom. */
+ screen_verts_valign(win, screen, sa1->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa1->v4->vec.y, bottom);
+
+ /* Move edges exactly matching target top and bottom. */
+ screen_verts_valign(win, screen, sa2->v2->vec.y, top);
+ screen_verts_valign(win, screen, sa2->v4->vec.y, bottom);
+ }
+ else {
+ /* Vertical join, use averages for new left and right. */
+ int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2;
+ int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2;
+
+ /* Move edges exactly matching source left and right. */
+ screen_verts_halign(win, screen, sa1->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa1->v3->vec.x, right);
+
+ /* Move edges exactly matching target left and right */
+ screen_verts_halign(win, screen, sa2->v1->vec.x, left);
+ screen_verts_halign(win, screen, sa2->v3->vec.x, right);
+ }
+}
+
/* Helper function to join 2 areas, it has a return value, 0=failed 1=success
* used by the split, join operators
*/
-int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
+int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
{
int dir = area_getorientation(sa1, sa2);
@@ -346,51 +409,37 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
}
/* Align areas if they are not. Do sanity checking before getting here. */
-
- if (dir == 0 || dir == 2) {
- /* horizontal join, so vertically align source vert to target */
- sa2->v1->vec.y = sa1->v1->vec.y; /* vertical align sa1 BL */
- sa2->v2->vec.y = sa1->v2->vec.y; /* vertical align sa1 TL */
- sa2->v3->vec.y = sa1->v3->vec.y; /* vertical align sa1 TR */
- sa2->v4->vec.y = sa1->v4->vec.y; /* vertical align sa1 BR */
- }
- else {
- /* vertical join, so horizontally align source verts to target */
- sa2->v1->vec.x = sa1->v1->vec.x; /* vertical align sa1 BL */
- sa2->v2->vec.x = sa1->v2->vec.x; /* vertical align sa1 TL */
- sa2->v3->vec.x = sa1->v3->vec.x; /* vertical align sa1 TR */
- sa2->v4->vec.x = sa1->v4->vec.x; /* vertical align sa1 BR */
- }
+ screen_areas_align(C, screen, sa1, sa2, dir);
if (dir == 0) { /* sa1 to right of sa2 = W */
sa1->v1 = sa2->v1; /* BL */
sa1->v2 = sa2->v2; /* TL */
- screen_geom_edge_add(scr, sa1->v2, sa1->v3);
- screen_geom_edge_add(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v2, sa1->v3);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 1) { /* sa1 to bottom of sa2 = N */
sa1->v2 = sa2->v2; /* TL */
sa1->v3 = sa2->v3; /* TR */
- screen_geom_edge_add(scr, sa1->v1, sa1->v2);
- screen_geom_edge_add(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v2);
+ screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
else if (dir == 2) { /* sa1 to left of sa2 = E */
sa1->v3 = sa2->v3; /* TR */
sa1->v4 = sa2->v4; /* BR */
- screen_geom_edge_add(scr, sa1->v2, sa1->v3);
- screen_geom_edge_add(scr, sa1->v1, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v2, sa1->v3);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v4);
}
else if (dir == 3) { /* sa1 on top of sa2 = S */
sa1->v1 = sa2->v1; /* BL */
sa1->v4 = sa2->v4; /* BR */
- screen_geom_edge_add(scr, sa1->v1, sa1->v2);
- screen_geom_edge_add(scr, sa1->v3, sa1->v4);
+ screen_geom_edge_add(screen, sa1->v1, sa1->v2);
+ screen_geom_edge_add(screen, sa1->v3, sa1->v4);
}
- screen_delarea(C, scr, sa2);
- BKE_screen_remove_double_scrverts(scr);
+ screen_delarea(C, screen, sa2);
+ BKE_screen_remove_double_scrverts(screen);
/* Update preview thumbnail */
- BKE_icon_changed(scr->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
return 1;
}
@@ -398,12 +447,12 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
/* screen sets cursor based on active region */
-static void region_cursor_set_ex(wmWindow *win, ScrArea *sa, ARegion *region, bool swin_changed)
+static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
{
BLI_assert(WM_window_get_active_screen(win)->active_region == region);
if (win->tag_cursor_refresh || swin_changed || (region->type && region->type->event_cursor)) {
win->tag_cursor_refresh = false;
- ED_region_cursor_set(win, sa, region);
+ ED_region_cursor_set(win, area, region);
}
}
@@ -411,11 +460,10 @@ static void region_cursor_set(wmWindow *win, bool swin_changed)
{
bScreen *screen = WM_window_get_active_screen(win);
- ED_screen_areas_iter(win, screen, sa)
- {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ ED_screen_areas_iter (win, screen, area) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == screen->active_region) {
- region_cursor_set_ex(win, sa, region, swin_changed);
+ region_cursor_set_ex(win, area, region, swin_changed);
return;
}
}
@@ -465,8 +513,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
screen_geom_vertices_scale(win, screen);
- ED_screen_areas_iter(win, screen, area)
- {
+ ED_screen_areas_iter (win, screen, area) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
ED_area_initialize(wm, win, area);
@@ -522,11 +569,11 @@ void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *scree
* Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
* slightly differently, see #ui_region_temp_remove().
*/
-void ED_region_remove(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
{
ED_region_exit(C, region);
- BKE_area_region_free(sa->type, region);
- BLI_freelinkN(&sa->regionbase, region);
+ BKE_area_region_free(area->type, region);
+ BLI_freelinkN(&area->regionbase, region);
}
/* *********** exit calls are for closing running stuff ******** */
@@ -545,7 +592,7 @@ void ED_region_exit(bContext *C, ARegion *region)
WM_event_remove_handlers(C, &region->handlers);
WM_event_modal_handler_region_replace(win, region, NULL);
- WM_draw_region_free(region);
+ WM_draw_region_free(region, true);
if (region->headerstr) {
MEM_freeN(region->headerstr);
@@ -562,25 +609,25 @@ void ED_region_exit(bContext *C, ARegion *region)
CTX_wm_region_set(C, prevar);
}
-void ED_area_exit(bContext *C, ScrArea *sa)
+void ED_area_exit(bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *region;
- if (sa->type && sa->type->exit) {
- sa->type->exit(wm, sa);
+ if (area->type && area->type->exit) {
+ area->type->exit(wm, area);
}
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_exit(C, region);
}
- WM_event_remove_handlers(C, &sa->handlers);
- WM_event_modal_handler_area_replace(win, sa, NULL);
+ WM_event_remove_handlers(C, &area->handlers);
+ WM_event_modal_handler_area_replace(win, area, NULL);
CTX_wm_area_set(C, prevsa);
}
@@ -605,15 +652,15 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
screen->active_region = NULL;
- for (ARegion *region = screen->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
ED_region_exit(C, region);
}
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- ED_area_exit(C, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ ED_area_exit(C, area);
}
/* Don't use ED_screen_areas_iter here, it skips hidden areas. */
- for (ScrArea *sa = window->global_areas.areabase.first; sa; sa = sa->next) {
- ED_area_exit(C, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &window->global_areas.areabase) {
+ ED_area_exit(C, area);
}
/* mark it available for use for other windows */
@@ -636,15 +683,15 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
{
const bScreen *screen = WM_window_get_active_screen(win);
AZone *az = NULL;
- ScrArea *sa;
+ ScrArea *area;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if ((az = ED_area_actionzone_find_xy(sa, xy))) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if ((az = ED_area_actionzone_find_xy(area, xy))) {
break;
}
}
- if (sa) {
+ if (area) {
if (az->type == AZONE_AREA) {
WM_cursor_set(win, WM_CURSOR_EDIT);
}
@@ -680,63 +727,63 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
*/
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
- bScreen *scr = WM_window_get_active_screen(win);
- if (scr == NULL) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (screen == NULL) {
return;
}
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
ARegion *region;
- ARegion *ar_prev = scr->active_region;
+ ARegion *region_prev = screen->active_region;
- ED_screen_areas_iter(win, scr, area_iter)
- {
- if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) {
- if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) {
+ ED_screen_areas_iter (win, screen, area_iter) {
+ if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
+ xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) {
+ if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
+ xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) {
if (ED_area_azones_update(area_iter, xy) == NULL) {
- sa = area_iter;
+ area = area_iter;
break;
}
}
}
}
- if (sa) {
+ if (area) {
/* Make overlap active when mouse over. */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (ED_region_contains_xy(region, xy)) {
- scr->active_region = region;
+ screen->active_region = region;
break;
}
}
}
else {
- scr->active_region = NULL;
+ screen->active_region = NULL;
}
/* Check for redraw headers. */
- if (ar_prev != scr->active_region) {
+ if (region_prev != screen->active_region) {
- ED_screen_areas_iter(win, scr, area_iter)
- {
+ ED_screen_areas_iter (win, screen, area_iter) {
bool do_draw = false;
for (region = area_iter->regionbase.first; region; region = region->next) {
/* Call old area's deactivate if assigned. */
- if (region == ar_prev && area_iter->type->deactivate) {
+ if (region == region_prev && area_iter->type->deactivate) {
area_iter->type->deactivate(area_iter);
}
- if (region == ar_prev && region != scr->active_region) {
- wmGizmoMap *gzmap = ar_prev->gizmo_map;
+ if (region == region_prev && region != screen->active_region) {
+ wmGizmoMap *gzmap = region_prev->gizmo_map;
if (gzmap) {
if (WM_gizmo_highlight_set(gzmap, NULL)) {
- ED_region_tag_redraw_no_rebuild(ar_prev);
+ ED_region_tag_redraw_no_rebuild(region_prev);
}
}
}
- if (region == ar_prev || region == scr->active_region) {
+ if (region == region_prev || region == screen->active_region) {
do_draw = true;
}
}
@@ -753,19 +800,19 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
/* Cursors, for time being set always on edges,
* otherwise the active region doesn't switch. */
- if (scr->active_region == NULL) {
+ if (screen->active_region == NULL) {
screen_cursor_set(win, xy);
}
else {
/* Notifier invokes freeing the buttons... causing a bit too much redraws. */
- region_cursor_set_ex(win, sa, scr->active_region, ar_prev != scr->active_region);
+ region_cursor_set_ex(win, area, screen->active_region, region_prev != screen->active_region);
- if (ar_prev != scr->active_region) {
+ if (region_prev != screen->active_region) {
/* This used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling. */
if (C) {
- UI_screen_free_active_but(C, scr);
+ UI_screen_free_active_but(C, screen);
}
}
}
@@ -774,19 +821,19 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
int ED_screen_area_active(const bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
- if (win && sc && sa) {
- AZone *az = ED_area_actionzone_find_xy(sa, &win->eventstate->x);
+ if (win && screen && area) {
+ AZone *az = ED_area_actionzone_find_xy(area, &win->eventstate->x);
ARegion *region;
if (az && az->type == AZONE_REGION) {
return 1;
}
- for (region = sa->regionbase.first; region; region = region->next) {
- if (region == sc->active_region) {
+ for (region = area->regionbase.first; region; region = region->next) {
+ if (region == screen->active_region) {
return 1;
}
}
@@ -815,16 +862,16 @@ static ScrArea *screen_area_create_with_geometry(ScrAreaMap *area_map,
return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
}
-static void screen_area_set_geometry_rect(ScrArea *sa, const rcti *rect)
+static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
{
- sa->v1->vec.x = rect->xmin;
- sa->v1->vec.y = rect->ymin;
- sa->v2->vec.x = rect->xmin;
- sa->v2->vec.y = rect->ymax;
- sa->v3->vec.x = rect->xmax;
- sa->v3->vec.y = rect->ymax;
- sa->v4->vec.x = rect->xmax;
- sa->v4->vec.y = rect->ymin;
+ area->v1->vec.x = rect->xmin;
+ area->v1->vec.y = rect->ymin;
+ area->v2->vec.x = rect->xmin;
+ area->v2->vec.y = rect->ymax;
+ area->v3->vec.x = rect->xmax;
+ area->v3->vec.y = rect->ymax;
+ area->v4->vec.x = rect->xmax;
+ area->v4->vec.y = rect->ymin;
}
static void screen_global_area_refresh(wmWindow *win,
@@ -910,7 +957,7 @@ void ED_screen_global_areas_sync(wmWindow *win)
screen->flag &= ~SCREEN_COLLAPSE_STATUSBAR;
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->global->cur_fixed_height == area->global->size_min) {
if (area->spacetype == SPACE_STATUSBAR) {
screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
@@ -943,8 +990,8 @@ static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmai
for (bScreen *screen_iter = bmain->screens.first; screen_iter;
screen_iter = screen_iter->id.next) {
if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = screen_iter->areabase.first;
- if (sa && sa->full == screen) {
+ ScrArea *area = screen_iter->areabase.first;
+ if (area && area->full == screen) {
return screen_iter;
}
}
@@ -976,8 +1023,8 @@ bScreen *screen_change_prepare(
wmTimer *wt = screen_old->animtimer;
/* remove handlers referencing areas in old screen */
- for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
- WM_event_remove_area_handler(&win->modalhandlers, sa);
+ LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
+ WM_event_remove_area_handler(&win->modalhandlers, area);
}
/* we put timer to sleep, so screen_exit has to think there's no timer */
@@ -998,17 +1045,17 @@ bScreen *screen_change_prepare(
return NULL;
}
-void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
+void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
{
Scene *scene = WM_window_get_active_scene(win);
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
- WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
ED_screen_refresh(CTX_wm_manager(C), win);
- BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */
+ BKE_screen_view3d_scene_sync(screen, scene); /* sync new screen with scene data */
WM_event_add_notifier(C, NC_WINDOW, NULL);
WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
@@ -1024,16 +1071,16 @@ void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
* \warning Do NOT call in area/region queues!
* \returns if screen changing was successful.
*/
-bool ED_screen_change(bContext *C, bScreen *sc)
+bool ED_screen_change(bContext *C, bScreen *screen)
{
Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
bScreen *screen_old = CTX_wm_screen(C);
- bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
+ bScreen *screen_new = screen_change_prepare(screen_old, screen, bmain, C, win);
if (screen_new) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
- WM_window_set_active_screen(win, workspace, sc);
+ WM_window_set_active_screen(win, workspace, screen);
screen_change_update(C, win, screen_new);
return true;
@@ -1042,21 +1089,24 @@ bool ED_screen_change(bContext *C, bScreen *sc)
return false;
}
-static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *sa, View3D *v3d)
+static void screen_set_3dview_camera(Scene *scene,
+ ViewLayer *view_layer,
+ ScrArea *area,
+ View3D *v3d)
{
/* fix any cameras that are used in the 3d view but not in the scene */
BKE_screen_view3d_sync(v3d, scene);
if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
v3d->camera = BKE_view_layer_camera_find(view_layer);
- // XXX if (sc == curscreen) handle_view3d_lock();
+ // XXX if (screen == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *region;
ListBase *regionbase;
/* regionbase is in different place depending if space is active */
- if (v3d == sa->spacedata.first) {
- regionbase = &sa->regionbase;
+ if (v3d == area->spacedata.first) {
+ regionbase = &area->regionbase;
}
else {
regionbase = &v3d->regionbase;
@@ -1104,28 +1154,28 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
/* Update 3D view cameras. */
const bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
- screen_set_3dview_camera(scene, view_layer, sa, v3d);
+ screen_set_3dview_camera(scene, view_layer, area, v3d);
}
}
}
}
-ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
+ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *newsa = NULL;
SpaceLink *newsl;
- if (!sa || sa->full == NULL) {
- newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
+ if (!area || area->full == NULL) {
+ newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
}
if (!newsa) {
- newsa = sa;
+ newsa = area;
}
BLI_assert(newsa);
@@ -1144,40 +1194,40 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
/**
* \a was_prev_temp for the case previous space was a temporary fullscreen as well
*/
-void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
+void ED_screen_full_prevspace(bContext *C, ScrArea *area)
{
- BLI_assert(sa->full);
+ BLI_assert(area->full);
- if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
+ if (area->flag & AREA_FLAG_STACKED_FULLSCREEN) {
/* stacked fullscreen -> only go back to previous area and don't toggle out of fullscreen */
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
else {
- ED_screen_restore_temp_type(C, sa);
+ ED_screen_restore_temp_type(C, area);
}
}
-void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
+void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
{
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
/* In case nether functions below run. */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
- ED_area_prevspace(C, sa);
+ ED_area_prevspace(C, area);
}
- if (sa->full) {
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ if (area->full) {
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENMAXIMIZED);
}
}
/* restore a screen / area back to default operation, after temp fullscreen modes */
-void ED_screen_full_restore(bContext *C, ScrArea *sa)
+void ED_screen_full_restore(bContext *C, ScrArea *area)
{
wmWindow *win = CTX_wm_window(C);
- SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *sl = area->spacedata.first;
bScreen *screen = CTX_wm_screen(C);
short state = (screen ? screen->state : SCREENMAXIMIZED);
@@ -1186,37 +1236,37 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
if (sl->next) {
if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
}
else {
- ED_screen_state_toggle(C, win, sa, state);
+ ED_screen_state_toggle(C, win, area, state);
}
- /* warning: 'sa' may be freed */
+ /* warning: 'area' may be freed */
}
/* otherwise just tile the area again */
else {
- ED_screen_state_toggle(C, win, sa, state);
+ ED_screen_state_toggle(C, win, area, state);
}
}
/**
* this function toggles: if area is maximized/full then the parent will be restored
*
- * \warning \a sa may be freed.
+ * \warning \a area may be freed.
*/
-ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
+ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
WorkSpace *workspace = WM_window_get_active_workspace(win);
- bScreen *sc, *oldscreen;
+ bScreen *screen, *oldscreen;
ARegion *region;
- if (sa) {
+ if (area) {
/* ensure we don't have a button active anymore, can crash when
* switching screens with tooltip open because region and tooltip
* are no longer in the same screen */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
UI_blocklist_free(C, &region->uiblocks);
if (region->regiontimer) {
@@ -1226,25 +1276,25 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
/* prevent hanging status prints */
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
ED_workspace_status_text(C, NULL);
}
- if (sa && sa->full) {
+ if (area && area->full) {
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
- sc = sa->full; /* the old screen to restore */
+ screen = area->full; /* the old screen to restore */
oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
- BLI_assert(BKE_workspace_layout_screen_get(layout_old) != sc);
+ BLI_assert(BKE_workspace_layout_screen_get(layout_old) != screen);
BLI_assert(BKE_workspace_layout_screen_get(layout_old)->state != SCREENNORMAL);
- sc->state = SCREENNORMAL;
- sc->flag = oldscreen->flag;
+ screen->state = SCREENNORMAL;
+ screen->flag = oldscreen->flag;
/* find old area to restore from */
ScrArea *fullsa = NULL;
- for (ScrArea *old = sc->areabase.first; old; old = old->next) {
+ LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
/* area to restore from is always first */
if (old->full && !fullsa) {
fullsa = old;
@@ -1254,7 +1304,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
old->full = NULL;
}
- sa->full = NULL;
+ area->full = NULL;
if (fullsa == NULL) {
if (G.debug & G_DEBUG) {
@@ -1265,23 +1315,22 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
if (state == SCREENFULL) {
/* unhide global areas */
- for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area;
- glob_area = glob_area->next) {
+ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
}
/* restore the old side panels/header visibility */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
region->flag = region->flagfullscreen;
}
}
- ED_area_data_swap(fullsa, sa);
+ ED_area_data_swap(fullsa, area);
/* animtimer back */
- sc->animtimer = oldscreen->animtimer;
+ screen->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- ED_screen_change(C, sc);
+ ED_screen_change(C, screen);
BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
@@ -1289,7 +1338,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
* screen handling as it uses the area coords which aren't updated yet.
* Without doing so, the screen handling gets wrong area coords,
* which in worst case can lead to crashes (see T43139) */
- sc->skip_handling = true;
+ screen->skip_handling = true;
}
else {
/* change from SCREENNORMAL to new state */
@@ -1306,32 +1355,31 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
- sc = BKE_workspace_layout_screen_get(layout_new);
- sc->state = state;
- sc->redraws_flag = oldscreen->redraws_flag;
- sc->temp = oldscreen->temp;
- sc->flag = oldscreen->flag;
+ screen = BKE_workspace_layout_screen_get(layout_new);
+ screen->state = state;
+ screen->redraws_flag = oldscreen->redraws_flag;
+ screen->temp = oldscreen->temp;
+ screen->flag = oldscreen->flag;
/* timer */
- sc->animtimer = oldscreen->animtimer;
+ screen->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!sa || sa->global) {
- sa = oldscreen->areabase.first;
+ if (!area || area->global) {
+ area = oldscreen->areabase.first;
}
- newa = (ScrArea *)sc->areabase.first;
+ newa = (ScrArea *)screen->areabase.first;
/* copy area */
- ED_area_data_swap(newa, sa);
- newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+ ED_area_data_swap(newa, area);
+ newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
if (state == SCREENFULL) {
/* temporarily hide global areas */
- for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area;
- glob_area = glob_area->next) {
+ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
}
/* temporarily hide the side panels/header */
@@ -1351,16 +1399,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
}
- sa->full = oldscreen;
+ area->full = oldscreen;
newa->full = oldscreen;
- ED_screen_change(C, sc);
+ ED_screen_change(C, screen);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
- CTX_wm_area_set(C, sc->areabase.first);
+ CTX_wm_area_set(C, screen->areabase.first);
- return sc->areabase.first;
+ return screen->areabase.first;
}
/**
@@ -1381,35 +1429,35 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
int display_type,
bool dialog)
{
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
switch (display_type) {
case USER_TEMP_SPACE_DISPLAY_WINDOW:
if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
}
break;
case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
- ScrArea *ctx_sa = CTX_wm_area(C);
+ ScrArea *ctx_area = CTX_wm_area(C);
- if (ctx_sa != NULL && ctx_sa->full) {
- sa = ctx_sa;
- ED_area_newspace(C, ctx_sa, space_type, true);
- sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
- ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
+ if (ctx_area != NULL && ctx_area->full) {
+ area = ctx_area;
+ ED_area_newspace(C, ctx_area, space_type, true);
+ area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
- else if (ctx_sa != NULL && ctx_sa->spacetype == space_type) {
- sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ else if (ctx_area != NULL && ctx_area->spacetype == space_type) {
+ area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED);
}
else {
- sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
- ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
+ area = ED_screen_full_newspace(C, ctx_area, (int)space_type);
+ ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
break;
}
}
- return sa;
+ return area;
}
/* update frame rate info for viewport drawing */
@@ -1487,12 +1535,12 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
char spacetype = -1;
- if (sa) {
- spacetype = sa->spacetype;
+ if (area) {
+ spacetype = area->spacetype;
}
sad->from_anim_edit = (ELEM(spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA));
@@ -1508,13 +1556,13 @@ void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
static ARegion *time_top_left_3dwindow(bScreen *screen)
{
ARegion *aret = NULL;
- ScrArea *sa;
+ ScrArea *area;
int min = 10000;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_VIEW3D) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
if (region->winrct.xmin - region->winrct.ymin < min) {
aret = region;
@@ -1552,11 +1600,11 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
if (camera && scene->camera != camera) {
- bScreen *sc;
+ bScreen *screen;
scene->camera = camera;
/* are there cameras in the views that are not in the scene? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc, scene);
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ BKE_screen_view3d_scene_sync(screen, scene);
}
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
}
@@ -1573,11 +1621,11 @@ void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
*/
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
- ScrArea *sa;
+ ScrArea *area;
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- switch (sa->spacetype) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ switch (area->spacetype) {
case SPACE_VIEW3D: {
View3D *v3d;
@@ -1585,10 +1633,10 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
if (rv3d->persp == RV3D_CAMOB) {
@@ -1604,7 +1652,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
/* images should always show in stereo, even if
* the file doesn't have views enabled */
- sima = sa->spacedata.first;
+ sima = area->spacedata.first;
if (sima->image && BKE_image_is_stereo(sima->image) &&
(sima->iuser.flag & IMA_SHOW_STEREO)) {
return true;
@@ -1618,7 +1666,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- snode = sa->spacedata.first;
+ snode = area->spacedata.first;
if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
return true;
}
@@ -1631,7 +1679,7 @@ bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
continue;
}
- sseq = sa->spacedata.first;
+ sseq = area->spacedata.first;
if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
return true;
}
@@ -1657,7 +1705,7 @@ Scene *ED_screen_scene_find_with_window(const bScreen *screen,
const wmWindowManager *wm,
struct wmWindow **r_window)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
if (r_window) {
*r_window = win;
@@ -1675,16 +1723,16 @@ ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
const bool only_visible)
{
if (only_visible) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacedata.first == sl) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacedata.first == sl) {
+ return area;
}
}
}
else {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (BLI_findindex(&sa->spacedata, sl) != -1) {
- return sa;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (BLI_findindex(&area->spacedata, sl) != -1) {
+ return area;
}
}
}
@@ -1698,7 +1746,7 @@ Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (WM_window_get_active_screen(win) == screen) {
return win;
}
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 25855382307..47580c2f4b3 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -57,9 +57,9 @@ ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
BLI_addtail(&area_map->vertbase, sv);
return sv;
}
-ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y)
+ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y)
{
- return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(sc), x, y);
+ return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(screen), x, y);
}
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
@@ -73,9 +73,9 @@ ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
BLI_addtail(&area_map->edgebase, se);
return se;
}
-ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2)
+ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2)
{
- return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(sc), v1, v2);
+ return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(screen), v1, v2);
}
bool screen_geom_edge_is_horizontal(ScrEdge *se)
@@ -92,11 +92,11 @@ ScrEdge *screen_geom_area_map_find_active_scredge(const ScrAreaMap *area_map,
const int mx,
const int my)
{
- int safety = U.widget_unit / 10;
+ int safety = BORDERPADDING;
CLAMP_MIN(safety, 2);
- for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
+ LISTBASE_FOREACH (ScrEdge *, se, &area_map->edgebase) {
if (screen_geom_edge_is_horizontal(se)) {
if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
short min, max;
@@ -153,7 +153,7 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
* * Ensure areas have a minimum height.
* * Correctly set global areas to their fixed height.
*/
-void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
{
rcti window_rect, screen_rect;
@@ -163,7 +163,6 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
const int screen_size_x = BLI_rcti_size_x(&screen_rect);
const int screen_size_y = BLI_rcti_size_y(&screen_rect);
ScrVert *sv = NULL;
- ScrArea *sa;
int screen_size_x_prev, screen_size_y_prev;
float min[2], max[2];
@@ -171,7 +170,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
min[0] = min[1] = 20000.0f;
max[0] = max[1] = 0.0f;
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
minmax_v2v2_v2(min, max, fv);
}
@@ -184,7 +183,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1);
/* make sure it fits! */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
sv->vec.x = screen_rect.xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
CLAMP(sv->vec.x, screen_rect.xmin, screen_rect.xmax - 1);
@@ -199,19 +198,19 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
if (facy > 1) {
/* Keep timeline small in video edit workspace. */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_ACTION && sa->v1->vec.y == screen_rect.ymin &&
- screen_geom_area_height(sa) <= headery * facy + 1) {
- ScrEdge *se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_ACTION && area->v1->vec.y == screen_rect.ymin &&
+ screen_geom_area_height(area) <= headery * facy + 1) {
+ ScrEdge *se = BKE_screen_find_edge(screen, area->v2, area->v3);
if (se) {
- const int yval = sa->v1->vec.y + headery - 1;
+ const int yval = area->v1->vec.y + headery - 1;
screen_geom_select_connected_edge(win, se);
/* all selected vertices get the right offset */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
/* if is a collapsed area */
- if (sv != sa->v1 && sv != sa->v4) {
+ if (sv != area->v1 && sv != area->v4) {
if (sv->flag) {
sv->vec.y = yval;
}
@@ -223,19 +222,19 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
}
if (facy < 1) {
/* make each window at least ED_area_headersize() high */
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (screen_geom_area_height(sa) < headery) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (screen_geom_area_height(area) < headery) {
/* lower edge */
- ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
- if (se && sa->v1 != sa->v2) {
- const int yval = sa->v2->vec.y - headery + 1;
+ ScrEdge *se = BKE_screen_find_edge(screen, area->v4, area->v1);
+ if (se && area->v1 != area->v2) {
+ const int yval = area->v2->vec.y - headery + 1;
screen_geom_select_connected_edge(win, se);
/* all selected vertices get the right offset */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
+ for (sv = screen->vertbase.first; sv; sv = sv->next) {
/* if is not a collapsed area */
- if (sv != sa->v2 && sv != sa->v3) {
+ if (sv != area->v2 && sv != area->v3) {
if (sv->flag) {
sv->vec.y = yval;
}
@@ -249,7 +248,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
/* Global areas have a fixed size that only changes with the DPI.
* Here we ensure that exactly this size is set. */
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
continue;
}
@@ -284,14 +283,14 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc)
/**
* \return 0 if no split is possible, otherwise the screen-coordinate at which to split.
*/
-short screen_geom_find_area_split_point(const ScrArea *sa,
+short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
float fac)
{
short x, y;
- const int cur_area_width = screen_geom_area_width(sa);
- const int cur_area_height = screen_geom_area_height(sa);
+ 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_y = ED_area_headersize();
int area_min;
@@ -308,43 +307,43 @@ short screen_geom_find_area_split_point(const ScrArea *sa,
CLAMP(fac, 0.0f, 1.0f);
if (dir == 'h') {
- y = sa->v1->vec.y + round_fl_to_short(fac * cur_area_height);
+ y = area->v1->vec.y + round_fl_to_short(fac * cur_area_height);
area_min = area_min_y;
- if (sa->v1->vec.y > window_rect->ymin) {
+ if (area->v1->vec.y > window_rect->ymin) {
area_min += U.pixelsize;
}
- if (sa->v2->vec.y < (window_rect->ymax - 1)) {
+ if (area->v2->vec.y < (window_rect->ymax - 1)) {
area_min += U.pixelsize;
}
- if (y - sa->v1->vec.y < area_min) {
- y = sa->v1->vec.y + area_min;
+ if (y - area->v1->vec.y < area_min) {
+ y = area->v1->vec.y + area_min;
}
- else if (sa->v2->vec.y - y < area_min) {
- y = sa->v2->vec.y - area_min;
+ else if (area->v2->vec.y - y < area_min) {
+ y = area->v2->vec.y - area_min;
}
return y;
}
else {
- x = sa->v1->vec.x + round_fl_to_short(fac * cur_area_width);
+ x = area->v1->vec.x + round_fl_to_short(fac * cur_area_width);
area_min = area_min_x;
- if (sa->v1->vec.x > window_rect->xmin) {
+ if (area->v1->vec.x > window_rect->xmin) {
area_min += U.pixelsize;
}
- if (sa->v4->vec.x < (window_rect->xmax - 1)) {
+ if (area->v4->vec.x < (window_rect->xmax - 1)) {
area_min += U.pixelsize;
}
- if (x - sa->v1->vec.x < area_min) {
- x = sa->v1->vec.x + area_min;
+ if (x - area->v1->vec.x < area_min) {
+ x = area->v1->vec.x + area_min;
}
- else if (sa->v4->vec.x - x < area_min) {
- x = sa->v4->vec.x - area_min;
+ else if (area->v4->vec.x - x < area_min) {
+ x = area->v4->vec.x - area_min;
}
return x;
@@ -356,7 +355,7 @@ short screen_geom_find_area_split_point(const ScrArea *sa,
*/
void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
{
- bScreen *sc = WM_window_get_active_screen(win);
+ bScreen *screen = WM_window_get_active_screen(win);
bool oneselected = true;
char dir;
@@ -370,7 +369,7 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
dir = 'h';
}
- ED_screen_verts_iter(win, sc, sv)
+ ED_screen_verts_iter(win, screen, sv)
{
sv->flag = 0;
}
@@ -380,7 +379,7 @@ void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge)
while (oneselected) {
oneselected = false;
- for (ScrEdge *se = sc->edgebase.first; se; se = se->next) {
+ LISTBASE_FOREACH (ScrEdge *, se, &screen->edgebase) {
if (se->v1->flag + se->v2->flag == 1) {
if (dir == 'h') {
if (se->v1->vec.y == se->v2->vec.y) {
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index e1a75e51cf2..2d42313d528 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -35,8 +35,13 @@ struct bContextDataResult;
#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
+#define AREAJOINTOLERANCE (1.0f * U.widget_unit) /* Edges must be close to allow joining. */
+
+/* Expanded interaction influence of area borders. */
+#define BORDERPADDING (U.dpi_fac + U.pixelsize)
+
/* area.c */
-void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free);
+void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free);
void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2);
void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade);
@@ -44,25 +49,26 @@ void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fad
bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
void screen_data_copy(bScreen *to, bScreen *from);
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new);
-void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc);
+void screen_change_update(struct bContext *C, wmWindow *win, bScreen *screen);
bScreen *screen_change_prepare(bScreen *screen_old,
bScreen *screen_new,
struct Main *bmain,
struct bContext *C,
wmWindow *win);
-ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
-int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2);
-int area_getorientation(ScrArea *sa, ScrArea *sb);
+ScrArea *area_split(
+ const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge);
+int screen_area_join(struct bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2);
+int area_getorientation(ScrArea *area, ScrArea *sb);
-struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]);
+struct AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2]);
/* screen_geometry.c */
int screen_geom_area_height(const ScrArea *area);
int screen_geom_area_width(const ScrArea *area);
ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y);
-ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y);
+ScrVert *screen_geom_vertex_add(bScreen *screen, short x, short y);
ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2);
-ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2);
+ScrEdge *screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2);
bool screen_geom_edge_is_horizontal(ScrEdge *se);
ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map,
const rcti *bounds_rect,
@@ -72,8 +78,8 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const bScreen *screen,
const int mx,
const int my);
-void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc);
-short screen_geom_find_area_split_point(const ScrArea *sa,
+void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen);
+short screen_geom_find_area_split_point(const ScrArea *area,
const rcti *window_rect,
char dir,
float fac);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f2f35f45d12..ace11ffe577 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -339,7 +339,7 @@ bool ED_operator_console_active(bContext *C)
return ed_spacetype_test(C, SPACE_CONSOLE);
}
-static bool ed_object_hidden(Object *ob)
+static bool ed_object_hidden(const Object *ob)
{
/* if hidden but in edit mode, we still display, can happen with animation */
return ((ob->restrictflag & OB_RESTRICT_VIEWPORT) && !(ob->mode & OB_MODE_EDIT));
@@ -351,10 +351,15 @@ bool ED_operator_object_active(bContext *C)
return ((ob != NULL) && !ed_object_hidden(ob));
}
+bool ED_operator_object_active_editable_ex(bContext *UNUSED(C), const Object *ob)
+{
+ return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+}
+
bool ED_operator_object_active_editable(bContext *C)
{
Object *ob = ED_object_active_context(C);
- return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob));
+ return ED_operator_object_active_editable_ex(C, ob);
}
bool ED_operator_object_active_editable_mesh(bContext *C)
@@ -590,20 +595,20 @@ bool ED_operator_editmball(bContext *C)
bool ED_operator_mask(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacedata.first) {
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacedata.first) {
+ switch (area->spacetype) {
case SPACE_CLIP: {
- SpaceClip *sc = sa->spacedata.first;
- return ED_space_clip_check_show_maskedit(sc);
+ SpaceClip *screen = area->spacedata.first;
+ return ED_space_clip_check_show_maskedit(screen);
}
case SPACE_SEQ: {
- SpaceSeq *sseq = sa->spacedata.first;
+ 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 = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
ViewLayer *view_layer = CTX_data_view_layer(C);
return ED_space_image_check_show_maskedit(sima, view_layer);
}
@@ -681,8 +686,8 @@ static bool actionzone_area_poll(bContext *C)
const int *xy = &win->eventstate->x;
AZone *az;
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (az = sa->actionzones.first; az; az = az->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ for (az = area->actionzones.first; az; az = az->next) {
if (BLI_rcti_isect_pt_v(&az->rect, xy)) {
return 1;
}
@@ -743,11 +748,11 @@ static bool azone_clipped_rect_calc(const AZone *az, rcti *r_rect_clip)
return false;
}
-static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const bool test_only)
+static AZone *area_actionzone_refresh_xy(ScrArea *area, const int xy[2], const bool test_only)
{
AZone *az = NULL;
- for (az = sa->actionzones.first; az; az = az->next) {
+ for (az = area->actionzones.first; az; az = az->next) {
rcti az_rect_clip;
if (BLI_rcti_isect_pt_v(&az->rect, xy) &&
/* Check clipping if this is clipped */
@@ -798,7 +803,7 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
}
/* XXX force redraw to show/hide the action zone */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
}
@@ -868,18 +873,18 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
else if (!test_only && !IS_EQF(az->alpha, 0.0f)) {
if (az->type == AZONE_FULLSCREEN) {
az->alpha = 0.0f;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
- ED_area_tag_redraw_no_rebuild(sa);
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ ED_area_tag_redraw_no_rebuild(area);
}
else if (az->type == AZONE_REGION_SCROLL) {
if (az->direction == AZ_SCROLL_VERT) {
az->alpha = az->region->v2d.alpha_vert = 0;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
ED_region_tag_redraw_no_rebuild(az->region);
}
else if (az->direction == AZ_SCROLL_HOR) {
az->alpha = az->region->v2d.alpha_hor = 0;
- sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
+ area->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
ED_region_tag_redraw_no_rebuild(az->region);
}
else {
@@ -893,10 +898,10 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
}
/* Finds an action-zone by position in entire screen so azones can overlap. */
-static AZone *screen_actionzone_find_xy(bScreen *sc, const int xy[2])
+static AZone *screen_actionzone_find_xy(bScreen *screen, const int xy[2])
{
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
- AZone *az = area_actionzone_refresh_xy(sa, xy, true);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ AZone *az = area_actionzone_refresh_xy(area, xy, true);
if (az != NULL) {
return az;
}
@@ -905,10 +910,10 @@ static AZone *screen_actionzone_find_xy(bScreen *sc, const int xy[2])
}
/* Returns the area that the azone belongs to */
-static ScrArea *screen_actionzone_area(bScreen *sc, const AZone *az)
+static ScrArea *screen_actionzone_area(bScreen *screen, const AZone *az)
{
- for (ScrArea *area = sc->areabase.first; area; area = area->next) {
- for (AZone *zone = area->actionzones.first; zone; zone = zone->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (AZone *, zone, &area->actionzones) {
if (zone == az) {
return area;
}
@@ -917,14 +922,14 @@ static ScrArea *screen_actionzone_area(bScreen *sc, const AZone *az)
return NULL;
}
-AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2])
+AZone *ED_area_actionzone_find_xy(ScrArea *area, const int xy[2])
{
- return area_actionzone_refresh_xy(sa, xy, true);
+ return area_actionzone_refresh_xy(area, xy, true);
}
-AZone *ED_area_azones_update(ScrArea *sa, const int xy[2])
+AZone *ED_area_azones_update(ScrArea *area, const int xy[2])
{
- return area_actionzone_refresh_xy(sa, xy, false);
+ return area_actionzone_refresh_xy(area, xy, false);
}
static void actionzone_exit(wmOperator *op)
@@ -968,8 +973,8 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
- AZone *az = screen_actionzone_find_xy(sc, &event->x);
+ bScreen *screen = CTX_wm_screen(C);
+ AZone *az = screen_actionzone_find_xy(screen, &event->x);
sActionzoneData *sad;
/* Quick escape - Scroll azones only hide/unhide the scroll-bars,
@@ -980,7 +985,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* ok we do the action-zone */
sad = op->customdata = MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
- sad->sa1 = screen_actionzone_area(sc, az);
+ sad->sa1 = screen_actionzone_area(screen, az);
sad->az = az;
sad->x = event->x;
sad->y = event->y;
@@ -1003,7 +1008,7 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sActionzoneData *sad = op->customdata;
switch (event->type) {
@@ -1044,9 +1049,9 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Have we dragged off the zone and are not on an edge? */
if ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
(screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL)) {
+ AREAMAP_FROM_SCREEN(screen), &screen_rect, event->x, event->y) == NULL)) {
/* Are we still in same area? */
- if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
+ if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
@@ -1081,7 +1086,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -1136,12 +1141,12 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
ScrArea **r_sa2)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ScrEdge *actedge;
rcti window_rect;
WM_window_rect_calc(win, &window_rect);
actedge = screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &window_rect, cursor[0], cursor[1]);
+ AREAMAP_FROM_SCREEN(screen), &window_rect, cursor[0], cursor[1]);
*r_sa1 = NULL;
*r_sa2 = NULL;
if (actedge == NULL) {
@@ -1150,12 +1155,12 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C,
int borderwidth = (4 * UI_DPI_FAC);
ScrArea *sa1, *sa2;
if (screen_geom_edge_is_horizontal(actedge)) {
- sa1 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
- sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
+ sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth);
+ sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth);
}
else {
- sa1 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
- sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
+ sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]);
+ sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]);
}
bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2)));
if (!isGlobal) {
@@ -1327,12 +1332,12 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
WorkSpaceLayout *layout_new;
bScreen *newsc;
- ScrArea *sa;
+ ScrArea *area;
rcti rect;
win = CTX_wm_window(C);
scene = CTX_data_scene(C);
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
/* XXX hrmf! */
if (event->type == EVT_ACTIONZONE_AREA) {
@@ -1342,11 +1347,11 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_PASS_THROUGH;
}
- sa = sad->sa1;
+ area = sad->sa1;
}
/* adds window to WM */
- rect = sa->totrct;
+ rect = area->totrct;
BLI_rcti_translate(&rect, win->posx, win->posy);
rect.xmax = rect.xmin + BLI_rcti_size_x(&rect) / U.pixelsize;
rect.ymax = rect.ymin + BLI_rcti_size_y(&rect) / U.pixelsize;
@@ -1371,7 +1376,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_set_active_layout(newwin, workspace, layout_new);
/* copy area to new screen */
- ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true);
+ ED_area_data_copy((ScrArea *)newsc->areabase.first, area, true);
ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
@@ -1454,8 +1459,12 @@ typedef struct sAreaMoveData {
/* helper call to move area-edge, sets limits
* need window bounds in order to get correct limits */
-static void area_move_set_limits(
- wmWindow *win, bScreen *sc, int dir, int *bigger, int *smaller, bool *use_bigger_smaller_snap)
+static void area_move_set_limits(wmWindow *win,
+ bScreen *screen,
+ int dir,
+ int *bigger,
+ int *smaller,
+ bool *use_bigger_smaller_snap)
{
rcti window_rect;
int areaminy = ED_area_headersize();
@@ -1466,7 +1475,7 @@ static void area_move_set_limits(
if (use_bigger_smaller_snap != NULL) {
*use_bigger_smaller_snap = false;
- for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
int size_min = ED_area_global_min_size_y(area) - 1;
int size_max = ED_area_global_max_size_y(area) - 1;
@@ -1507,25 +1516,25 @@ static void area_move_set_limits(
WM_window_rect_calc(win, &window_rect);
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
if (dir == 'h') {
int y1;
areamin = areaminy;
- if (sa->v1->vec.y > window_rect.ymin) {
+ if (area->v1->vec.y > window_rect.ymin) {
areamin += U.pixelsize;
}
- if (sa->v2->vec.y < (window_rect.ymax - 1)) {
+ if (area->v2->vec.y < (window_rect.ymax - 1)) {
areamin += U.pixelsize;
}
- y1 = screen_geom_area_height(sa) - areamin;
+ y1 = screen_geom_area_height(area) - areamin;
/* if top or down edge selected, test height */
- if (sa->v1->editflag && sa->v4->editflag) {
+ if (area->v1->editflag && area->v4->editflag) {
*bigger = min_ii(*bigger, y1);
}
- else if (sa->v2->editflag && sa->v3->editflag) {
+ else if (area->v2->editflag && area->v3->editflag) {
*smaller = min_ii(*smaller, y1);
}
}
@@ -1533,20 +1542,20 @@ static void area_move_set_limits(
int x1;
areamin = AREAMINX;
- if (sa->v1->vec.x > window_rect.xmin) {
+ if (area->v1->vec.x > window_rect.xmin) {
areamin += U.pixelsize;
}
- if (sa->v4->vec.x < (window_rect.xmax - 1)) {
+ if (area->v4->vec.x < (window_rect.xmax - 1)) {
areamin += U.pixelsize;
}
- x1 = screen_geom_area_width(sa) - areamin;
+ x1 = screen_geom_area_width(area) - areamin;
/* if left or right edge selected, test width */
- if (sa->v1->editflag && sa->v2->editflag) {
+ if (area->v1->editflag && area->v2->editflag) {
*bigger = min_ii(*bigger, x1);
}
- else if (sa->v3->editflag && sa->v4->editflag) {
+ else if (area->v3->editflag && area->v4->editflag) {
*smaller = min_ii(*smaller, x1);
}
}
@@ -1557,7 +1566,7 @@ static void area_move_set_limits(
/* return 0: init failed */
static int area_move_init(bContext *C, wmOperator *op)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
wmWindow *win = CTX_wm_window(C);
ScrEdge *actedge;
sAreaMoveData *md;
@@ -1568,7 +1577,7 @@ static int area_move_init(bContext *C, wmOperator *op)
y = RNA_int_get(op->ptr, "y");
/* setup */
- actedge = screen_geom_find_active_scredge(win, sc, x, y);
+ actedge = screen_geom_find_active_scredge(win, screen, x, y);
if (actedge == NULL) {
return 0;
}
@@ -1586,20 +1595,20 @@ static int area_move_init(bContext *C, wmOperator *op)
screen_geom_select_connected_edge(win, actedge);
/* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
- ED_screen_verts_iter(win, sc, v1)
+ ED_screen_verts_iter(win, screen, v1)
{
v1->editflag = v1->flag;
}
bool use_bigger_smaller_snap = false;
- area_move_set_limits(win, sc, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
+ area_move_set_limits(win, screen, md->dir, &md->bigger, &md->smaller, &use_bigger_smaller_snap);
md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
return 1;
}
-static int area_snap_calc_location(const bScreen *sc,
+static int area_snap_calc_location(const bScreen *screen,
const enum AreaMoveSnapType snap_type,
const int delta,
const int origval,
@@ -1657,13 +1666,13 @@ static int area_snap_calc_location(const bScreen *sc,
}
}
- for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ LISTBASE_FOREACH (const ScrVert *, v1, &screen->vertbase) {
if (!v1->editflag) {
continue;
}
const int v_loc = (&v1->vec.x)[!axis];
- for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+ LISTBASE_FOREACH (const ScrVert *, v2, &screen->vertbase) {
if (v2->editflag) {
continue;
}
@@ -1702,7 +1711,7 @@ static void area_move_apply_do(const bContext *C,
const enum AreaMoveSnapType snap_type)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
short final_loc = -1;
bool doredraw = false;
@@ -1714,13 +1723,13 @@ static void area_move_apply_do(const bContext *C,
final_loc = origval + delta;
}
else {
- final_loc = area_snap_calc_location(sc, snap_type, delta, origval, dir, bigger, smaller);
+ final_loc = area_snap_calc_location(screen, snap_type, delta, origval, dir, bigger, smaller);
}
BLI_assert(final_loc != -1);
short axis = (dir == 'v') ? 0 : 1;
- ED_screen_verts_iter(win, sc, v1)
+ ED_screen_verts_iter(win, screen, v1)
{
if (v1->editflag) {
short oldval = (&v1->vec.x)[axis];
@@ -1737,29 +1746,27 @@ static void area_move_apply_do(const bContext *C,
/* only redraw if we actually moved a screen vert, for AREAGRID */
if (doredraw) {
bool redraw_all = false;
- ED_screen_areas_iter(win, sc, sa)
- {
- if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
- if (ED_area_is_global(sa)) {
+ ED_screen_areas_iter (win, screen, area) {
+ if (area->v1->editflag || area->v2->editflag || area->v3->editflag || area->v4->editflag) {
+ if (ED_area_is_global(area)) {
/* Snap to minimum or maximum for global areas. */
- int height = round_fl_to_int(screen_geom_area_height(sa) / UI_DPI_FAC);
- if (abs(height - sa->global->size_min) < abs(height - sa->global->size_max)) {
- sa->global->cur_fixed_height = sa->global->size_min;
+ int height = round_fl_to_int(screen_geom_area_height(area) / UI_DPI_FAC);
+ if (abs(height - area->global->size_min) < abs(height - area->global->size_max)) {
+ area->global->cur_fixed_height = area->global->size_min;
}
else {
- sa->global->cur_fixed_height = sa->global->size_max;
+ area->global->cur_fixed_height = area->global->size_max;
}
- sc->do_refresh = true;
+ screen->do_refresh = true;
redraw_all = true;
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
if (redraw_all) {
- ED_screen_areas_iter(win, sc, sa)
- {
- ED_area_tag_redraw(sa);
+ ED_screen_areas_iter (win, screen, area) {
+ ED_area_tag_redraw(area);
}
}
@@ -1767,7 +1774,7 @@ static void area_move_apply_do(const bContext *C,
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
/* Update preview thumbnail */
- BKE_icon_changed(sc->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
}
}
@@ -1984,13 +1991,13 @@ static int area_split_menu_init(bContext *C, wmOperator *op)
/* generic init, no UI stuff here, assumes active area */
static int area_split_init(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
sAreaSplitData *sd;
int areaminy = ED_area_headersize();
int dir;
/* required context */
- if (sa == NULL) {
+ if (area == NULL) {
return 0;
}
@@ -1998,10 +2005,10 @@ static int area_split_init(bContext *C, wmOperator *op)
dir = RNA_enum_get(op->ptr, "direction");
/* minimal size */
- if (dir == 'v' && sa->winx < 2 * AREAMINX) {
+ if (dir == 'v' && area->winx < 2 * AREAMINX) {
return 0;
}
- if (dir == 'h' && sa->winy < 2 * areaminy) {
+ if (dir == 'h' && area->winy < 2 * areaminy) {
return 0;
}
@@ -2009,42 +2016,42 @@ static int area_split_init(bContext *C, wmOperator *op)
sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split");
op->customdata = sd;
- sd->sarea = sa;
+ sd->sarea = area;
if (dir == 'v') {
- sd->origmin = sa->v1->vec.x;
- sd->origsize = sa->v4->vec.x - sd->origmin;
+ sd->origmin = area->v1->vec.x;
+ sd->origsize = area->v4->vec.x - sd->origmin;
}
else {
- sd->origmin = sa->v1->vec.y;
- sd->origsize = sa->v2->vec.y - sd->origmin;
+ sd->origmin = area->v1->vec.y;
+ sd->origsize = area->v2->vec.y - sd->origmin;
}
return 1;
}
-/* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
+/* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
/* used with split operator */
-static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
+static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *area, ScrArea *sb)
{
- ScrVert *sav1 = sa->v1;
- ScrVert *sav2 = sa->v2;
- ScrVert *sav3 = sa->v3;
- ScrVert *sav4 = sa->v4;
+ ScrVert *sav1 = area->v1;
+ ScrVert *sav2 = area->v2;
+ ScrVert *sav3 = area->v3;
+ ScrVert *sav4 = area->v4;
ScrVert *sbv1 = sb->v1;
ScrVert *sbv2 = sb->v2;
ScrVert *sbv3 = sb->v3;
ScrVert *sbv4 = sb->v4;
- if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
+ if (sav1 == sbv4 && sav2 == sbv3) { /* area to right of sb = W */
return BKE_screen_find_edge(screen, sav1, sav2);
}
- else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
+ else if (sav2 == sbv1 && sav3 == sbv4) { /* area to bottom of sb = N */
return BKE_screen_find_edge(screen, sav2, sav3);
}
- else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
+ else if (sav3 == sbv2 && sav4 == sbv1) { /* area to left of sb = E */
return BKE_screen_find_edge(screen, sav3, sav4);
}
- else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
+ else if (sav1 == sbv2 && sav4 == sbv3) { /* area on top of sb = S*/
return BKE_screen_find_edge(screen, sav1, sav4);
}
@@ -2055,7 +2062,7 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
static int area_split_apply(bContext *C, wmOperator *op)
{
const wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sAreaSplitData *sd = (sAreaSplitData *)op->customdata;
float fac;
int dir;
@@ -2063,13 +2070,13 @@ static int area_split_apply(bContext *C, wmOperator *op)
fac = RNA_float_get(op->ptr, "factor");
dir = RNA_enum_get(op->ptr, "direction");
- sd->narea = area_split(win, sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
+ sd->narea = area_split(win, screen, sd->sarea, dir, fac, 0); /* 0 = no merge */
if (sd->narea) {
- sd->nedge = area_findsharededge(sc, sd->sarea, sd->narea);
+ sd->nedge = area_findsharededge(screen, sd->sarea, sd->narea);
/* select newly created edge, prepare for moving edge */
- ED_screen_verts_iter(win, sc, sv)
+ ED_screen_verts_iter(win, screen, sv)
{
sv->editflag = 0;
}
@@ -2089,7 +2096,7 @@ static int area_split_apply(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
/* Update preview thumbnail */
- BKE_icon_changed(sc->id.icon_id);
+ BKE_icon_changed(screen->id.icon_id);
return 1;
}
@@ -2137,12 +2144,12 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
sAreaSplitData *sd;
int dir;
/* no full window splitting allowed */
- BLI_assert(sc->state == SCREENNORMAL);
+ BLI_assert(screen->state == SCREENNORMAL);
PropertyRNA *prop_dir = RNA_struct_find_property(op->ptr, "direction");
PropertyRNA *prop_factor = RNA_struct_find_property(op->ptr, "factor");
@@ -2198,18 +2205,18 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else if (RNA_property_is_set(op->ptr, prop_dir)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa == NULL) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area == NULL) {
return OPERATOR_CANCELLED;
}
dir = RNA_property_enum_get(op->ptr, prop_dir);
if (dir == 'h') {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->x - sa->v1->vec.x)) / (float)sa->winx);
+ op->ptr, prop_factor, ((float)(event->x - area->v1->vec.x)) / (float)area->winx);
}
else {
RNA_property_float_set(
- op->ptr, prop_factor, ((float)(event->y - sa->v1->vec.y)) / (float)sa->winy);
+ op->ptr, prop_factor, ((float)(event->y - area->v1->vec.y)) / (float)area->winy);
}
if (!area_split_init(C, op)) {
@@ -2232,7 +2239,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_window_rect_calc(win, &window_rect);
actedge = screen_geom_area_map_find_active_scredge(
- AREAMAP_FROM_SCREEN(sc), &window_rect, event_co[0], event_co[1]);
+ AREAMAP_FROM_SCREEN(screen), &window_rect, event_co[0], event_co[1]);
if (actedge == NULL) {
return OPERATOR_CANCELLED;
}
@@ -2253,7 +2260,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* do the split */
if (area_split_apply(C, op)) {
- area_move_set_limits(win, sc, dir, &sd->bigger, &sd->smaller, NULL);
+ area_move_set_limits(win, screen, dir, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
G.moving |= G_TRANSFORM_WM;
@@ -2389,18 +2396,18 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
if (sd->sarea) {
- ScrArea *sa = sd->sarea;
+ ScrArea *area = sd->sarea;
if (dir == 'v') {
- sd->origmin = sa->v1->vec.x;
- sd->origsize = sa->v4->vec.x - sd->origmin;
+ sd->origmin = area->v1->vec.x;
+ sd->origsize = area->v4->vec.x - sd->origmin;
}
else {
- sd->origmin = sa->v1->vec.y;
- sd->origsize = sa->v2->vec.y - sd->origmin;
+ sd->origmin = area->v1->vec.y;
+ sd->origsize = area->v2->vec.y - sd->origmin;
}
if (sd->do_snap) {
- sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1;
+ area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 1;
const int snap_loc = area_snap_calc_location(CTX_wm_screen(C),
SNAP_FRACTION_AND_ADJACENT,
@@ -2410,7 +2417,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->origmin + sd->origsize,
-sd->origmin);
- sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0;
+ area->v1->editflag = area->v2->editflag = area->v3->editflag = area->v4->editflag = 0;
sd->delta = snap_loc - sd->origval;
}
@@ -2465,7 +2472,7 @@ static void SCREEN_OT_area_split(wmOperatorType *ot)
typedef struct RegionMoveData {
AZone *az;
ARegion *region;
- ScrArea *sa;
+ ScrArea *area;
int bigger, smaller, origval;
int origx, origy;
int maxsize;
@@ -2473,7 +2480,7 @@ typedef struct RegionMoveData {
} RegionMoveData;
-static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
+static int area_max_regionsize(ScrArea *area, ARegion *scalear, AZEdge edge)
{
int dist;
@@ -2492,15 +2499,15 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
}
else {
if (edge == AE_RIGHT_TO_TOPLEFT || edge == AE_LEFT_TO_TOPRIGHT) {
- dist = BLI_rcti_size_x(&sa->totrct);
+ dist = BLI_rcti_size_x(&area->totrct);
}
else { /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
- dist = BLI_rcti_size_y(&sa->totrct);
+ dist = BLI_rcti_size_y(&area->totrct);
}
/* subtractwidth of regions on opposite side
* prevents dragging regions into other opposite regions */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region == scalear) {
continue;
}
@@ -2574,11 +2581,11 @@ static int region_scale_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
rmd->region = az->region;
}
- rmd->sa = sad->sa1;
+ rmd->area = sad->sa1;
rmd->edge = az->edge;
rmd->origx = event->x;
rmd->origy = event->y;
- rmd->maxsize = area_max_regionsize(rmd->sa, rmd->region, rmd->edge);
+ rmd->maxsize = area_max_regionsize(rmd->area, rmd->region, rmd->edge);
/* if not set we do now, otherwise it uses type */
if (rmd->region->sizex == 0) {
@@ -2641,11 +2648,11 @@ static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
if ((rmd->region->flag & RGN_FLAG_HIDDEN) == 0) {
if (rmd->region->regiontype == RGN_TYPE_HEADER) {
- ARegion *ar_tool_header = BKE_area_find_region_type(rmd->sa, RGN_TYPE_TOOL_HEADER);
- if (ar_tool_header != NULL) {
- if ((ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
- (ar_tool_header->flag & RGN_FLAG_HIDDEN) != 0) {
- region_toggle_hidden(C, ar_tool_header, 0);
+ ARegion *region_tool_header = BKE_area_find_region_type(rmd->area, RGN_TYPE_TOOL_HEADER);
+ if (region_tool_header != NULL) {
+ if ((region_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
+ (region_tool_header->flag & RGN_FLAG_HIDDEN) != 0) {
+ region_toggle_hidden(C, region_tool_header, 0);
}
}
}
@@ -2732,7 +2739,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
rmd->region->sizey = rmd->origval;
}
}
- ED_area_tag_redraw(rmd->sa);
+ ED_area_tag_redraw(rmd->area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
break;
@@ -2747,7 +2754,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
region_scale_validate_size(rmd);
}
- ED_area_tag_redraw(rmd->sa);
+ ED_area_tag_redraw(rmd->area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -2794,19 +2801,19 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot)
static void areas_do_frame_follow(bContext *C, bool middle)
{
- bScreen *scr = CTX_wm_screen(C);
+ bScreen *screen_ctx = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
- for (wmWindow *window = wm->windows.first; window; window = window->next) {
+ LISTBASE_FOREACH (wmWindow *, window, &wm->windows) {
const bScreen *screen = WM_window_get_active_screen(window);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
/* do follow here if editor type supports it */
- if ((scr->redraws_flag & TIME_FOLLOW)) {
+ if ((screen_ctx->redraws_flag & TIME_FOLLOW)) {
if ((region->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
- (sa->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
+ ELEM(area->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
+ (area->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
float w = BLI_rctf_size_x(&region->v2d.cur);
if (middle) {
@@ -3155,32 +3162,32 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
static int screen_maximize_area_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
/* search current screen for 'fullscreen' areas */
/* prevents restoring info header, when mouse is over it */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->full) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->full) {
break;
}
}
- if (sa == NULL) {
- sa = CTX_wm_area(C);
+ if (area == NULL) {
+ area = CTX_wm_area(C);
}
if (hide_panels) {
if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
return OPERATOR_CANCELLED;
}
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENFULL);
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENFULL);
}
else {
if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
return OPERATOR_CANCELLED;
}
- ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENMAXIMIZED);
}
return OPERATOR_FINISHED;
@@ -3381,7 +3388,7 @@ static void area_join_cancel(bContext *C, wmOperator *op)
/* modal callback while selecting area (space) that will be removed */
static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
wmWindow *win = CTX_wm_window(C);
sAreaJoinData *jd;
@@ -3396,24 +3403,24 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE: {
- ScrArea *sa = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
int dir = -1;
- if (sa) {
- if (jd->sa1 != sa) {
- dir = area_getorientation(jd->sa1, sa);
+ if (area) {
+ if (jd->sa1 != area) {
+ dir = area_getorientation(jd->sa1, area);
if (dir != -1) {
- jd->sa2 = sa;
+ jd->sa2 = area;
}
else {
/* we are not bordering on the previously selected area
* we check if area has common border with the one marked for removal
* in this case we can swap areas.
*/
- dir = area_getorientation(sa, jd->sa2);
+ dir = area_getorientation(area, jd->sa2);
if (dir != -1) {
jd->sa1 = jd->sa2;
- jd->sa2 = sa;
+ jd->sa2 = area;
}
else {
jd->sa2 = NULL;
@@ -3426,16 +3433,16 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
* we swap the areas if possible to allow user to choose */
if (jd->sa2 != NULL) {
jd->sa1 = jd->sa2;
- jd->sa2 = sa;
+ jd->sa2 = area;
dir = area_getorientation(jd->sa1, jd->sa2);
if (dir == -1) {
printf("oops, didn't expect that!\n");
}
}
else {
- dir = area_getorientation(jd->sa1, sa);
+ dir = area_getorientation(jd->sa1, area);
if (dir != -1) {
- jd->sa2 = sa;
+ jd->sa2 = area;
}
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -3612,18 +3619,18 @@ static int spacedata_cleanup_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
bScreen *screen;
- ScrArea *sa;
+ ScrArea *area;
int tot = 0;
for (screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacedata.first != sa->spacedata.last) {
- SpaceLink *sl = sa->spacedata.first;
-
- BLI_remlink(&sa->spacedata, sl);
- tot += BLI_listbase_count(&sa->spacedata);
- BKE_spacedata_freelist(&sa->spacedata);
- BLI_addtail(&sa->spacedata, sl);
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacedata.first != area->spacedata.last) {
+ SpaceLink *sl = area->spacedata.first;
+
+ BLI_remlink(&area->spacedata, sl);
+ tot += BLI_listbase_count(&area->spacedata);
+ BKE_spacedata_freelist(&area->spacedata);
+ BLI_addtail(&area->spacedata, sl);
}
}
}
@@ -3809,7 +3816,7 @@ static void view3d_localview_update_rv3d(struct RegionView3D *rv3d)
}
static void region_quadview_init_rv3d(
- ScrArea *sa, ARegion *region, const char viewlock, const char view, const char persp)
+ ScrArea *area, ARegion *region, const char viewlock, const char view, const char persp)
{
RegionView3D *rv3d = region->regiondata;
@@ -3826,7 +3833,7 @@ static void region_quadview_init_rv3d(
ED_view3d_lock(rv3d);
view3d_localview_update_rv3d(rv3d);
if ((viewlock & RV3D_BOXCLIP) && (persp == RV3D_ORTHO)) {
- ED_view3d_quadview_update(sa, region, true);
+ ED_view3d_quadview_update(area, region, true);
}
}
@@ -3841,24 +3848,24 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
}
else if (region->alignment == RGN_ALIGN_QSPLIT) {
/* Exit quad-view */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *arn;
/* keep current region */
region->alignment = 0;
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar_iter;
+ if (area->spacetype == SPACE_VIEW3D) {
+ ARegion *region_iter;
RegionView3D *rv3d = region->regiondata;
/* if this is a locked view, use settings from 'User' view */
if (rv3d->viewlock) {
View3D *v3d_user;
- ARegion *ar_user;
+ ARegion *region_user;
- if (ED_view3d_context_user_region(C, &v3d_user, &ar_user)) {
- if (region != ar_user) {
- SWAP(void *, region->regiondata, ar_user->regiondata);
+ if (ED_view3d_context_user_region(C, &v3d_user, &region_user)) {
+ if (region != region_user) {
+ SWAP(void *, region->regiondata, region_user->regiondata);
rv3d = region->regiondata;
}
}
@@ -3866,24 +3873,27 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
rv3d->viewlock_quad = RV3D_VIEWLOCK_INIT;
rv3d->viewlock = 0;
- rv3d->rflag &= ~RV3D_CLIPPING;
+
+ /* FIXME: This fixes missing update to workbench TAA. (see T76216)
+ * However, it would be nice if the tagging should be done in a more conventional way. */
+ rv3d->rflag |= RV3D_GPULIGHT_UPDATE;
/* Accumulate locks, in case they're mixed. */
- for (ar_iter = sa->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
- if (ar_iter->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d_iter = ar_iter->regiondata;
+ for (region_iter = area->regionbase.first; region_iter; region_iter = region_iter->next) {
+ if (region_iter->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d_iter = region_iter->regiondata;
rv3d->viewlock_quad |= rv3d_iter->viewlock;
}
}
}
- for (region = sa->regionbase.first; region; region = arn) {
+ for (region = area->regionbase.first; region; region = arn) {
arn = region->next;
if (region->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_remove(C, sa, region);
+ ED_region_remove(C, area, region);
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
else if (region->next) {
@@ -3891,20 +3901,20 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
}
else {
/* Enter quad-view */
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *newar;
int count;
region->alignment = RGN_ALIGN_QSPLIT;
for (count = 0; count < 3; count++) {
- newar = BKE_area_region_copy(sa->type, region);
- BLI_addtail(&sa->regionbase, newar);
+ newar = BKE_area_region_copy(area->type, region);
+ BLI_addtail(&area->regionbase, newar);
}
/* lock views and set them */
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
int index_qsplit = 0;
/* run ED_view3d_lock() so the correct 'rv3d->viewquat' is set,
@@ -3919,13 +3929,13 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
RV3D_LOCK_ROTATION;
region_quadview_init_rv3d(
- sa, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
- region_quadview_init_rv3d(sa,
+ area, region, viewlock, ED_view3d_lock_view_from_index(index_qsplit++), RV3D_ORTHO);
+ region_quadview_init_rv3d(area,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
RV3D_ORTHO);
- region_quadview_init_rv3d(sa,
+ region_quadview_init_rv3d(area,
(region = region->next),
viewlock,
ED_view3d_lock_view_from_index(index_qsplit++),
@@ -3933,16 +3943,16 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
/* forcing camera is distracting */
#if 0
if (v3d->camera) {
- region_quadview_init_rv3d(sa, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
+ region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_CAMERA, RV3D_CAMOB);
}
else {
- region_quadview_init_rv3d(sa, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
+ region_quadview_init_rv3d(area, (region = region->next), 0, RV3D_VIEW_USER, RV3D_PERSP);
}
#else
(void)v3d;
#endif
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
}
@@ -4091,11 +4101,11 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
/* show/hide header text menus */
static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- sa->flag = sa->flag ^ HEADER_NO_PULLDOWN;
+ area->flag = area->flag ^ HEADER_NO_PULLDOWN;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
return OPERATOR_FINISHED;
@@ -4122,42 +4132,42 @@ static void SCREEN_OT_header_toggle_menus(wmOperatorType *ot)
static bool screen_region_context_menu_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa && sa->spacetype != SPACE_STATUSBAR);
+ ScrArea *area = CTX_wm_area(C);
+ return (area && area->spacetype != SPACE_STATUSBAR);
}
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_TOP) ?
IFACE_("Flip to Bottom") :
IFACE_("Flip to Top");
{
PointerRNA ptr;
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
- if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first, &ptr);
+ if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
uiItemR(layout, &ptr, "show_region_header", 0, IFACE_("Show Header"), ICON_NONE);
}
- ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
uiLayout *col = uiLayoutColumn(layout, 0);
- uiLayoutSetActive(col, (ar_header->flag & RGN_FLAG_HIDDEN) == 0);
+ uiLayoutSetActive(col, (region_header->flag & RGN_FLAG_HIDDEN) == 0);
- if (BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER)) {
+ if (BKE_area_find_region_type(area, RGN_TYPE_TOOL_HEADER)) {
uiItemR(col, &ptr, "show_region_tool_header", 0, IFACE_("Show Tool Settings"), ICON_NONE);
}
uiItemO(col,
IFACE_("Show Menus"),
- (sa->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
+ (area->flag & HEADER_NO_PULLDOWN) ? ICON_CHECKBOX_DEHLT : ICON_CHECKBOX_HLT,
"SCREEN_OT_header_toggle_menus");
}
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
- if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_TOPBAR)) {
uiItemS(layout);
uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
@@ -4165,24 +4175,24 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
/* File browser should be fullscreen all the time, top-bar should
* never be. But other regions can be maximized/restored. */
- if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
uiItemS(layout);
- const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
const char *but_flip_str = (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) == RGN_ALIGN_TOP) ?
IFACE_("Flip to Bottom") :
IFACE_("Flip to Top");
{
PointerRNA ptr;
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, area->spacedata.first, &ptr);
uiItemR(layout, &ptr, "show_region_footer", 0, IFACE_("Show Footer"), ICON_NONE);
}
@@ -4193,10 +4203,10 @@ void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UN
/* File browser should be fullscreen all the time, top-bar should
* never be. But other regions can be maximized/restored... */
- if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ if (!ELEM(area->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
uiItemS(layout);
- const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ const char *but_str = area->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
@@ -4383,9 +4393,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window;
- ScrArea *sa;
+ ScrArea *area;
int sync;
- float time;
+ double time;
/* sync, don't sync, or follow scene setting */
if (sad->flag & ANIMPLAY_FLAG_SYNC) {
@@ -4408,7 +4418,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
isfinite(time = BKE_sound_sync_scene(scene_eval))) {
- double newfra = (double)time * FPS;
+ double newfra = time * FPS;
/* give some space here to avoid jumps */
if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) {
@@ -4432,10 +4442,29 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
else {
if (sync) {
- /* note: this is very simplistic,
- * its has problem that it may skip too many frames.
- * however at least this gives a less jittery playback */
- const int step = max_ii(1, floor((wt->duration - sad->last_duration) * FPS));
+ /* Try to keep the playback in realtime by dropping frames. */
+
+ /* How much time (in frames) has passed since the last frame was drawn? */
+ double delta_frames = wt->delta * FPS;
+
+ /* Add the remaining fraction from the last time step. */
+ delta_frames += sad->lagging_frame_count;
+
+ if (delta_frames < 1.0) {
+ /* We can render faster than the scene frame rate. However skipping or delaying frames
+ * here seems to in practice lead to jittery playback so just step forward a minimum of
+ * one frame. (Even though this can lead to too fast playback, the jitteryness is more
+ * annoying)
+ */
+ delta_frames = 1.0f;
+ sad->lagging_frame_count = 0;
+ }
+ else {
+ /* Extract the delta frame fractions that will be skipped when converting to int. */
+ sad->lagging_frame_count = delta_frames - (int)delta_frames;
+ }
+
+ const int step = delta_frames;
/* skip frames */
if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
@@ -4456,8 +4485,6 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
}
- sad->last_duration = wt->duration;
-
/* reset 'jumped' flag before checking if we need to jump... */
sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
@@ -4514,15 +4541,15 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
for (window = wm->windows.first; window; window = window->next) {
const bScreen *win_screen = WM_window_get_active_screen(window);
- for (sa = win_screen->areabase.first; sa; sa = sa->next) {
+ for (area = win_screen->areabase.first; area; area = area->next) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
bool redraw = false;
if (region == sad->region) {
redraw = true;
}
else if (match_region_with_redraws(
- sa->spacetype, region->regiontype, sad->redraws, sad->from_anim_edit)) {
+ area->spacetype, region->regiontype, sad->redraws, sad->from_anim_edit)) {
redraw = true;
}
@@ -4531,8 +4558,8 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
/* do follow here if editor type supports it */
if ((sad->redraws & TIME_FOLLOW)) {
if ((region->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
- (sa->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
+ ELEM(area->spacetype, SPACE_SEQ, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA)) ||
+ (area->spacetype == SPACE_CLIP && region->regiontype == RGN_TYPE_PREVIEW)) {
float w = BLI_rctf_size_x(&region->v2d.cur);
if (scene->r.cfra < region->v2d.cur.xmin) {
region->v2d.cur.xmax = scene->r.cfra;
@@ -4591,7 +4618,7 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
/* find window that owns the animation timer */
bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer || screen->scrubbing) {
@@ -4604,7 +4631,7 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm)
bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm)
{
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
if (screen->animtimer) {
@@ -4803,20 +4830,20 @@ static void SCREEN_OT_box_select(wmOperatorType *ot)
static int fullscreen_back_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = NULL;
+ ScrArea *area = NULL;
/* search current screen for 'fullscreen' areas */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->full) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->full) {
break;
}
}
- if (!sa) {
+ if (!area) {
BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
return OPERATOR_CANCELLED;
}
- ED_screen_full_prevspace(C, sa);
+ ED_screen_full_prevspace(C, area);
return OPERATOR_FINISHED;
}
@@ -4839,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
/** \name Show User Preferences Operator
* \{ */
-static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int userpref_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC;
int sizey = 520 * UI_DPI_FAC;
@@ -4877,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_userpref_show";
/* api callbacks */
- ot->invoke = userpref_show_invoke;
+ ot->exec = userpref_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4887,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
/** \name Show Drivers Editor Operator
* \{ */
-static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int drivers_editor_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
PointerRNA ptr = {NULL};
PropertyRNA *prop = NULL;
int index = -1;
@@ -4919,7 +4952,7 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
+ fcu = BKE_fcurve_find_by_rna_context_ui(C, &ptr, prop, index, NULL, NULL, &driven, &special);
if (fcu) {
/* Isolate this F-Curve... */
bAnimContext ac;
@@ -4952,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_drivers_editor_show";
/* api callbacks */
- ot->invoke = drivers_editor_show_invoke;
+ ot->exec = drivers_editor_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -4962,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
/** \name Show Info Log Operator
* \{ */
-static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int info_log_show_exec(bContext *C, wmOperator *op)
{
+ wmWindow *win_cur = CTX_wm_window(C);
+ /* Use eventstate, not event from _invoke, so this can be called through exec(). */
+ const wmEvent *event = win_cur->eventstate;
int sizex = 900 * UI_DPI_FAC;
int sizey = 580 * UI_DPI_FAC;
int shift_y = 480;
@@ -4993,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot)
ot->idname = "SCREEN_OT_info_log_show";
/* api callbacks */
- ot->invoke = info_log_show_invoke;
+ ot->exec = info_log_show_exec;
ot->poll = ED_operator_screenactive;
}
@@ -5037,9 +5073,9 @@ static void SCREEN_OT_new(wmOperatorType *ot)
static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
WorkSpace *workspace = CTX_wm_workspace(C);
- WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
@@ -5069,8 +5105,8 @@ static void SCREEN_OT_delete(wmOperatorType *ot)
* \{ */
typedef struct RegionAlphaInfo {
- ScrArea *sa;
- ARegion *region, *child_ar; /* other region */
+ ScrArea *area;
+ ARegion *region, *child_region; /* other region */
int hidden;
} RegionAlphaInfo;
@@ -5107,8 +5143,8 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
/* always send redraw */
ED_region_tag_redraw(region);
- if (rgi->child_ar) {
- ED_region_tag_redraw(rgi->child_ar);
+ if (rgi->child_region) {
+ ED_region_tag_redraw(rgi->child_region);
}
/* if running timer was hiding, the flag toggle went wrong */
@@ -5120,10 +5156,10 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
else {
if (rgi->hidden) {
rgi->region->flag |= rgi->hidden;
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), rgi->sa);
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), rgi->area);
}
/* area decoration needs redraw in end */
- ED_area_tag_redraw(rgi->sa);
+ ED_area_tag_redraw(rgi->area);
}
WM_event_remove_timer(CTX_wm_manager(C), NULL, region->regiontimer); /* frees rgi */
region->regiontimer = NULL;
@@ -5131,7 +5167,7 @@ static void region_blend_end(bContext *C, ARegion *region, const bool is_running
/**
* \note Assumes that \a region itself is not a split version from previous region.
*/
-void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegion *region)
+void ED_region_visibility_change_update_animated(bContext *C, ScrArea *area, ARegion *region)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -5145,13 +5181,13 @@ void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegi
rgi = MEM_callocN(sizeof(RegionAlphaInfo), "RegionAlphaInfo");
rgi->hidden = region->flag & RGN_FLAG_HIDDEN;
- rgi->sa = sa;
+ rgi->area = area;
rgi->region = region;
region->flag &= ~RGN_FLAG_HIDDEN;
/* blend in, reinitialize regions because it got unhidden */
if (rgi->hidden == 0) {
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
else {
WM_event_remove_handlers(C, &region->handlers);
@@ -5159,7 +5195,7 @@ void ED_region_visibility_change_update_animated(bContext *C, ScrArea *sa, ARegi
if (region->next) {
if (region->next->alignment & RGN_SPLIT_PREV) {
- rgi->child_ar = region->next;
+ rgi->child_region = region->next;
}
}
@@ -5183,8 +5219,8 @@ static int region_blend_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
/* always send redraws */
ED_region_tag_redraw(rgi->region);
- if (rgi->child_ar) {
- ED_region_tag_redraw(rgi->child_ar);
+ if (rgi->child_region) {
+ ED_region_tag_redraw(rgi->child_region);
}
/* end timer? */
@@ -5220,8 +5256,8 @@ static void SCREEN_OT_region_blend(wmOperatorType *ot)
static bool space_type_set_or_cycle_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- return (sa && !ELEM(sa->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
+ ScrArea *area = CTX_wm_area(C);
+ return (area && !ELEM(area->spacetype, SPACE_TOPBAR, SPACE_STATUSBAR));
}
static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
@@ -5229,12 +5265,12 @@ static int space_type_set_or_cycle_exec(bContext *C, wmOperator *op)
const int space_type = RNA_enum_get(op->ptr, "space_type");
PointerRNA ptr;
- ScrArea *sa = CTX_wm_area(C);
- RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, sa, &ptr);
+ ScrArea *area = CTX_wm_area(C);
+ RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Area, area, &ptr);
PropertyRNA *prop_type = RNA_struct_find_property(&ptr, "type");
PropertyRNA *prop_ui_type = RNA_struct_find_property(&ptr, "ui_type");
- if (sa->spacetype != space_type) {
+ if (area->spacetype != space_type) {
/* Set the type. */
RNA_property_enum_set(&ptr, prop_type, space_type);
RNA_property_update(C, &ptr, prop_type);
@@ -5293,25 +5329,25 @@ static const EnumPropertyItem space_context_cycle_direction[] = {
static bool space_context_cycle_poll(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- /* sa might be NULL if called out of window bounds */
- return (sa && ELEM(sa->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
+ ScrArea *area = CTX_wm_area(C);
+ /* area might be NULL if called out of window bounds */
+ return (area && ELEM(area->spacetype, SPACE_PROPERTIES, SPACE_USERPREF));
}
/**
* Helper to get the correct RNA pointer/property pair for changing
- * the display context of active space type in \a sa.
+ * the display context of active space type in \a area.
*/
static void context_cycle_prop_get(bScreen *screen,
- const ScrArea *sa,
+ const ScrArea *area,
PointerRNA *r_ptr,
PropertyRNA **r_prop)
{
const char *propname;
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_PROPERTIES:
- RNA_pointer_create(&screen->id, &RNA_SpaceProperties, sa->spacedata.first, r_ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceProperties, area->spacedata.first, r_ptr);
propname = "context";
break;
case SPACE_USERPREF:
@@ -5384,7 +5420,7 @@ static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEve
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace_src) {
if (direction == SPACE_CONTEXT_CYCLE_PREV) {
workspace_dst = (link->prev) ? link->prev->data : NULL;
@@ -5517,7 +5553,7 @@ static void keymap_modal_set(wmKeyConfig *keyconf)
wmKeyMap *keymap;
/* Standard Modal keymap ------------------------------------------------ */
- keymap = WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Standard Modal Map", modal_items);
WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
}
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 38d83801f2b..733e8b694a6 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -113,7 +113,7 @@ bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb,
IDProperty *prop,
short opcontext)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
if (STREQ(ot->idname, umi_op->op_idname) && (opcontext == umi_op->opcontext) &&
@@ -128,7 +128,7 @@ bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb,
struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(struct ListBase *lb,
const struct MenuType *mt)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_MENU) {
bUserMenuItem_Menu *umi_mt = (bUserMenuItem_Menu *)umi;
if (STREQ(mt->idname, umi_mt->mt_idname)) {
@@ -144,7 +144,7 @@ struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(struct ListBase *l
const char *prop_id,
int prop_index)
{
- for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, lb) {
if (umi->type == USER_MENU_TYPE_PROP) {
bUserMenuItem_Prop *umi_pr = (bUserMenuItem_Prop *)umi;
if (STREQ(context_data_path, umi_pr->context_data_path) && STREQ(prop_id, umi_pr->prop_id) &&
@@ -222,7 +222,7 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
if (um == NULL) {
continue;
}
- for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ LISTBASE_FOREACH (bUserMenuItem *, umi, &um->items) {
const char *ui_name = umi->ui_name[0] ? umi->ui_name : NULL;
if (umi->type == USER_MENU_TYPE_OPERATOR) {
bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index d52dc262c3f..83ded5b3503 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -54,7 +54,7 @@
#include "screen_intern.h"
typedef struct ScreenshotData {
- unsigned int *dumprect;
+ uint *dumprect;
int dumpsx, dumpsy;
rcti crop;
@@ -76,13 +76,13 @@ static int screenshot_data_create(bContext *C, wmOperator *op)
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
scd->dumpsx = dumprect_size[0];
scd->dumpsy = dumprect_size[1];
scd->dumprect = dumprect;
- if (sa) {
- scd->crop = sa->totrct;
+ if (area) {
+ scd->crop = area->totrct;
}
BKE_imformat_defaults(&scd->im_format);
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 784fa60999d..478a0adfd9a 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -83,8 +83,7 @@ static void workspace_change_update(WorkSpace *workspace_new,
eObjectMode mode_new = workspace_new->object_mode;
if (mode_old != mode_new) {
- ED_object_mode_compat_set(C, ob_act, mode_new, &wm->reports);
- ED_object_mode_toggle(C, mode_new);
+ ED_object_mode_set(C, mode_new);
}
#endif
}
@@ -109,9 +108,9 @@ static WorkSpaceLayout *workspace_change_get_new_layout(Main *bmain,
layout_new = win->workspace_hook->temp_layout_store;
}
else {
- layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new);
+ layout_new = BKE_workspace_active_layout_for_workspace_get(win->workspace_hook, workspace_new);
if (!layout_new) {
- layout_new = BKE_workspace_layouts_get(workspace_new)->first;
+ layout_new = workspace_new->layouts.first;
}
}
screen_new = BKE_workspace_layout_screen_get(layout_new);
@@ -163,7 +162,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
return false;
}
- BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace_new, layout_new);
+ BKE_workspace_active_layout_set(win->workspace_hook, workspace_new, layout_new);
BKE_workspace_active_set(win->workspace_hook, workspace_new);
/* update screen *after* changing workspace - which also causes the
@@ -175,7 +174,7 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
/* Automatic mode switching. */
if (workspace_new->object_mode != workspace_old->object_mode) {
- ED_object_mode_generic_enter(C, workspace_new->object_mode);
+ ED_object_mode_set(C, workspace_new->object_mode);
}
return true;
@@ -188,7 +187,6 @@ bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager
WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win)
{
WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook);
- ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old);
WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2);
workspace_new->flags = workspace_old->flags;
@@ -198,8 +196,7 @@ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindo
/* TODO(campbell): tools */
- for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old;
- layout_old = layout_old->next) {
+ LISTBASE_FOREACH (WorkSpaceLayout *, layout_old, &workspace_old->layouts) {
WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(
bmain, workspace_new, layout_old, win);
@@ -222,7 +219,7 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
ListBase ordered;
BKE_id_ordered_list(&ordered, &bmain->workspaces);
WorkSpace *prev = NULL, *next = NULL;
- for (LinkData *link = ordered.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &ordered) {
if (link->data == workspace) {
prev = link->prev ? link->prev->data : NULL;
next = link->next ? link->next->data : NULL;
@@ -232,7 +229,7 @@ bool ED_workspace_delete(WorkSpace *workspace, Main *bmain, bContext *C, wmWindo
BLI_freelistN(&ordered);
BLI_assert((prev != NULL) || (next != NULL));
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace_active = WM_window_get_active_workspace(win);
if (workspace_active == workspace) {
ED_workspace_change((prev != NULL) ? prev : next, C, wm, win);
@@ -481,7 +478,7 @@ static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS
ListBase templates;
BKE_appdir_app_templates(&templates);
- for (LinkData *link = templates.first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, &templates) {
char *template = link->data;
char display_name[FILE_MAX];
diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c
index 276e36b97dc..7ce92bc3e4d 100644
--- a/source/blender/editors/screen/workspace_layout_edit.c
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -68,7 +68,7 @@ WorkSpaceLayout *ED_workspace_layout_duplicate(Main *bmain,
screen_new = BKE_workspace_layout_screen_get(layout_new);
if (BKE_screen_is_fullscreen_area(screen_old)) {
- for (ScrArea *area_old = screen_old->areabase.first; area_old; area_old = area_old->next) {
+ LISTBASE_FOREACH (ScrArea *, area_old, &screen_old->areabase) {
if (area_old->full) {
ScrArea *area_new = (ScrArea *)screen_new->areabase.first;
ED_area_data_copy(area_new, area_old, true);
@@ -140,7 +140,7 @@ bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_ol
const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
WorkSpaceLayout *layout_new;
- BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1);
+ BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
/* don't allow deleting temp fullscreens for now */
if (BKE_screen_is_fullscreen_area(screen_old)) {
@@ -172,9 +172,9 @@ bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bCon
WorkSpaceLayout *old_layout = BKE_workspace_active_layout_get(win->workspace_hook);
WorkSpaceLayout *new_layout;
const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (old_screen->temp || (sa && sa->full && sa->full->temp)) {
+ if (old_screen->temp || (area && area->full && area->full->temp)) {
return false;
}
@@ -188,9 +188,9 @@ bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bCon
if (new_layout && (old_layout != new_layout)) {
bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
- if (sa && sa->full) {
+ if (area && area->full) {
/* return to previous state before switching screens */
- ED_screen_full_restore(C, sa); /* may free screen of old_layout */
+ ED_screen_full_restore(C, area); /* may free screen of old_layout */
}
ED_screen_change(C, new_screen);
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index de9e70f8e06..b8754953741 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -59,9 +59,18 @@ set(SRC
paint_vertex_weight_ops.c
paint_vertex_weight_utils.c
sculpt.c
+ sculpt_automasking.c
sculpt_cloth.c
+ sculpt_detail.c
+ sculpt_dyntopo.c
+ sculpt_face_set.c
+ sculpt_filter_mask.c
+ sculpt_filter_mesh.c
+ sculpt_mask_expand.c
sculpt_multiplane_scrape.c
sculpt_pose.c
+ sculpt_smooth.c
+ sculpt_transform.c
sculpt_undo.c
sculpt_uv.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index c035863203b..4222a466a7b 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2009 by Nicholas Bishop
@@ -171,6 +171,8 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
bool convert_to_linear = false;
struct ColorSpace *colorspace = NULL;
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) {
ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool);
/* For consistency, sampling always returns color in linear space. */
@@ -214,8 +216,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
if (col) {
float rgba[4];
- paint_get_tex_pixel_col(
- mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace);
+ paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace);
buffer[index * 4] = rgba[0] * 255;
buffer[index * 4 + 1] = rgba[1] * 255;
@@ -223,7 +224,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata,
buffer[index * 4 + 3] = rgba[3] * 255;
}
else {
- float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id);
+ float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id);
avg += br->texture_sample_bias;
@@ -876,12 +877,8 @@ static bool paint_draw_alpha_overlay(UnifiedPaintSettings *ups,
return alpha_overlay_active;
}
-BLI_INLINE void draw_tri_point(unsigned int pos,
- const float sel_col[4],
- float pivot_col[4],
- float *co,
- float width,
- bool selected)
+BLI_INLINE void draw_tri_point(
+ uint pos, const float sel_col[4], float pivot_col[4], float *co, float width, bool selected)
{
immUniformColor4fv(selected ? sel_col : pivot_col);
@@ -910,12 +907,8 @@ BLI_INLINE void draw_tri_point(unsigned int pos,
immEnd();
}
-BLI_INLINE void draw_rect_point(unsigned int pos,
- const float sel_col[4],
- float handle_col[4],
- float *co,
- float width,
- bool selected)
+BLI_INLINE void draw_rect_point(
+ uint pos, const float sel_col[4], float handle_col[4], float *co, float width, bool selected)
{
immUniformColor4fv(selected ? sel_col : handle_col);
@@ -935,7 +928,7 @@ BLI_INLINE void draw_rect_point(unsigned int pos,
imm_draw_box_wire_2d(pos, minx, miny, maxx, maxy);
}
-BLI_INLINE void draw_bezier_handle_lines(unsigned int pos, float sel_col[4], BezTriple *bez)
+BLI_INLINE void draw_bezier_handle_lines(uint pos, float sel_col[4], BezTriple *bez)
{
immUniformColor4f(0.0f, 0.0f, 0.0f, 0.5f);
GPU_line_width(3.0f);
@@ -1224,6 +1217,34 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
}
}
+static void SCULPT_layer_brush_height_preview_draw(const uint gpuattr,
+ const Brush *brush,
+ const float obmat[4][4],
+ const float location[3],
+ const float normal[3],
+ const float rds,
+ const float line_width,
+ const float outline_col[3],
+ const float alpha)
+{
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+ float height_preview_trans[3];
+ copy_m4_m4(cursor_trans, obmat);
+ madd_v3_v3v3fl(height_preview_trans, location, normal, brush->height);
+ translate_m4(
+ cursor_trans, height_preview_trans[0], height_preview_trans[1], height_preview_trans[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, normal);
+ quat_to_mat4(cursor_rot, quat);
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+
+ GPU_line_width(line_width);
+ immUniformColor3fvAlpha(outline_col, alpha * 0.5f);
+ imm_draw_circle_wire_3d(gpuattr, 0, 0, rds, 80);
+}
+
static bool paint_use_2d_cursor(ePaintMode mode)
{
if (mode >= PAINT_MODE_TEXTURE_3D) {
@@ -1484,6 +1505,21 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
GPU_matrix_pop();
}
+ /* Layer brush height. */
+ if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
+ GPU_matrix_push();
+ SCULPT_layer_brush_height_preview_draw(pos,
+ brush,
+ vc.obact->obmat,
+ gi.location,
+ gi.normal,
+ rds,
+ 1.0f,
+ outline_col,
+ outline_alpha);
+ GPU_matrix_pop();
+ }
+
/* Update and draw dynamic mesh preview lines. */
GPU_matrix_push();
GPU_matrix_mul(vc.obact->obmat);
@@ -1638,23 +1674,13 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* Public API */
-void paint_cursor_start(bContext *C, bool (*poll)(bContext *C))
+void paint_cursor_start(Paint *p, bool (*poll)(bContext *C))
{
- Paint *p = BKE_paint_get_active_from_context(C);
-
if (p && !p->paint_cursor) {
p->paint_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
}
/* Invalidate the paint cursors. */
BKE_paint_invalidate_overlay_all();
}
-
-void paint_cursor_start_explicit(Paint *p, wmWindowManager *wm, bool (*poll)(bContext *C))
-{
- if (p && !p->paint_cursor) {
- p->paint_cursor = WM_paint_cursor_activate(
- wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, poll, paint_draw_cursor, NULL);
- }
-}
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index 5797eb68dd3..a3daef19f11 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -179,6 +179,7 @@ void ED_paintcurve_undo_push_end(void)
{
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
WM_file_tag_modified();
}
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 69ca86efa9d..e9dcc4a356a 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 by Nicholas Bishop
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index cbb0ce84156..08af3bdd16c 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -388,6 +388,10 @@ void paint_brush_color_get(struct Scene *scene,
break;
}
}
+ /* Gradient / Colorband colors are not considered PROP_COLOR_GAMMA.
+ * Brush colors are expected to be in sRGB though. */
+ IMB_colormanagement_scene_linear_to_srgb_v3(color_gr);
+
copy_v3_v3(color, color_gr);
}
else {
@@ -507,12 +511,8 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const flo
}
if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
- pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- image_paint_poll,
- gradient_draw_line,
- pop);
+ pop->cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, image_paint_poll, gradient_draw_line, pop);
}
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
@@ -651,7 +651,7 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
}
if (pop->cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+ WM_paint_cursor_end(pop->cursor);
}
ED_image_undo_push_end();
@@ -764,9 +764,9 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (sima->mode == SI_MODE_PAINT) {
ARegion *region = CTX_wm_region(C);
ED_space_image_get_zoom(sima, region, zoomx, zoomy);
@@ -781,19 +781,18 @@ bool get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
/************************ cursor drawing *******************************/
-static void toggle_paint_cursor(bContext *C, int enable)
+static void toggle_paint_cursor(Scene *scene, bool enable)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
+ Paint *p = &settings->imapaint.paint;
- if (settings->imapaint.paintcursor && !enable) {
- WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
- settings->imapaint.paintcursor = NULL;
+ if (p->paint_cursor && !enable) {
+ WM_paint_cursor_end(p->paint_cursor);
+ p->paint_cursor = NULL;
paint_cursor_delete_textures();
}
else if (enable) {
- paint_cursor_start(C, image_paint_poll);
+ paint_cursor_start(p, image_paint_poll);
}
}
@@ -808,12 +807,12 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
ImagePaintSettings *imapaint = &settings->imapaint;
bool enabled = false;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- if (((SpaceImage *)sa->spacedata.first)->mode == SI_MODE_PAINT) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_IMAGE) {
+ if (((SpaceImage *)area->spacedata.first)->mode == SI_MODE_PAINT) {
enabled = true;
}
}
@@ -823,7 +822,7 @@ void ED_space_image_paint_update(Main *bmain, wmWindowManager *wm, Scene *scene)
if (enabled) {
BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_2D, PAINT_CURSOR_TEXTURE_PAINT);
- paint_cursor_start_explicit(&imapaint->paint, wm, image_paint_poll);
+ paint_cursor_start(&imapaint->paint, image_paint_poll);
}
else {
paint_cursor_delete_textures();
@@ -949,9 +948,9 @@ typedef struct {
static void sample_color_update_header(SampleColorData *data, bContext *C)
{
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
BLI_snprintf(msg,
sizeof(msg),
TIP_("Sample color for %s"),
@@ -1117,6 +1116,100 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
/******************** texture paint toggle operator ********************/
+void ED_object_texture_paint_mode_enter_ex(Main *bmain, Scene *scene, Object *ob)
+{
+ bScreen *screen;
+ Image *ima = NULL;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+
+ /* This has to stay here to regenerate the texture paint
+ * cache in case we are loading a file */
+ BKE_texpaint_slots_refresh_object(scene, ob);
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ /* entering paint mode also sets image to editors */
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* set the current material active paint slot on image editor */
+ Material *ma = BKE_object_material_get(ob, ob->actcol);
+
+ if (ma && ma->texpaintslot) {
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+ }
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ ima = imapaint->canvas;
+ }
+
+ if (ima) {
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ ScrArea *area;
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl;
+ for (sl = area->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin) {
+ ED_space_image_set(bmain, sima, NULL, ima, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ob->mode |= OB_MODE_TEXTURE_PAINT;
+
+ BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
+
+ BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
+
+ if (U.glreslimit != 0) {
+ GPU_free_images(bmain);
+ }
+ GPU_paint_set_mipmap(bmain, 0);
+
+ toggle_paint_cursor(scene, true);
+
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE, scene);
+}
+
+void ED_object_texture_paint_mode_enter(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ED_object_texture_paint_mode_enter_ex(bmain, scene, ob);
+}
+
+void ED_object_texture_paint_mode_exit_ex(Main *bmain, Scene *scene, Object *ob)
+{
+ ob->mode &= ~OB_MODE_TEXTURE_PAINT;
+
+ if (U.glreslimit != 0) {
+ GPU_free_images(bmain);
+ }
+ GPU_paint_set_mipmap(bmain, 1);
+ toggle_paint_cursor(scene, false);
+
+ Mesh *me = BKE_mesh_from_object(ob);
+ BLI_assert(me != NULL);
+ DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
+ WM_main_add_notifier(NC_SCENE | ND_MODE, scene);
+}
+
+void ED_object_texture_paint_mode_exit(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
+}
+
static bool texture_paint_toggle_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -1126,9 +1219,6 @@ static bool texture_paint_toggle_poll(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return 1;
}
@@ -1149,78 +1239,12 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
}
if (ob->mode & mode_flag) {
- ob->mode &= ~mode_flag;
-
- if (U.glreslimit != 0) {
- GPU_free_images(bmain);
- }
- GPU_paint_set_mipmap(bmain, 1);
-
- toggle_paint_cursor(C, 0);
+ ED_object_texture_paint_mode_exit_ex(bmain, scene, ob);
}
else {
- bScreen *sc;
- Image *ima = NULL;
- ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
-
- /* This has to stay here to regenerate the texture paint
- * cache in case we are loading a file */
- BKE_texpaint_slots_refresh_object(scene, ob);
-
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
-
- /* entering paint mode also sets image to editors */
- if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
- /* set the current material active paint slot on image editor */
- Material *ma = BKE_object_material_get(ob, ob->actcol);
-
- if (ma && ma->texpaintslot) {
- ima = ma->texpaintslot[ma->paint_active_slot].ima;
- }
- }
- else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
- ima = imapaint->canvas;
- }
-
- if (ima) {
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- ScrArea *sa;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl;
- for (sl = sa->spacedata.first; sl; sl = sl->next) {
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)sl;
-
- if (!sima->pin) {
- Object *obedit = CTX_data_edit_object(C);
- ED_space_image_set(bmain, sima, obedit, ima, true);
- }
- }
- }
- }
- }
- }
-
- ob->mode |= mode_flag;
-
- BKE_paint_init(bmain, scene, PAINT_MODE_TEXTURE_3D, PAINT_CURSOR_TEXTURE_PAINT);
-
- BKE_paint_toolslots_brush_validate(bmain, &imapaint->paint);
-
- if (U.glreslimit != 0) {
- GPU_free_images(bmain);
- }
- GPU_paint_set_mipmap(bmain, 0);
-
- toggle_paint_cursor(C, 1);
+ ED_object_texture_paint_mode_enter_ex(bmain, scene, ob);
}
- Mesh *me = BKE_mesh_from_object(ob);
- BLI_assert(me != NULL);
- DEG_id_tag_update(&me->id, ID_RECALC_COPY_ON_WRITE);
-
- WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
-
WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
WM_toolsystem_update_from_context_view3d(C);
@@ -1288,9 +1312,9 @@ static bool brush_colors_flip_poll(bContext *C)
void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Brush Colors Flip";
+ ot->name = "Swap Colors";
ot->idname = "PAINT_OT_brush_colors_flip";
- ot->description = "Toggle foreground and background brush colors";
+ ot->description = "Swap primary and secondary brush colors";
/* api callbacks */
ot->exec = brush_colors_flip_exec;
@@ -1305,20 +1329,20 @@ void ED_imapaint_bucket_fill(struct bContext *C,
wmOperator *op,
const int mouse[2])
{
- wmWindowManager *wm = CTX_wm_manager(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = sima->image;
- BKE_undosys_step_push_init_with_type(wm->undo_stack, C, op->type->name, BKE_UNDOSYS_TYPE_IMAGE);
+ if (sima && sima->image) {
+ Image *ima = sima->image;
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
+ ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- float mouse_init[2] = {mouse[0], mouse[1]};
- paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
+ float mouse_init[2] = {mouse[0], mouse[1]};
+ paint_2d_bucket_fill(C, color, NULL, mouse_init, NULL, NULL);
- BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
+ ED_image_undo_push_end();
- DEG_id_tag_update(&ima->id, 0);
+ DEG_id_tag_update(&ima->id, 0);
+ }
}
static bool texture_paint_poll(bContext *C)
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 73c099c9407..16ccfaf8286 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -80,11 +80,11 @@ typedef struct BrushPainterCache {
ImBuf *ibuf;
ImBuf *texibuf;
- unsigned short *curve_mask;
- unsigned short *tex_mask;
- unsigned short *tex_mask_old;
- unsigned int tex_mask_old_w;
- unsigned int tex_mask_old_h;
+ ushort *curve_mask;
+ ushort *tex_mask;
+ ushort *tex_mask_old;
+ uint tex_mask_old_w;
+ uint tex_mask_old_h;
int image_size[2];
} BrushPainterCache;
@@ -228,7 +228,7 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
}
/* create a mask with the mask texture */
-static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
+static ushort *brush_painter_mask_ibuf_new(BrushPainter *painter, const int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -236,10 +236,10 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
struct ImagePool *pool = painter->pool;
float texco[3];
- unsigned short *mask, *m;
+ ushort *mask, *m;
int x, y, thread = 0;
- mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(ushort) * size * size, "brush_painter_mask");
m = mask;
for (y = 0; y < size; y++) {
@@ -247,7 +247,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
float res;
brush_imbuf_tex_co(&mask_mapping, x, y, texco);
res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- *m = (unsigned short)(65535.0f * res);
+ *m = (ushort)(65535.0f * res);
}
}
@@ -257,7 +257,7 @@ static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, const
/* update rectangular section of the brush image */
static void brush_painter_mask_imbuf_update(BrushPainter *painter,
ImagePaintTile *tile,
- unsigned short *tex_mask_old,
+ ushort *tex_mask_old,
int origx,
int origy,
int w,
@@ -271,14 +271,14 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
BrushPainterCache *cache = &tile->cache;
rctf tex_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- unsigned short res;
+ ushort res;
bool use_texture_old = (tex_mask_old != NULL);
int x, y, thread = 0;
- unsigned short *tex_mask = cache->tex_mask;
- unsigned short *tex_mask_cur = cache->tex_mask_old;
+ ushort *tex_mask = cache->tex_mask;
+ ushort *tex_mask_cur = cache->tex_mask_old;
/* fill pixels */
for (y = origy; y < h; y++) {
@@ -287,13 +287,12 @@ static void brush_painter_mask_imbuf_update(BrushPainter *painter,
float texco[3];
/* handle byte pixel */
- unsigned short *b = tex_mask + (y * diameter + x);
- unsigned short *t = tex_mask_cur + (y * diameter + x);
+ ushort *b = tex_mask + (y * diameter + x);
+ ushort *t = tex_mask_cur + (y * diameter + x);
if (!use_texture_old) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
- res = (unsigned short)(65535.0f *
- BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ res = (ushort)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
}
/* read from old texture buffer */
@@ -320,19 +319,17 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
const int diameter)
{
BrushPainterCache *cache = &tile->cache;
- unsigned short *tex_mask_old;
+ ushort *tex_mask_old;
int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
/* create brush image buffer if it didn't exist yet */
if (!cache->tex_mask) {
- cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
- "brush_painter_mask");
+ cache->tex_mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
}
/* create new texture image buffer with coordinates relative to old */
tex_mask_old = cache->tex_mask_old;
- cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter,
- "brush_painter_mask");
+ cache->tex_mask_old = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
if (tex_mask_old) {
ImBuf maskibuf;
@@ -393,18 +390,18 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter,
}
/* create a mask with the falloff strength */
-static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
- int diameter,
- float radius,
- const float pos[2])
+static ushort *brush_painter_curve_mask_new(BrushPainter *painter,
+ int diameter,
+ float radius,
+ const float pos[2])
{
Brush *brush = painter->brush;
int offset = (int)floorf(diameter / 2.0f);
- unsigned short *mask, *m;
+ ushort *mask, *m;
- mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask");
m = mask;
int aa_samples = 1.0f / (radius * 0.20f);
@@ -458,7 +455,7 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
total_samples += curve * hardness_factor;
}
}
- *m = (unsigned short)(total_samples * norm_factor);
+ *m = (ushort)(total_samples * norm_factor);
}
}
@@ -528,7 +525,7 @@ static ImBuf *brush_painter_imbuf_new(
}
else {
/* write to byte pixel */
- unsigned char *dst = (unsigned char *)ibuf->rect + (y * size + x) * 4;
+ uchar *dst = (uchar *)ibuf->rect + (y * size + x) * 4;
rgb_float_to_uchar(dst, rgba);
dst[3] = unit_float_to_uchar_clamp(rgba[3]);
@@ -624,16 +621,16 @@ static void brush_painter_imbuf_update(BrushPainter *painter,
bf[3] = rgba[3];
}
else {
- unsigned char crgba[4];
+ uchar crgba[4];
/* handle byte pixel */
- unsigned char *b = (unsigned char *)ibuf->rect + (y * ibuf->x + x) * 4;
- unsigned char *t = (unsigned char *)texibuf->rect + (y * texibuf->x + x) * 4;
+ uchar *b = (uchar *)ibuf->rect + (y * ibuf->x + x) * 4;
+ uchar *t = (uchar *)texibuf->rect + (y * texibuf->x + x) * 4;
/* read from old texture buffer */
if (use_texture_old) {
- unsigned char *ot = (unsigned char *)oldtexibuf->rect +
- ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
+ uchar *ot = (uchar *)oldtexibuf->rect +
+ ((y - origy + yt) * oldtexibuf->x + (x - origx + xt)) * 4;
crgba[0] = ot[0];
crgba[1] = ot[1];
crgba[2] = ot[2];
@@ -975,7 +972,7 @@ static void paint_2d_ibuf_rgb_get(ImBuf *ibuf, int x, int y, float r_rgb[4])
copy_v4_v4(r_rgb, rrgbf);
}
else {
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
straight_uchar_to_premul_float(r_rgb, rrgb);
}
}
@@ -1001,8 +998,8 @@ static void paint_2d_ibuf_rgb_set(
rrgbf[3] = rgb[3];
}
else {
- unsigned char straight[4];
- unsigned char *rrgb = (unsigned char *)ibuf->rect + (ibuf->x * y + x) * 4;
+ uchar straight[4];
+ uchar *rrgb = (uchar *)ibuf->rect + (ibuf->x * y + x) * 4;
premul_float_to_straight_uchar(straight, rgb);
rrgb[0] = straight[0];
@@ -1329,7 +1326,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
- unsigned short *mask;
+ ushort *mask;
int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
@@ -1829,7 +1826,7 @@ static void paint_2d_fill_add_pixel_byte(const int x_px,
if (!BLI_BITMAP_TEST(touched, coordinate)) {
float color_f[4];
- unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ uchar *color_b = (uchar *)(ibuf->rect + coordinate);
rgba_uchar_to_float(color_f, color_b);
straight_to_premul_v4(color_f);
@@ -1895,9 +1892,9 @@ void paint_2d_bucket_fill(const bContext *C,
ImBuf *ibuf;
int x_px, y_px;
- unsigned int color_b;
+ uint color_b;
float color_f[4];
- float strength = br ? BKE_brush_alpha_get(s->scene, br) : 1.0f;
+ float strength = (s && br) ? BKE_brush_alpha_get(s->scene, br) : 1.0f;
bool do_float;
@@ -1935,7 +1932,7 @@ void paint_2d_bucket_fill(const bContext *C,
* be in gamma space. strictly speaking this is not correct, but blender does not paint
* byte images in linear space */
if (!do_float) {
- linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ linearrgb_to_srgb_uchar3((uchar *)&color_b, color);
*(((char *)&color_b) + 3) = strength * 255;
}
else {
@@ -1959,9 +1956,9 @@ void paint_2d_bucket_fill(const bContext *C,
else {
for (x_px = 0; x_px < ibuf->x; x_px++) {
for (y_px = 0; y_px < ibuf->y; y_px++) {
- blend_color_mix_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b);
+ blend_color_mix_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)&color_b);
}
}
}
@@ -2000,7 +1997,7 @@ void paint_2d_bucket_fill(const bContext *C,
}
else {
int pixel_color_b = *(ibuf->rect + coordinate);
- rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ rgba_uchar_to_float(pixel_color, (uchar *)&pixel_color_b);
straight_to_premul_v4(pixel_color);
}
@@ -2055,9 +2052,9 @@ void paint_2d_bucket_fill(const bContext *C,
while (!BLI_stack_is_empty(stack)) {
BLI_stack_pop(stack, &coordinate);
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)(ibuf->rect + coordinate),
- (unsigned char *)&color_b,
+ IMB_blend_color_byte((uchar *)(ibuf->rect + coordinate),
+ (uchar *)(ibuf->rect + coordinate),
+ (uchar *)&color_b,
br->blend);
/* reconstruct the coordinates here */
@@ -2117,7 +2114,7 @@ void paint_2d_gradient_fill(
ImBuf *ibuf;
int x_px, y_px;
- unsigned int color_b;
+ uint color_b;
float color_f[4];
float image_init[2], image_final[2];
float tangent[2];
@@ -2212,11 +2209,11 @@ void paint_2d_gradient_fill(
BKE_colorband_evaluate(br->gradient, f, color_f);
linearrgb_to_srgb_v3_v3(color_f, color_f);
- rgba_float_to_uchar((unsigned char *)&color_b, color_f);
- ((unsigned char *)&color_b)[3] *= brush_alpha;
- IMB_blend_color_byte((unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
- (unsigned char *)&color_b,
+ rgba_float_to_uchar((uchar *)&color_b, color_f);
+ ((uchar *)&color_b)[3] *= brush_alpha;
+ IMB_blend_color_byte((uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)(ibuf->rect + ((size_t)y_px) * ibuf->x + x_px),
+ (uchar *)&color_b,
br->blend);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index c56ce8fd183..5e3204b6d5a 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -112,7 +112,7 @@ static void partial_redraw_array_init(ImagePaintPartialRedraw *pr);
/* Defines and Structs */
/* unit_float_to_uchar_clamp as inline function */
-BLI_INLINE unsigned char f_to_char(const float val)
+BLI_INLINE uchar f_to_char(const float val)
{
return unit_float_to_uchar_clamp(val);
}
@@ -206,7 +206,7 @@ typedef struct ProjPaintImage {
volatile void **undoRect;
/** The mask accumulation must happen on canvas, not on space screen bucket.
* Here we store the mask rectangle. */
- unsigned short **maskRect;
+ ushort **maskRect;
/** Store flag to enforce validation of undo rectangle. */
bool **valid;
bool touch;
@@ -279,7 +279,7 @@ typedef struct ProjPaintState {
/** bucketRect aligned array linkList of faces overlapping each bucket. */
LinkNode **bucketFaces;
/** store if the bucks have been initialized. */
- unsigned char *bucketFlags;
+ uchar *bucketFlags;
/** store options per vert, now only store if the vert is pointing away from the view. */
char *vertFlags;
@@ -443,13 +443,13 @@ typedef union pixelPointer {
/** float buffer. */
float *f_pt;
/** 2 ways to access a char buffer. */
- unsigned int *uint_pt;
- unsigned char *ch_pt;
+ uint *uint_pt;
+ uchar *ch_pt;
} PixelPointer;
typedef union pixelStore {
- unsigned char ch[4];
- unsigned int uint;
+ uchar ch[4];
+ uint uint;
float f[4];
} PixelStore;
@@ -461,17 +461,17 @@ typedef struct ProjPixel {
short x_px, y_px;
/** if anyone wants to paint onto more than 65535 images they can bite me. */
- unsigned short image_index;
- unsigned char bb_cell_index;
+ ushort image_index;
+ uchar bb_cell_index;
/* for various reasons we may want to mask out painting onto this pixel */
- unsigned short mask;
+ ushort mask;
/* Only used when the airbrush is disabled.
* Store the max mask value to avoid painting over an area with a lower opacity
* with an advantage that we can avoid touching the pixel at all, if the
* new mask value is lower then mask_accum */
- unsigned short *mask_accum;
+ ushort *mask_accum;
/* horrible hack, store tile valid flag pointer here to re-validate tiles
* used for anchored and drag-dot strokes */
@@ -491,7 +491,7 @@ typedef struct ProjPixelClone {
typedef struct {
SpinLock *lock;
bool masked;
- unsigned short tile_width;
+ ushort tile_width;
ImBuf **tmpibuf;
ProjPaintImage *pjima;
} TileInfo;
@@ -717,11 +717,8 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa
/* Set the top-most face color that the screen space coord 'pt' touches
* (or return 0 if none touch) */
-static bool project_paint_PickColor(const ProjPaintState *ps,
- const float pt[2],
- float *rgba_fp,
- unsigned char *rgba,
- const bool interp)
+static bool project_paint_PickColor(
+ const ProjPaintState *ps, const float pt[2], float *rgba_fp, uchar *rgba, const bool interp)
{
const MLoopTri *lt;
const float *lt_tri_uv[3];
@@ -774,7 +771,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
bilinear_interpolation_color_wrap(ibuf, rgba, NULL, x, y);
}
else {
- unsigned char rgba_tmp[4];
+ uchar rgba_tmp[4];
bilinear_interpolation_color_wrap(ibuf, rgba_tmp, NULL, x, y);
straight_uchar_to_premul_float(rgba_fp, rgba_tmp);
}
@@ -795,8 +792,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
premul_float_to_straight_uchar(rgba, rgba_tmp_fp);
}
else {
- *((unsigned int *)rgba) = *(unsigned int *)(((char *)ibuf->rect) +
- ((xi + yi * ibuf->x) * 4));
+ *((uint *)rgba) = *(uint *)(((char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4));
}
}
@@ -805,7 +801,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps,
copy_v4_v4(rgba_fp, (ibuf->rect_float + ((xi + yi * ibuf->x) * 4)));
}
else {
- unsigned char *tmp_ch = ((unsigned char *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
+ uchar *tmp_ch = ((uchar *)ibuf->rect) + ((xi + yi * ibuf->x) * 4);
straight_uchar_to_premul_float(rgba_fp, tmp_ch);
}
}
@@ -1150,8 +1146,8 @@ static bool check_seam(const ProjPaintState *ps,
const MLoopTri *orig_lt = &ps->mlooptri_eval[orig_face];
const float *orig_lt_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, orig_lt)};
/* vert indices from face vert order indices */
- const unsigned int i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
- const unsigned int i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
+ const uint i1 = ps->mloop_eval[orig_lt->tri[orig_i1_fidx]].v;
+ const uint i2 = ps->mloop_eval[orig_lt->tri[orig_i2_fidx]].v;
LinkNode *node;
/* index in face */
int i1_fidx = -1, i2_fidx = -1;
@@ -1641,7 +1637,7 @@ static float screen_px_line_point_factor_v2_persp(const ProjPaintState *ps,
static void project_face_pixel(const float *lt_tri_uv[3],
ImBuf *ibuf_other,
const float w[3],
- unsigned char rgba_ub[4],
+ uchar rgba_ub[4],
float rgba_f[4])
{
float uv_other[2], x, y;
@@ -1677,7 +1673,7 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps,
const float *lt_other_tri_uv[3] = {PS_LOOPTRI_AS_UV_3(ps->poly_to_loop_uv, lt_other)};
/* BKE_image_acquire_ibuf - TODO - this may be slow */
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
float rgba_f[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, rgba_f);
@@ -1937,8 +1933,8 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
zero_v4(projPixel->newColor.f);
}
else {
- projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
- projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
+ projPixel->pixel.ch_pt = (uchar *)(ibuf->rect + (x_px + y_px * ibuf->x));
+ projPixel->origColor.uint_pt = (uint *)projima->undoRect[tile_index] + tile_offset;
projPixel->newColor.uint = 0;
}
@@ -1952,7 +1948,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
projPixel->x_px = x_px;
projPixel->y_px = y_px;
- projPixel->mask = (unsigned short)(mask * 65535);
+ projPixel->mask = (ushort)(mask * 65535);
if (ps->do_masking) {
projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
}
@@ -1984,7 +1980,7 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
lt_other_tri_uv, ibuf_other, w, NULL, ((ProjPixelClone *)projPixel)->clonepx.f);
}
else { /* from char to float */
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
float rgba[4];
project_face_pixel(lt_other_tri_uv, ibuf_other, w, rgba_ub, NULL);
if (ps->use_colormanagement) {
@@ -4026,7 +4022,7 @@ static void project_paint_bleed_add_face_user(const ProjPaintState *ps,
* Ideally this would be checked later, not to add to the cost of computing non-degenerate
* triangles, but that would allow other triangles to still find adjacent seams on degenerate
* triangles, potentially causing incorrect results. */
- if (area_tri_v2(UNPACK3(lt_tri_uv)) > FLT_EPSILON) {
+ if (area_tri_v2(UNPACK3(lt_tri_uv)) > 0.0f) {
const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)};
void *tri_index_p = POINTER_FROM_INT(tri_index);
@@ -4844,15 +4840,15 @@ typedef struct ProjectHandle {
static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- const unsigned char *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
+ const uchar *clone_pt = ((ProjPixelClone *)projPixel)->clonepx.ch;
if (clone_pt[3]) {
- unsigned char clone_rgba[4];
+ uchar clone_rgba[4];
clone_rgba[0] = clone_pt[0];
clone_rgba[1] = clone_pt[1];
clone_rgba[2] = clone_pt[2];
- clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
+ clone_rgba[3] = (uchar)(clone_pt[3] * mask);
if (ps->do_masking) {
IMB_blend_color_byte(
@@ -4895,7 +4891,7 @@ static void do_projectpaint_smear(ProjPaintState *ps,
LinkNode **smearPixels,
const float co[2])
{
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1) == 0) {
return;
@@ -5016,7 +5012,7 @@ static void do_projectpaint_soften(ProjPaintState *ps,
}
if (LIKELY(accum_tot != 0)) {
- unsigned char *rgba_ub = projPixel->newColor.ch;
+ uchar *rgba_ub = projPixel->newColor.ch;
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
@@ -5061,7 +5057,7 @@ static void do_projectpaint_draw(ProjPaintState *ps,
float v)
{
float rgb[3];
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
if (ps->is_texbrush) {
mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
@@ -5119,7 +5115,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps,
static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
{
- unsigned char rgba_ub[4];
+ uchar rgba_ub[4];
rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
rgba_ub[3] = f_to_char(mask);
@@ -5172,9 +5168,7 @@ static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf)
}
/* Run this for single and multi-threaded painting. */
-static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
- void *ph_v,
- int UNUSED(threadid))
+static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v)
{
/* First unpack args from the struct */
ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps;
@@ -5204,7 +5198,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
/* for smear only */
float pos_ofs[2] = {0};
float co[2];
- unsigned short mask_short;
+ ushort mask_short;
const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
const float brush_radius = ps->brush_size;
/* avoid a square root with every dist comparison */
@@ -5468,7 +5462,7 @@ static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool),
}
mask = min_ff(mask, 65535.0f);
- mask_short = (unsigned short)mask;
+ mask_short = (ushort)mask;
if (mask_short > *projPixel->mask_accum) {
*projPixel->mask_accum = mask_short;
@@ -5609,7 +5603,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
bool touch_any = false;
ProjectHandle handles[BLENDER_MAX_THREADS];
- TaskScheduler *scheduler = NULL;
TaskPool *task_pool = NULL;
int a, i;
@@ -5620,8 +5613,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
if (ps->thread_tot > 1) {
- scheduler = BLI_task_scheduler_get();
- task_pool = BLI_task_pool_create_suspended(scheduler, NULL);
+ task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH);
}
image_pool = BKE_image_pool_new();
@@ -5656,8 +5648,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
handles[a].pool = image_pool;
if (task_pool != NULL) {
- BLI_task_pool_push(
- task_pool, do_projectpaint_thread, &handles[a], false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_push(task_pool, do_projectpaint_thread, &handles[a], false, NULL);
}
}
@@ -5666,7 +5657,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
BLI_task_pool_free(task_pool);
}
else {
- do_projectpaint_thread(NULL, &handles[0], 0);
+ do_projectpaint_thread(NULL, &handles[0]);
}
BKE_image_pool_free(image_pool);
@@ -6228,13 +6219,13 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
int maxsize;
char err_out[256] = "unknown";
- ScrArea *sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
- if (!sa) {
+ ScrArea *area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
+ if (!area) {
BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
return OPERATOR_CANCELLED;
}
- ARegion *region = BKE_area_find_region_active_win(sa);
+ ARegion *region = BKE_area_find_region_active_win(area);
if (!region) {
BKE_report(op->reports, RPT_ERROR, "No 3D viewport found to create image from");
return OPERATOR_CANCELLED;
@@ -6254,7 +6245,7 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
/* Create a copy of the overlays where they are all turned off, except the
* texture paint overlay opacity */
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
View3D v3d_copy = *v3d;
v3d_copy.gridflag = 0;
v3d_copy.flag2 = 0;
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 018d7f72bb6..0d4e957c77b 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -90,10 +90,7 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke);
float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
bool paint_poll(struct bContext *C);
-void paint_cursor_start(struct bContext *C, bool (*poll)(struct bContext *C));
-void paint_cursor_start_explicit(struct Paint *p,
- struct wmWindowManager *wm,
- bool (*poll)(struct bContext *C));
+void paint_cursor_start(struct Paint *p, bool (*poll)(struct bContext *C));
void paint_cursor_delete_textures(void);
/* paint_vertex.c */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index fb8cc3a639b..c32e496f4f5 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 by Nicholas Bishop
@@ -168,9 +168,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.value = value,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
.clip_planes_final = clip_planes_final,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -456,10 +456,10 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata,
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
float clip_planes[4][4], clip_planes_final[4][4];
BoundBox bb;
@@ -485,7 +485,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
ob = vc.obact;
ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
- BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
+ BLI_lasso_boundbox(&data.rect, mcoords, mcoords_len);
data.width = data.rect.xmax - data.rect.xmin;
data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
@@ -493,8 +493,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.rect.ymin,
data.rect.xmax,
data.rect.ymax,
- mcords,
- mcords_tot,
+ mcoords,
+ mcoords_len,
mask_lasso_px_cb,
&data);
@@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
if (nodes) {
MEM_freeN(nodes);
@@ -551,7 +551,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
SCULPT_undo_push_end();
ED_region_tag_redraw(vc.region);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
MEM_freeN(data.px);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index cc848b80bb3..0f54d5e0821 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -397,7 +397,7 @@ static int palette_sort_exec(bContext *C, wmOperator *op)
color_array = MEM_calloc_arrayN(totcol, sizeof(tPaletteColorHSV), __func__);
/* Put all colors in an array. */
int t = 0;
- for (PaletteColor *color = palette->colors.first; color; color = color->next) {
+ LISTBASE_FOREACH (PaletteColor *, color, &palette->colors) {
float h, s, v;
rgb_to_hsv(color->rgb[0], color->rgb[1], color->rgb[2], &h, &s, &v);
col_elm = &color_array[t];
@@ -543,7 +543,7 @@ static int palette_join_exec(bContext *C, wmOperator *op)
const int totcol = BLI_listbase_count(&palette_join->colors);
if (totcol > 0) {
- for (PaletteColor *color = palette_join->colors.first; color; color = color->next) {
+ LISTBASE_FOREACH (PaletteColor *, color, &palette_join->colors) {
PaletteColor *palcol = BKE_palette_color_add(palette);
if (palcol) {
copy_v3_v3(palcol->rgb, color->rgb);
@@ -731,7 +731,14 @@ static bool brush_generic_tool_set(bContext *C,
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
/* Tool System
- * This is needed for when there is a non-sculpt tool active (transform for e.g.) */
+ * This is needed for when there is a non-sculpt tool active (transform for e.g.).
+ * In case we are toggling (and the brush changed to the toggle_brush), we need to get the
+ * tool_name again. */
+ int tool_result = brush_tool(brush, paint->runtime.tool_offset);
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ const EnumPropertyItem *items = BKE_paint_get_tool_enum_from_paintmode(paint_mode);
+ RNA_enum_name_from_value(items, tool_result, &tool_name);
+
char tool_id[MAX_NAME];
SNPRINTF(tool_id, "builtin_brush.%s", tool_name);
WM_toolsystem_ref_set_by_id(C, tool_id);
@@ -1140,24 +1147,24 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op)
aspy *= tex->yrepeat;
}
- orig_area = aspx * aspy;
+ orig_area = fabsf(aspx * aspy);
if (do_mask) {
- stencil_area = br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1];
+ stencil_area = fabsf(br->mask_stencil_dimension[0] * br->mask_stencil_dimension[1]);
}
else {
- stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
+ stencil_area = fabsf(br->stencil_dimension[0] * br->stencil_dimension[1]);
}
factor = sqrtf(stencil_area / orig_area);
if (do_mask) {
- br->mask_stencil_dimension[0] = factor * aspx;
- br->mask_stencil_dimension[1] = factor * aspy;
+ br->mask_stencil_dimension[0] = fabsf(factor * aspx);
+ br->mask_stencil_dimension[1] = fabsf(factor * aspy);
}
else {
- br->stencil_dimension[0] = factor * aspx;
- br->stencil_dimension[1] = factor * aspy;
+ br->stencil_dimension[0] = fabsf(factor * aspx);
+ br->stencil_dimension[1] = fabsf(factor * aspy);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 01a0e8ddd5b..2c6f708d82a 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2009 by Nicholas Bishop
@@ -230,8 +230,7 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
SCULPT_TOOL_THUMB)) {
return false;
}
- else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ else if (SCULPT_is_cloth_deform_brush(brush)) {
return false;
}
else {
@@ -963,7 +962,7 @@ void paint_stroke_free(bContext *C, wmOperator *op)
}
if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ WM_paint_cursor_end(stroke->stroke_cursor);
}
BLI_freelistN(&stroke->line);
@@ -1103,11 +1102,11 @@ struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
static const char *name = "Paint Stroke Modal";
- struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
+ struct wmKeyMap *keymap = WM_modalkeymap_find(keyconf, name);
/* this function is called for each spacetype, only needs to add map once */
if (!keymap) {
- keymap = WM_modalkeymap_add(keyconf, name, modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, name, modal_items);
}
return keymap;
@@ -1340,7 +1339,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
Paint *p = BKE_paint_get_active_from_context(C);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
PaintStroke *stroke = op->customdata;
- Brush *br = stroke->brush;
+ Brush *br = stroke->brush = BKE_paint_brush(p);
PaintSample sample_average;
float mouse[2];
bool first_dab = false;
@@ -1386,12 +1385,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (paint_supports_smooth_stroke(br, mode)) {
- stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- paint_poll,
- paint_draw_smooth_cursor,
- stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke);
}
stroke->stroke_init = true;
@@ -1417,12 +1412,8 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (br->flag & BRUSH_LINE) {
- stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- paint_poll,
- paint_draw_line_cursor,
- stroke);
+ stroke->stroke_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke);
}
first_dab = true;
@@ -1597,13 +1588,14 @@ bool paint_poll(bContext *C)
{
Paint *p = BKE_paint_get_active_from_context(C);
Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- if (p && ob && BKE_paint_brush(p) && (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
+ if (p && ob && BKE_paint_brush(p) &&
+ (area && ELEM(area->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
(region && region->regiontype == RGN_TYPE_WINDOW)) {
/* Check the current tool is a brush. */
- bToolRef *tref = sa->runtime.tool;
+ bToolRef *tref = area->runtime.tool;
if (tref && tref->runtime && tref->runtime->data_block[0]) {
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index e67d43d4571..c84a3b9cbfc 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -166,10 +166,11 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo
float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread)
{
- float intensity, rgba[4];
+ float intensity;
+ float rgba_dummy[4];
float co[3] = {u, v, 0.0f};
- externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy);
return intensity;
}
@@ -184,11 +185,10 @@ void paint_get_tex_pixel_col(const MTex *mtex,
struct ColorSpace *colorspace)
{
float co[3] = {u, v, 0.0f};
- int hasrgb;
float intensity;
- hasrgb = externtex(
- mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false);
+ const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba);
+
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
@@ -294,12 +294,8 @@ static void imapaint_tri_weights(float matrix[4][4],
}
/* compute uv coordinates of mouse in face */
-static void imapaint_pick_uv(Mesh *me_eval,
- Scene *scene,
- Object *ob_eval,
- unsigned int faceindex,
- const int xy[2],
- float uv[2])
+static void imapaint_pick_uv(
+ Mesh *me_eval, Scene *scene, Object *ob_eval, uint faceindex, const int xy[2], float uv[2])
{
int i, findex;
float p[2], w[3], absw, minabsw;
@@ -376,10 +372,7 @@ static void imapaint_pick_uv(Mesh *me_eval,
}
/* returns 0 if not found, otherwise 1 */
-static int imapaint_pick_face(ViewContext *vc,
- const int mval[2],
- unsigned int *r_index,
- unsigned int totpoly)
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], uint *r_index, uint totpoly)
{
if (totpoly == 0) {
return 0;
@@ -389,7 +382,7 @@ static int imapaint_pick_face(ViewContext *vc,
ED_view3d_select_id_validate(vc);
*r_index = DRW_select_buffer_sample_point(vc->depsgraph, vc->region, vc->v3d, mval);
- if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
+ if ((*r_index) == 0 || (*r_index) > (uint)totpoly) {
return 0;
}
@@ -464,8 +457,8 @@ void paint_sample_color(
Palette *palette = BKE_paint_palette(paint);
PaletteColor *color = NULL;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- unsigned int col;
- const unsigned char *cp;
+ uint col;
+ const uchar *cp;
CLAMP(x, 0, region->winx);
CLAMP(y, 0, region->winy);
@@ -497,8 +490,8 @@ void paint_sample_color(
ViewContext vc;
const int mval[2] = {x, y};
- unsigned int faceindex;
- unsigned int totpoly = me->totpoly;
+ uint faceindex;
+ uint totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
ED_view3d_viewcontext_init(C, &vc, depsgraph);
@@ -563,7 +556,7 @@ void paint_sample_color(
}
}
else {
- unsigned char rgba[4];
+ uchar rgba[4];
bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
if (use_palette) {
rgb_uchar_to_float(color->rgb, rgba);
@@ -598,7 +591,7 @@ void paint_sample_color(
x + region->winrct.xmin, y + region->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
glReadBuffer(GL_BACK);
}
- cp = (unsigned char *)&col;
+ cp = (uchar *)&col;
if (use_palette) {
rgb_uchar_to_float(color->rgb, cp);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 604146e2ca6..6de54b3ae6a 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -214,8 +214,8 @@ bool vertex_paint_mode_poll(bContext *C)
static bool vertex_paint_poll_ex(bContext *C, bool check_tool)
{
if (vertex_paint_mode_poll(C) && BKE_paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_WINDOW) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
@@ -247,11 +247,11 @@ bool weight_paint_mode_poll(bContext *C)
static bool weight_paint_poll_ex(bContext *C, bool check_tool)
{
Object *ob = CTX_data_active_object(C);
- ScrArea *sa;
+ ScrArea *area;
if ((ob != NULL) && (ob->mode & OB_MODE_WEIGHT_PAINT) &&
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
- (sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
+ (area = CTX_wm_area(C)) && (area->spacetype == SPACE_VIEW3D)) {
ARegion *region = CTX_wm_region(C);
if (ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
@@ -1193,12 +1193,8 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
/** \name Enter Vertex/Weight Paint Mode
* \{ */
-static void ed_vwpaintmode_enter_generic(Main *bmain,
- Depsgraph *depsgraph,
- wmWindowManager *wm,
- Scene *scene,
- Object *ob,
- const eObjectMode mode_flag)
+static void ed_vwpaintmode_enter_generic(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, const eObjectMode mode_flag)
{
ob->mode |= mode_flag;
Mesh *me = BKE_mesh_from_object(ob);
@@ -1214,7 +1210,7 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->vpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, vertex_paint_poll);
+ paint_cursor_start(paint, vertex_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_VERTEX_PAINT);
}
else if (mode_flag == OB_MODE_WEIGHT_PAINT) {
@@ -1222,11 +1218,11 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->wpaint);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, paint_mode);
- paint_cursor_start_explicit(paint, wm, weight_paint_poll);
+ paint_cursor_start(paint, weight_paint_poll);
BKE_paint_init(bmain, scene, paint_mode, PAINT_CURSOR_WEIGHT_PAINT);
/* weight paint specific */
- ED_mesh_mirror_spatial_table(ob, NULL, NULL, NULL, 's');
+ ED_mesh_mirror_spatial_table_end(ob);
ED_vgroup_sync_from_pose(ob);
}
else {
@@ -1248,32 +1244,28 @@ static void ed_vwpaintmode_enter_generic(Main *bmain,
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
-void ED_object_vpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
+void ED_object_vpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_VERTEX_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_VERTEX_PAINT);
}
void ED_object_vpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
-void ED_object_wpaintmode_enter_ex(
- Main *bmain, Depsgraph *depsgraph, wmWindowManager *wm, Scene *scene, Object *ob)
+void ED_object_wpaintmode_enter_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- ed_vwpaintmode_enter_generic(bmain, depsgraph, wm, scene, ob, OB_MODE_WEIGHT_PAINT);
+ ed_vwpaintmode_enter_generic(bmain, depsgraph, scene, ob, OB_MODE_WEIGHT_PAINT);
}
void ED_object_wpaintmode_enter(struct bContext *C, Depsgraph *depsgraph)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
/** \} */
@@ -1318,8 +1310,8 @@ static void ed_vwpaintmode_exit_generic(Object *ob, const eObjectMode mode_flag)
paint_cursor_delete_textures();
if (mode_flag == OB_MODE_WEIGHT_PAINT) {
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(ob);
+ ED_mesh_mirror_topo_table_end(ob);
}
/* Never leave derived meshes behind. */
@@ -1384,8 +1376,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
if (depsgraph) {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint);
}
@@ -1398,7 +1389,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
*/
{
VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
if (md != NULL) {
/* Can be NULL. */
View3D *v3d = CTX_wm_view3d(C);
@@ -1450,8 +1441,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* for switching to/from mode */
-static bool paint_poll_test(bContext *C)
+static bool paint_mode_toggle_poll_test(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if (ob == NULL || ob->type != OB_MESH) {
@@ -1460,9 +1450,6 @@ static bool paint_poll_test(bContext *C)
if (!ob->data || ID_IS_LINKED(ob->data)) {
return 0;
}
- if (CTX_data_edit_object(C)) {
- return 0;
- }
return 1;
}
@@ -1476,7 +1463,7 @@ void PAINT_OT_weight_paint_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = wpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ ot->poll = paint_mode_toggle_poll_test;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2183,9 +2170,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -2231,22 +2218,22 @@ static void wpaint_paint_leaves(bContext *C,
data.strength = BKE_brush_weight_get(scene, brush);
/* NOTE: current mirroring code cannot be run in parallel */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode);
switch ((eBrushWeightPaintTool)brush->weightpaint_tool) {
case WPAINT_TOOL_AVERAGE:
calculate_average_weight(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
case WPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
break;
case WPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
break;
case WPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -2655,8 +2642,7 @@ static int vpaint_mode_toggle_exec(bContext *C, wmOperator *op)
if (depsgraph) {
depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
}
- wmWindowManager *wm = CTX_wm_manager(C);
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
BKE_paint_toolslots_brush_validate(bmain, &ts->vpaint->paint);
}
@@ -2683,7 +2669,7 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
/* api callbacks */
ot->exec = vpaint_mode_toggle_exec;
- ot->poll = paint_poll_test;
+ ot->poll = paint_mode_toggle_poll_test;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2698,19 +2684,19 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
/* Implementation notes:
*
* Operator->invoke()
- * - validate context (add mcol)
- * - create customdata storage
- * - call paint once (mouse click)
- * - add modal handler
+ * - Validate context (add #Mesh.mloopcol).
+ * - Create custom-data storage.
+ * - Call paint once (mouse click).
+ * - Add modal handler.
*
* Operator->modal()
- * - for every mousemove, apply vertex paint
- * - exit on mouse release, free customdata
+ * - For every mouse-move, apply vertex paint.
+ * - Exit on mouse release, free custom-data.
* (return OPERATOR_FINISHED also removes handler and operator)
*
* For future:
- * - implement a stroke event (or mousemove with past positions)
- * - revise whether op->customdata should be added in object, in set_vpaint
+ * - implement a stroke event (or mouse-move with past positions).
+ * - revise whether op->customdata should be added in object, in set_vpaint.
*/
struct VPaintData {
@@ -2722,8 +2708,10 @@ struct VPaintData {
struct VertProjHandle *vp_handle;
struct CoNo *vertexcosnos;
- /* modify 'me->mcol' directly, since the derived mesh is drawing from this
- * array, otherwise we need to refresh the modifier stack */
+ /**
+ * 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
@@ -3252,9 +3240,9 @@ static void calculate_average_color(SculptThreadedTaskData *data,
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
- BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -3298,21 +3286,21 @@ static void vpaint_paint_leaves(bContext *C,
.lcol = (uint *)me->mloopcol,
.me = me,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
case VPAINT_TOOL_BLUR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
break;
case VPAINT_TOOL_SMEAR:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
break;
case VPAINT_TOOL_DRAW:
- BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
index 6e706c907dd..addf7e9f868 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c
@@ -109,7 +109,7 @@ static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
+ uint paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint, false);
if (vertex_color_set(obact, paintcol)) {
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, obact);
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 103f312975a..08ffd8e620e 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -108,7 +108,7 @@ static bool weight_from_bones_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
- return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob));
+ return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && BKE_modifiers_is_deformed_by_armature(ob));
}
static int weight_from_bones_exec(bContext *C, wmOperator *op)
@@ -116,7 +116,7 @@ static int weight_from_bones_exec(bContext *C, wmOperator *op)
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- Object *armob = modifiers_isDeformedByArmature(ob);
+ Object *armob = BKE_modifiers_is_deformed_by_armature(ob);
Mesh *me = ob->data;
int type = RNA_enum_get(op->ptr, "type");
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 5a3067ef193..a483f63bc06 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -82,7 +82,7 @@ bool ED_wpaint_ensure_data(bContext *C,
/* this happens on a Bone select, when no vgroup existed yet */
if (ob->actdef <= 0) {
Object *modob;
- if ((modob = modifiers_isDeformedByArmature(ob))) {
+ if ((modob = BKE_modifiers_is_deformed_by_armature(ob))) {
Bone *actbone = ((bArmature *)modob->data)->act_bone;
if (actbone) {
bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c7b15d0c096..b4ae9c96ba7 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
@@ -153,12 +153,19 @@ const float *SCULPT_vertex_co_get(SculptSession *ss, int index)
return NULL;
}
-static void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- normal_short_to_float_v3(no, ss->mvert[index].no);
- return;
+ case PBVH_FACES: {
+ if (ss->shapekey_active || ss->deform_modifiers_active) {
+ const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh);
+ normal_short_to_float_v3(no, mverts[index].no);
+ }
+ else {
+ normal_short_to_float_v3(no, ss->mvert[index].no);
+ }
+ break;
+ }
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
@@ -196,33 +203,43 @@ float SCULPT_vertex_mask_get(SculptSession *ss, int index)
return 0.0f;
}
-static int SCULPT_active_vertex_get(SculptSession *ss)
+int SCULPT_active_vertex_get(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->active_vertex_index;
- case PBVH_BMESH:
- return ss->active_vertex_index;
- case PBVH_GRIDS:
- return ss->active_vertex_index;
+ if (ELEM(BKE_pbvh_type(ss->pbvh), PBVH_FACES, PBVH_BMESH, PBVH_GRIDS)) {
+ return ss->active_vertex_index;
}
-
return 0;
}
-static const float *SCULPT_active_vertex_co_get(SculptSession *ss)
+const float *SCULPT_active_vertex_co_get(SculptSession *ss)
{
return SCULPT_vertex_co_get(ss, SCULPT_active_vertex_get(ss));
}
-static void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3])
+void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3])
{
SCULPT_vertex_normal_get(ss, SCULPT_active_vertex_get(ss), normal);
}
/* Sculpt Face Sets and Visibility. */
-static void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
+int SCULPT_active_face_set_get(SculptSession *ss)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return ss->face_sets[ss->active_face_index];
+ case PBVH_GRIDS: {
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg,
+ ss->active_grid_index);
+ return ss->face_sets[face_index];
+ }
+ case PBVH_BMESH:
+ return SCULPT_FACE_SET_NONE;
+ }
+ return SCULPT_FACE_SET_NONE;
+}
+
+void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
@@ -237,24 +254,32 @@ static void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible
}
}
-static bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return !(ss->mvert[index].flag & ME_HIDE);
case PBVH_BMESH:
return !BM_elem_flag_test(BM_vert_at_index(ss->bm, index), BM_ELEM_HIDDEN);
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ 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);
+ }
+ }
}
return true;
}
-static void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible)
+void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) == face_set) {
if (visible) {
ss->face_sets[i] = abs(ss->face_sets[i]);
@@ -267,31 +292,29 @@ static void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static void SCULPT_face_sets_visibility_invert(SculptSession *ss)
+void SCULPT_face_sets_visibility_invert(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
ss->face_sets[i] *= -1;
}
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- for (int i = 0; i < ss->totpoly; i++) {
+ case PBVH_GRIDS:
+ for (int i = 0; i < ss->totfaces; i++) {
/* This can run on geometry without a face set assigned, so its ID sign can't be changed to
* modify the visibility. Force that geometry to the ID 1 to enable changing the visibility
@@ -310,12 +333,10 @@ static void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible)
break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
}
}
-static bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -335,7 +356,7 @@ static bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index)
return true;
}
-static bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index)
+bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -349,13 +370,17 @@ static bool SCULPT_vertex_all_face_sets_visible_get(SculptSession *ss, int index
}
case PBVH_BMESH:
return true;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index] > 0;
+ }
}
return true;
}
-static void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
+void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -368,12 +393,19 @@ static void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_se
} break;
case PBVH_BMESH:
break;
- case PBVH_GRIDS:
- break;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / 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);
+ }
+
+ } break;
}
}
-static int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
+int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -388,13 +420,17 @@ static int SCULPT_vertex_face_set_get(SculptSession *ss, int index)
}
case PBVH_BMESH:
return 0;
- case PBVH_GRIDS:
- 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 face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index];
+ }
}
return 0;
}
-static bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -408,8 +444,12 @@ static bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_se
}
case PBVH_BMESH:
return true;
- case PBVH_GRIDS:
- return true;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int face_index = BKE_subdiv_ccg_grid_to_face_index(ss->subdiv_ccg, grid_index);
+ return ss->face_sets[face_index] == face_set;
+ }
}
return true;
}
@@ -421,12 +461,23 @@ static void sculpt_visibility_sync_face_sets_to_vertex(SculptSession *ss, int in
void SCULPT_visibility_sync_all_face_sets_to_vertices(SculptSession *ss)
{
- for (int i = 0; i < ss->totvert; i++) {
- sculpt_visibility_sync_face_sets_to_vertex(ss, i);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES: {
+ for (int i = 0; i < ss->totvert; i++) {
+ sculpt_visibility_sync_face_sets_to_vertex(ss, i);
+ }
+ break;
+ }
+ case PBVH_GRIDS: {
+ BKE_pbvh_sync_face_sets_to_grids(ss->pbvh);
+ }
+ case PBVH_BMESH:
+ break;
}
}
-static void sculpt_visibility_sync_vertex_to_face_sets(SculptSession *ss, int index)
+static void UNUSED_FUNCTION(sculpt_visibility_sync_vertex_to_face_sets)(SculptSession *ss,
+ int index)
{
MeshElemMap *vert_map = &ss->pmap[index];
const bool visible = SCULPT_vertex_visible_get(ss, index);
@@ -444,7 +495,7 @@ static void sculpt_visibility_sync_vertex_to_face_sets(SculptSession *ss, int in
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->totpoly; i++) {
+ for (int i = 0; i < ss->totfaces; i++) {
MPoly *poly = &ss->mpoly[i];
bool poly_visible = true;
for (int l = 0; l < poly->totloop; l++) {
@@ -463,7 +514,7 @@ void SCULPT_visibility_sync_all_vertex_to_face_sets(SculptSession *ss)
}
}
-static bool sculpt_vertex_has_unique_face_set(SculptSession *ss, int index)
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -484,17 +535,18 @@ static bool sculpt_vertex_has_unique_face_set(SculptSession *ss, int index)
case PBVH_BMESH:
return false;
case PBVH_GRIDS:
- return false;
+ return true;
}
return false;
}
-static int SCULPT_face_set_next_available_get(SculptSession *ss)
+int SCULPT_face_set_next_available_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES: {
+ case PBVH_FACES:
+ case PBVH_GRIDS: {
int next_face_set = 0;
- for (int i = 0; i < ss->totpoly; i++) {
+ for (int i = 0; i < ss->totfaces; i++) {
if (abs(ss->face_sets[i]) > next_face_set) {
next_face_set = abs(ss->face_sets[i]);
}
@@ -504,8 +556,6 @@ static int SCULPT_face_set_next_available_get(SculptSession *ss)
}
case PBVH_BMESH:
return 0;
- case PBVH_GRIDS:
- return 0;
}
return 0;
}
@@ -638,7 +688,7 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
}
}
-static bool sculpt_vertex_is_boundary(SculptSession *ss, const int index)
+bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES: {
@@ -770,12 +820,12 @@ int SCULPT_nearest_vertex_get(
nvtd.nearest_vertex_index = -1;
nvtd.nearest_vertex_distance_squared = FLT_MAX;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = nearest_vertex_get_reduce;
settings.userdata_chunk = &nvtd;
settings.userdata_chunk_size = sizeof(NearestVertexTLSData);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
MEM_SAFE_FREE(nodes);
@@ -788,10 +838,10 @@ bool SCULPT_is_symmetry_iteration_valid(char i, char symm)
}
/* Checks if a vertex is inside the brush radius from any of its mirrored axis. */
-static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
- const float br_co[3],
- float radius,
- char symm)
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm)
{
for (char i = 0; i <= symm; ++i) {
if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
@@ -815,14 +865,38 @@ void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
SCULPT_vertex_random_access_init(ss);
flood->queue = BLI_gsqueue_new(sizeof(int));
- flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+ flood->visited_vertices = BLI_BITMAP_NEW(vertex_count, "visited vertices");
}
-static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
{
BLI_gsqueue_push(flood->queue, &index);
}
+void SCULPT_floodfill_add_initial_with_symmetry(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, int index, float radius)
+{
+ /* Add active vertex and symmetric vertices to the queue. */
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ for (char i = 0; i <= symm; ++i) {
+ if (SCULPT_is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = index;
+ }
+ 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);
+ v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ SCULPT_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
void SCULPT_floodfill_add_active(
Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, float radius)
{
@@ -841,7 +915,7 @@ void SCULPT_floodfill_add_active(
v = SCULPT_nearest_vertex_get(sd, ob, location, radius_squared, false);
}
if (v != -1) {
- sculpt_floodfill_add_initial(flood, v);
+ SCULPT_floodfill_add_initial(flood, v);
}
}
}
@@ -857,18 +931,17 @@ void SCULPT_floodfill_execute(
int from_v;
BLI_gsqueue_pop(flood->queue, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni)
- {
+ SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) {
const int to_v = ni.index;
- if (flood->visited_vertices[to_v] == 0 && SCULPT_vertex_visible_get(ss, to_v)) {
- flood->visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(flood->visited_vertices, to_v) && SCULPT_vertex_visible_get(ss, to_v)) {
+ BLI_BITMAP_ENABLE(flood->visited_vertices, to_v);
if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
BLI_gsqueue_push(flood->queue, &to_v);
}
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
}
@@ -893,11 +966,11 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob)
ModifierData *md;
VirtualModifierData virtualModifierData;
- md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+ md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
/* Exception for shape keys because we can edit those. */
for (; md; md = md->next) {
- if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+ if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
return true;
}
}
@@ -1137,7 +1210,7 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
* Factors: some brushes like grab cannot do dynamic topology.
* Others, like smooth, are better without. Same goes for alt-
* key smoothing. */
-static bool sculpt_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
@@ -1224,9 +1297,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
MEM_SAFE_FREE(nodes);
}
@@ -1301,6 +1374,8 @@ void SCULPT_brush_test_init(SculptSession *ss, SculptBrushTest *test)
test->radius_squared = ss->cache ? ss->cache->radius_squared :
ss->cursor_radius * ss->cursor_radius;
+ test->radius = sqrtf(test->radius_squared);
+
if (ss->cache) {
copy_v3_v3(test->location, ss->cache->location);
test->mirror_symmetry_pass = ss->cache->mirror_symmetry_pass;
@@ -1524,221 +1599,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
#endif
-/* Automasking */
-
-static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
-{
- if (sculpt_stroke_is_dynamic_topology(ss, br)) {
- return false;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
- return true;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS) {
- return true;
- }
- if (br->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
- return true;
- }
- return false;
-}
-
-float SCULPT_automasking_factor_get(SculptSession *ss, int vert)
-{
- if (ss->cache->automask) {
- return ss->cache->automask[vert];
- }
- else {
- return 1.0f;
- }
-}
-
-static void sculpt_automasking_end(Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->cache && ss->cache->automask) {
- MEM_freeN(ss->cache->automask);
- }
-}
-
-static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
-{
- /* 2D falloff is not constrained by radius. */
- if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
- return false;
- }
-
- if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) {
- return true;
- }
- return false;
-}
-
-typedef struct AutomaskFloodFillData {
- float *automask_factor;
- float radius;
- bool use_radius;
- float location[3];
- char symm;
-} AutomaskFloodFillData;
-
-static bool automask_floodfill_cb(
- SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
-{
- AutomaskFloodFillData *data = userdata;
-
- data->automask_factor[to_v] = 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));
-}
-
-static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return NULL;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Topology masking: pmap missing");
- return NULL;
- }
-
- const int totvert = SCULPT_vertex_count_get(ss);
- for (int i = 0; i < totvert; i++) {
- ss->cache->automask[i] = 0.0f;
- }
-
- /* Flood fill automask to connected vertices. Limited to vertices inside
- * the brush radius if the tool requires it. */
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
-
- AutomaskFloodFillData fdata = {
- .automask_factor = automask_factor,
- .radius = ss->cache->radius,
- .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
- .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
- };
- copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
- SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
- SCULPT_floodfill_free(&flood);
-
- return automask_factor;
-}
-
-static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return NULL;
- }
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Face Sets automasking: pmap missing");
- return NULL;
- }
-
- int tot_vert = SCULPT_vertex_count_get(ss);
- int active_face_set = SCULPT_vertex_face_set_get(ss, SCULPT_active_vertex_get(ss));
- for (int i = 0; i < tot_vert; i++) {
- if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
- automask_factor[i] *= 0.0f;
- }
- }
-
- return automask_factor;
-}
-
-#define EDGE_DISTANCE_INF -1
-
-static float *sculpt_boundary_edges_automasking_init(Object *ob,
- int propagation_steps,
- float *automask_factor)
-{
- SculptSession *ss = ob->sculpt;
-
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"Boundary Edges masking: pmap missing");
- return NULL;
- }
-
- const int totvert = SCULPT_vertex_count_get(ss);
- int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
-
- for (int i = 0; i < totvert; i++) {
- edge_distance[i] = EDGE_DISTANCE_INF;
- if (!sculpt_vertex_is_boundary(ss, i)) {
- edge_distance[i] = 0;
- }
- }
-
- for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
- for (int i = 0; i < totvert; i++) {
- if (edge_distance[i] == EDGE_DISTANCE_INF) {
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, i, ni)
- {
- if (edge_distance[ni.index] == propagation_it) {
- edge_distance[i] = propagation_it + 1;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
- }
- }
-
- for (int i = 0; i < totvert; i++) {
- if (edge_distance[i] != EDGE_DISTANCE_INF) {
- const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps);
- const float edge_boundary_automask = 3.0f * p * p - 2.0f * p * p * p;
- automask_factor[i] *= (1.0f - edge_boundary_automask);
- }
- }
-
- MEM_SAFE_FREE(edge_distance);
- return automask_factor;
-}
-
-static void sculpt_automasking_init(Sculpt *sd, Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
- const int totvert = SCULPT_vertex_count_get(ss);
-
- if (!sculpt_automasking_enabled(ss, brush)) {
- return;
- }
-
- ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
- "automask_factor");
-
- for (int i = 0; i < totvert; i++) {
- ss->cache->automask[i] = 1.0f;
- }
-
- if (brush->automasking_flags & BRUSH_AUTOMASKING_TOPOLOGY) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_topology_automasking_init(sd, ob, ss->cache->automask);
- }
- if (brush->automasking_flags & BRUSH_AUTOMASKING_FACE_SETS) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask);
- }
-
- if (brush->automasking_flags & BRUSH_AUTOMASKING_BOUNDARY_EDGES) {
- SCULPT_vertex_random_access_init(ss);
- sculpt_boundary_edges_automasking_init(
- ob, brush->automasking_boundary_edges_propagation_steps, ss->cache->automask);
- }
-}
-
/* ===== Sculpting =====
*/
static void flip_v3(float v[3], const ePaintSymmetryFlags symm)
@@ -1863,10 +1723,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
/* Update the test radius to sample the normal using the normal radius of the brush. */
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(normal_test.radius_squared);
- /* Layer brush produces artifacts with normal and area radius. */
- if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
- test_radius *= data->brush->normal_radius_factor;
- }
+ test_radius *= data->brush->normal_radius_factor;
+ normal_test.radius = test_radius;
normal_test.radius_squared = test_radius * test_radius;
}
@@ -1877,16 +1735,15 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
if (data->brush->ob_mode == OB_MODE_SCULPT) {
float test_radius = sqrtf(area_test.radius_squared);
/* Layer brush produces artifacts with normal and area radius */
- if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
- /* Enable area radius control only on Scrape for now */
- if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
- data->brush->area_radius_factor > 0.0f) {
- test_radius *= data->brush->area_radius_factor;
- }
- else {
- test_radius *= data->brush->normal_radius_factor;
- }
+ /* Enable area radius control only on Scrape for now */
+ if (ELEM(data->brush->sculpt_tool, SCULPT_TOOL_SCRAPE, SCULPT_TOOL_FILL) &&
+ data->brush->area_radius_factor > 0.0f) {
+ test_radius *= data->brush->area_radius_factor;
}
+ else {
+ test_radius *= data->brush->normal_radius_factor;
+ }
+ area_test.radius = test_radius;
area_test.radius_squared = test_radius * test_radius;
}
@@ -1920,10 +1777,26 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
if (use_area_cos && area_test_r) {
+ /* Weight the coordinates towards the center. */
+ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius);
+ float afactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(afactor, 0.0f, 1.0f);
+
+ float disp[3];
+ sub_v3_v3v3(disp, co, area_test.location);
+ mul_v3_fl(disp, 1.0f - afactor);
+ add_v3_v3v3(co, area_test.location, disp);
add_v3_v3(anctd->area_cos[flip_index], co);
+
anctd->count_co[flip_index] += 1;
}
if (use_area_nos && normal_test_r) {
+ /* Weight the normals towards the center. */
+ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius);
+ float nfactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(nfactor, 0.0f, 1.0f);
+ mul_v3_fl(no, nfactor);
+
add_v3_v3(anctd->area_nos[flip_index], no);
anctd->count_no[flip_index] += 1;
}
@@ -1933,54 +1806,73 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
else {
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- const float *co;
+ float co[3];
+
/* For bm_vert only. */
- const short *no_s;
+ short no_s[3];
if (use_original) {
if (unode->bm_entry) {
- BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &co, &no_s);
+ const float *temp_co;
+ const short *temp_no_s;
+ BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s);
+ copy_v3_v3(co, temp_co);
+ copy_v3_v3_short(no_s, temp_no_s);
}
else {
- co = unode->co[vd.i];
- no_s = unode->no[vd.i];
+ copy_v3_v3(co, unode->co[vd.i]);
+ copy_v3_v3_short(no_s, unode->no[vd.i]);
}
}
else {
- co = vd.co;
+ copy_v3_v3(co, vd.co);
}
normal_test_r = sculpt_brush_normal_test_sq_fn(&normal_test, co);
area_test_r = sculpt_brush_area_test_sq_fn(&area_test, co);
if (normal_test_r || area_test_r) {
- float no_buf[3];
- const float *no;
+ float no[3];
int flip_index;
data->any_vertex_sampled = true;
if (use_original) {
- normal_short_to_float_v3(no_buf, no_s);
- no = no_buf;
+ normal_short_to_float_v3(no, no_s);
}
else {
if (vd.no) {
- normal_short_to_float_v3(no_buf, vd.no);
- no = no_buf;
+ normal_short_to_float_v3(no, vd.no);
}
else {
- no = vd.fno;
+ copy_v3_v3(no, vd.fno);
}
}
flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
0.0f);
+
if (use_area_cos && area_test_r) {
+ /* Weight the coordinates towards the center. */
+ float p = 1.0f - (sqrtf(area_test.dist) / area_test.radius);
+ float afactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(afactor, 0.0f, 1.0f);
+
+ float disp[3];
+ sub_v3_v3v3(disp, co, area_test.location);
+ mul_v3_fl(disp, 1.0f - afactor);
+ add_v3_v3v3(co, area_test.location, disp);
+
add_v3_v3(anctd->area_cos[flip_index], co);
anctd->count_co[flip_index] += 1;
}
if (use_area_nos && normal_test_r) {
+ /* Weight the normals towards the center. */
+ float p = 1.0f - (sqrtf(normal_test.dist) / normal_test.radius);
+ float nfactor = 3.0f * p * p - 2.0f * p * p * p;
+ CLAMP(nfactor, 0.0f, 1.0f);
+ mul_v3_fl(no, nfactor);
+
add_v3_v3(anctd->area_nos[flip_index], no);
anctd->count_no[flip_index] += 1;
}
@@ -2015,7 +1907,7 @@ static void calc_area_center(
{
const Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
/* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
@@ -2031,12 +1923,12 @@ static void calc_area_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -2074,7 +1966,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
float r_area_no[3])
{
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
@@ -2090,12 +1982,12 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush,
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For area normal. */
for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) {
@@ -2114,7 +2006,7 @@ static void calc_area_normal_and_center(
{
const Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
- const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
+ const bool has_bm_orco = ss->bm && SCULPT_stroke_is_dynamic_topology(ss, brush);
int n;
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
@@ -2131,12 +2023,12 @@ static void calc_area_normal_and_center(
AreaNormalCenterTLSData anctd = {{{0}}};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
settings.func_reduce = calc_area_normal_and_center_reduce;
settings.userdata_chunk = &anctd;
settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData);
- BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
/* For flatten center. */
for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
@@ -2206,9 +2098,13 @@ static float brush_strength(const Sculpt *sd,
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
case SCULPT_TOOL_CLOTH:
- /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
- * the same vertices. */
- if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
+ /* Grab deform uses the same falloff as a regular grab brush. */
+ return root_alpha * feather;
+ }
+ else if (brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_EXPAND) {
+ /* Expand is more sensible to strength as it keeps expanding the cloth when sculpting over
+ * the same vertices. */
return 0.1f * alpha * flip * pressure * overlap * feather;
}
else {
@@ -2222,7 +2118,7 @@ static float brush_strength(const Sculpt *sd,
return alpha * pressure * overlap * feather * 2.0f;
case SCULPT_TOOL_CLAY_STRIPS:
/* Clay Strips needs less strength to compensate the curve. */
- final_pressure = pressure * pressure * pressure;
+ final_pressure = powf(pressure, 1.5f);
return alpha * flip * final_pressure * overlap * feather * 0.3f;
case SCULPT_TOOL_CLAY_THUMB:
final_pressure = pressure * pressure;
@@ -2476,7 +2372,7 @@ bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v)
}
/* Handles clipping against a mirror modifier and SCULPT_LOCK axis flags. */
-static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3])
{
for (int i = 0; i < 3; i++) {
if (sd->flags & (SCULPT_LOCK_X << i)) {
@@ -2681,227 +2577,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob)
}
}
-/* For the smooth brush, uses the neighboring vertices around vert to calculate
- * a smoothed location for vert. Skips corner vertices (used by only one
- * polygon). */
-static void neighbor_average(SculptSession *ss, float avg[3], uint vert)
-{
- const MeshElemMap *vert_map = &ss->pmap[vert];
- const MVert *mvert = ss->mvert;
- float(*deform_co)[3] = ss->deform_cos;
-
- /* Don't modify corner vertices. */
- if (vert_map->count > 1) {
- int total = 0;
-
- zero_v3(avg);
-
- for (int i = 0; i < vert_map->count; i++) {
- const MPoly *p = &ss->mpoly[vert_map->indices[i]];
- uint f_adj_v[2];
-
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] : mvert[f_adj_v[j]].co);
-
- total++;
- }
- }
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
-
- copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
-}
-
-/* Similar to neighbor_average(), but returns an averaged mask value
- * instead of coordinate. Also does not restrict based on border or
- * corner vertices. */
-static float neighbor_average_mask(SculptSession *ss, uint vert)
-{
- const float *vmask = ss->vmask;
- float avg = 0.0f;
- int total = 0;
-
- for (int i = 0; i < ss->pmap[vert].count; i++) {
- const MPoly *p = &ss->mpoly[ss->pmap[vert].indices[i]];
- uint f_adj_v[2];
-
- if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
- for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- avg += vmask[f_adj_v[j]];
- total++;
- }
- }
- }
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- return vmask[vert];
- }
-}
-
-/* Same logic as neighbor_average(), but for bmesh rather than mesh. */
-static void bmesh_neighbor_average(float avg[3], BMVert *v)
-{
- /* logic for 3 or more is identical. */
- const int vfcount = BM_vert_face_count_at_most(v, 3);
-
- /* Don't modify corner vertices. */
- if (vfcount > 1) {
- BMIter liter;
- BMLoop *l;
- int total = 0;
-
- zero_v3(avg);
-
- 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 (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- add_v3_v3(avg, v_other->co);
- total++;
- }
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- return;
- }
- }
-
- copy_v3_v3(avg, v->co);
-}
-
-/* For bmesh: Average surrounding verts based on an orthogonality measure.
- * Naturally converges to a quad-like structure. */
-static void bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
-{
-
- float avg_co[3] = {0.0f, 0.0f, 0.0f};
- float tot_co = 0.0f;
-
- BMIter eiter;
- BMEdge *e;
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_edge_is_boundary(e)) {
- copy_v3_v3(avg, v->co);
- return;
- }
- BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
- normalize_v3(vec);
-
- /* fac is a measure of how orthogonal or parallel the edge is
- * relative to the direction. */
- float fac = dot_v3v3(vec, direction);
- fac = fac * fac - 0.5f;
- fac *= fac;
- madd_v3_v3fl(avg_co, v_other->co, fac);
- tot_co += fac;
- }
-
- /* In case vert has no Edge s. */
- if (tot_co > 0.0f) {
- mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
-
- /* Preserve volume. */
- float vec[3];
- sub_v3_v3(avg, v->co);
- mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
- sub_v3_v3(avg, vec);
- add_v3_v3(avg, v->co);
- }
- else {
- zero_v3(avg);
- }
-}
-
-/* Same logic as neighbor_average_mask(), but for bmesh rather than mesh. */
-static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offset)
-{
- BMIter liter;
- BMLoop *l;
- float avg = 0.0f;
- int total = 0;
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- /* Skip this vertex. */
- 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];
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v_other, cd_vert_mask_offset);
- avg += (*vmask);
- total++;
- }
- }
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- const float *vmask = BM_ELEM_CD_GET_VOID_P(v, cd_vert_mask_offset);
- return (*vmask);
- }
-}
-
-static void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index)
-{
- 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));
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- mul_v3_v3fl(result, avg, 1.0f / (float)total);
- }
- else {
- copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
- }
-}
-
-static float grids_neighbor_average_mask(SculptSession *ss, int index)
-{
- 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);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- return avg / (float)total;
- }
- else {
- return SCULPT_vertex_mask_get(ss, index);
- }
-}
-
/* Note: uses after-struct allocated mem to store actual cache... */
typedef struct SculptDoBrushSmoothGridDataChunk {
size_t tmpgrid_size;
@@ -2918,17 +2593,10 @@ typedef struct {
int active_vertex_index;
float *face_normal;
- struct IsectRayPrecalc isect_precalc;
-} SculptRaycastData;
-
-typedef struct {
- const float *ray_start;
- bool hit;
- float depth;
- float edge_length;
+ int active_face_grid_index;
struct IsectRayPrecalc isect_precalc;
-} SculptDetailRaycastData;
+} SculptRaycastData;
typedef struct {
SculptSession *ss;
@@ -2939,119 +2607,6 @@ typedef struct {
bool original;
} SculptFindNearestToRayData;
-static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(
- ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- neighbor_average(ss, avg, vd.vert_indices[vd.i]);
- 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) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : *vd.mask,
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- val *= fade * bstrength;
- *vd.mask += val;
- CLAMP(*vd.mask, 0.0f, 1.0f);
- }
- else {
- float avg[3], val[3];
-
- bmesh_neighbor_average(avg, vd.bm_vert);
- 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) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
@@ -3081,32 +2636,27 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength *
- SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- *vd.mask,
- vd.index,
- tls->thread_id) *
- ss->cache->pressure;
+ 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->cache->pressure;
float avg[3], val[3];
- bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
+ SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert);
sub_v3_v3v3(val, avg, vd.co);
madd_v3_v3v3fl(val, vd.co, val, fade);
- sculpt_clip(sd, ss, vd.co, val);
+ SCULPT_clip(sd, ss, vd.co, val);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -3116,111 +2666,6 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- Sculpt *sd = data->sd;
- const Brush *brush = data->brush;
- const bool smooth_mask = data->smooth_mask;
- float bstrength = data->strength;
-
- PBVHVertexIter vd;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(
- ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
- vd.index,
- tls->thread_id);
- if (smooth_mask) {
- float val = grids_neighbor_average_mask(ss, vd.index) - *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(ss, avg, vd.index);
- sub_v3_v3v3(val, avg, vd.co);
- madd_v3_v3v3fl(val, vd.co, val, fade);
- sculpt_clip(sd, ss, vd.co, val);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void smooth(Sculpt *sd,
- Object *ob,
- PBVHNode **nodes,
- const int totnode,
- float bstrength,
- const bool smooth_mask)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- const int max_iterations = 4;
- const float fract = 1.0f / max_iterations;
- PBVHType type = BKE_pbvh_type(ss->pbvh);
- int iteration, count;
- float last;
-
- CLAMP(bstrength, 0.0f, 1.0f);
-
- count = (int)(bstrength * max_iterations);
- last = max_iterations * (bstrength - count * fract);
-
- if (type == PBVH_FACES && !ss->pmap) {
- BLI_assert(!"sculpt smooth: pmap missing");
- return;
- }
-
- for (iteration = 0; iteration <= count; iteration++) {
- const float strength = (iteration != count) ? 1.0f : last;
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- .smooth_mask = smooth_mask,
- .strength = strength,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
-
- switch (type) {
- case PBVH_GRIDS:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
- break;
- case PBVH_FACES:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
- break;
- case PBVH_BMESH:
- BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
- break;
- }
- }
-}
-
static void bmesh_topology_rake(
Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength)
{
@@ -3243,163 +2688,10 @@ static void bmesh_topology_rake(
.nodes = nodes,
.strength = factor,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
- }
-}
-
-static void do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
-}
-/* HC Smooth Algorithm. */
-/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
-
-static void surface_smooth_laplacian_step(SculptSession *ss,
- float *disp,
- const float co[3],
- float (*laplacian_disp)[3],
- const int v_index,
- 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);
-
- mul_v3_v3fl(weigthed_o, origco, alpha);
- mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
- add_v3_v3v3(d, weigthed_o, weigthed_q);
- sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
-
- sub_v3_v3v3(disp, laplacian_smooth_co, co);
-}
-
-static void surface_smooth_displace_step(SculptSession *ss,
- float *co,
- float (*laplacian_disp)[3],
- const int v_index,
- const float beta,
- const float fade)
-{
- float b_avg[3] = {0.0f, 0.0f, 0.0f};
- float b_current_vertex[3];
- int total = 0;
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, v_index, ni)
- {
- add_v3_v3(b_avg, laplacian_disp[ni.index]);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
- if (total > 0) {
- mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)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));
- sub_v3_v3(co, b_current_vertex);
- }
-}
-
-static void do_surface_smooth_brush_laplacian_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
- float alpha = brush->surface_smooth_shape_preservation;
-
- PBVHVertexIter vd;
- SculptOrigVertData orig_data;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
-
- float disp[3];
- surface_smooth_laplacian_step(ss,
- disp,
- vd.co,
- ss->cache->surface_smooth_laplacian_disp,
- vd.index,
- orig_data.co,
- alpha);
- madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
- }
- BKE_pbvh_vertex_iter_end;
- }
-}
-
-static void do_surface_smooth_brush_displace_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
- const float beta = brush->surface_smooth_current_vertex;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade =
- bstrength *
- SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
- surface_smooth_displace_step(
- ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- Brush *brush = BKE_paint_brush(&sd->paint);
- SculptSession *ss = ob->sculpt;
-
- if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0) {
- ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
- SCULPT_vertex_count_get(ss) * 3 * sizeof(float), "HC smooth laplacian b");
- }
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- for (int i = 0; i < brush->surface_smooth_iterations; i++) {
- BKE_pbvh_parallel_range(
- 0, totnode, &data, do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
- BKE_pbvh_parallel_range(
- 0, totnode, &data, do_surface_smooth_brush_displace_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
}
@@ -3417,12 +2709,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
if (sculpt_brush_test_sq_fn(&test, vd.co)) {
const float fade = SCULPT_brush_strength_factor(
- ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id);
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
if (bstrength > 0.0f) {
(*vd.mask) += fade * bstrength * (1.0f - *vd.mask);
@@ -3452,9 +2745,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -3467,7 +2760,7 @@ static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
do_mask_brush_draw(sd, ob, nodes, totnode);
break;
case BRUSH_MASK_SMOOTH:
- smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true);
break;
}
}
@@ -3489,6 +2782,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3502,7 +2796,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3539,129 +2833,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
-}
-
-static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- const float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
-
- if (fade > 0.05f) {
- SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- const Brush *brush = data->brush;
- float bstrength = ss->cache->bstrength;
-
- PBVHVertexIter vd;
-
- SculptBrushTest test;
- SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
- ss, &test, data->brush->falloff_shape);
-
- const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
- /* This operations needs a stregth tweak as the relax deformation is too weak by default. */
- if (relax_face_sets) {
- bstrength *= 2.0f;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- if (sculpt_brush_test_sq_fn(&test, vd.co)) {
- if (relax_face_sets != sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
-
- SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
-{
- SculptSession *ss = ob->sculpt;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 &&
- ss->cache->radial_symmetry_pass == 0) {
- if (ss->cache->invert) {
- /* When inverting the brush, pick the paint face mask ID from the mesh. */
- ss->cache->paint_face_set = SCULPT_vertex_face_set_get(ss, SCULPT_active_vertex_get(ss));
- }
- else {
- /* By default create a new Face Sets. */
- ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
- }
- }
-
- BKE_curvemapping_initialize(brush->curve);
-
- /* Threaded loop over nodes. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .brush = brush,
- .nodes = nodes,
- };
-
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- if (ss->cache->alt_smooth) {
- for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
- }
- }
- else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
- }
+ BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
}
static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
@@ -3684,6 +2858,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3698,7 +2873,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3735,9 +2910,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -3764,6 +2939,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3777,7 +2953,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float current_disp[3];
float current_disp_norm[3];
float final_disp[3];
@@ -3786,8 +2962,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
normalize_v3_v3(current_disp_norm, current_disp);
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.index, ni) {
float vertex_disp[3];
float vertex_disp_norm[3];
sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co);
@@ -3796,7 +2971,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp));
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
mul_v3_v3fl(proxy[vd.i], final_disp, fade);
@@ -3820,15 +2995,14 @@ void SCULPT_relax_vertex(SculptSession *ss,
zero_v3(smooth_pos);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
- {
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
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.index))) {
add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index));
count++;
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (count > 0) {
mul_v3_fl(smooth_pos, 1.0f / (float)count);
@@ -3880,6 +3054,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -3893,7 +3068,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co);
if (vd.mvert) {
@@ -3922,15 +3097,15 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
if (ss->cache->alt_smooth) {
for (int i = 0; i < 4; i++) {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings);
}
}
else {
- BKE_pbvh_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings);
}
}
@@ -4043,6 +3218,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4056,7 +3232,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val1[3];
float val2[3];
@@ -4131,9 +3307,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.flippedbstrength = flippedbstrength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
}
static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
@@ -4154,6 +3330,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float x_object_space[3];
float z_object_space[3];
@@ -4171,7 +3348,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float disp_center[3];
float x_disp[3];
float z_disp[3];
@@ -4244,9 +3421,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.stroke_xz = stroke_xz,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
}
static void do_grab_brush_task_cb_ex(void *__restrict userdata,
@@ -4270,6 +3447,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4284,7 +3462,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -4316,9 +3494,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
}
static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata,
@@ -4425,9 +3603,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
}
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3])
@@ -4587,6 +3765,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4599,7 +3778,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4631,9 +3810,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
}
static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
@@ -4660,6 +3839,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4672,7 +3852,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -4752,9 +3932,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
}
static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
@@ -4778,6 +3958,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4792,7 +3973,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -4824,9 +4005,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
}
static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
@@ -4850,6 +4031,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -4865,7 +4047,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
NULL,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
sub_v3_v3v3(vec, orig_data.co, ss->cache->location);
axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade);
@@ -4897,9 +4079,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
}
static void do_layer_brush_task_cb_ex(void *__restrict userdata,
@@ -4910,64 +4092,83 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata,
SculptSession *ss = data->ob->sculpt;
Sculpt *sd = data->sd;
const Brush *brush = data->brush;
- const float *offset = data->offset;
+
+ const bool use_persistent_base = ss->layer_base && brush->flag & BRUSH_PERSISTENT;
PBVHVertexIter vd;
SculptOrigVertData orig_data;
- float *layer_disp;
const float bstrength = ss->cache->bstrength;
- const float lim = (bstrength < 0.0f) ? -data->brush->height : data->brush->height;
- /* XXX: layer brush needs conversion to proxy but its more complicated */
- /* proxy = BKE_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; */
-
SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
- /* Why does this have to be thread-protected? */
- BLI_mutex_lock(&data->mutex);
- layer_disp = BKE_pbvh_node_layer_disp_get(ss->pbvh, data->nodes[n]);
- BLI_mutex_unlock(&data->mutex);
-
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SCULPT_orig_vert_data_update(&orig_data, &vd);
if (sculpt_brush_test_sq_fn(&test, orig_data.co)) {
- const float fade = bstrength * SCULPT_brush_strength_factor(ss,
- brush,
- vd.co,
- sqrtf(test.dist),
- vd.no,
- vd.fno,
- vd.mask ? *vd.mask : 0.0f,
- vd.index,
- tls->thread_id);
- float *disp = &layer_disp[vd.i];
- float val[3];
-
- *disp += fade;
+ const float fade = SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
- /* Don't let the displacement go past the limit. */
- if ((lim < 0.0f && *disp < lim) || (lim >= 0.0f && *disp > lim)) {
- *disp = lim;
+ const int vi = vd.index;
+ float *disp_factor;
+ if (use_persistent_base) {
+ disp_factor = &ss->layer_base[vi].disp;
+ }
+ else {
+ disp_factor = &ss->cache->layer_displacement_factor[vi];
}
- mul_v3_v3fl(val, offset, *disp);
+ /* When using persistent base, the layer brush Ctrl invert mode resets the height of the
+ * layer to 0. This makes possible to clean edges of previously added layers on top of the
+ * base. */
+ /* The main direction of the layers is inverted using the regular brush strength with the
+ * brush direction property. */
+ if (use_persistent_base && ss->cache->invert) {
+ (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) *
+ ((*disp_factor) > 0.0f ? -1.0f : 1.0f);
+ }
+ else {
+ (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor));
+ }
+ if (vd.mask) {
+ const float clamp_mask = 1.0f - *vd.mask;
+ CLAMP(*disp_factor, -clamp_mask, clamp_mask);
+ }
+ else {
+ CLAMP(*disp_factor, -1.0f, 1.0f);
+ }
- if (!ss->multires && !ss->bm && ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- int index = vd.vert_indices[vd.i];
+ float final_co[3];
+ float normal[3];
- /* Persistent base. */
- add_v3_v3(val, ss->layer_co[index]);
+ if (use_persistent_base) {
+ copy_v3_v3(normal, ss->layer_base[vi].no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, ss->layer_base[vi].co, normal, *disp_factor);
}
else {
- add_v3_v3(val, orig_data.co);
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_fl(normal, brush->height);
+ madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor);
}
- sculpt_clip(sd, ss, vd.co, val);
+ float vdisp[3];
+ sub_v3_v3v3(vdisp, final_co, vd.co);
+ mul_v3_fl(vdisp, fabsf(fade));
+ add_v3_v3v3(final_co, vd.co, vdisp);
+
+ SCULPT_clip(sd, ss, vd.co, final_co);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
@@ -4981,24 +4182,22 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float offset[3];
- mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
+ if (ss->cache->layer_displacement_factor == NULL) {
+ ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "layer displacement factor");
+ }
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
- .offset = offset,
};
- BLI_mutex_init(&data.mutex);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
-
- BLI_mutex_end(&data.mutex);
+ BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
}
static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
@@ -5018,6 +4217,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5030,7 +4230,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float val[3];
if (vd.fno) {
@@ -5062,9 +4262,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
}
int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3])
@@ -5120,6 +4320,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5142,7 +4343,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5186,9 +4387,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -5274,6 +4475,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5294,7 +4496,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5336,13 +4538,13 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
ClaySampleData csd = {{0}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_clay_surface_reduce;
sample_settings.userdata_chunk = &csd;
sample_settings.userdata_chunk_size = sizeof(ClaySampleData);
- BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
+ BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings);
float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]);
d_offset = min_ff(radius, d_offset);
@@ -5367,9 +4569,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
}
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
@@ -5393,6 +4595,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
SCULPT_brush_test_init(ss, &test);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5416,7 +4619,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5438,7 +4641,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
const bool flip = (ss->cache->bstrength < 0.0f);
const float radius = flip ? -ss->cache->radius : ss->cache->radius;
const float offset = SCULPT_brush_plane_offset_get(sd, ss);
- const float displace = radius * (0.25f + offset);
+ const float displace = radius * (0.18f + offset);
/* The sculpt-plane normal (whatever its set to). */
float area_no_sp[3];
@@ -5500,9 +4703,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.mat = mat,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
}
static void do_fill_brush_task_cb_ex(void *__restrict userdata,
@@ -5524,6 +4727,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
@@ -5547,7 +4751,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5593,9 +4797,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
}
static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
@@ -5617,6 +4821,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
plane_from_point_normal_v3(test.plane_tool, area_co, area_no);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
@@ -5639,7 +4844,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5685,9 +4890,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_co = area_co,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
}
/* -------------------------------------------------------------------- */
@@ -5715,6 +4920,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
float plane_tilt[4];
float normal_tilt[3];
@@ -5755,7 +4961,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -5770,10 +4976,10 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata,
static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache)
{
float final_pressure = 0.0f;
- for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
final_pressure += cache->clay_pressure_stabilizer[i];
}
- return final_pressure / (float)CLAY_STABILIZER_LEN;
+ return final_pressure / (float)SCULPT_CLAY_STABILIZER_LEN;
}
static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -5857,9 +5063,9 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.clay_strength = clay_strength,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings);
}
/** \} */
@@ -5881,6 +5087,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -5893,7 +5100,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -5928,9 +5135,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
}
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -6109,6 +5316,23 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
+ /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
+ * vertices and uses regular coords undo. */
+ /* It also assigns the paint_face_set here as it needs to be done regardless of the stroke type
+ * and the number of nodes under the brush influence. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
+ ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_FACE_SETS);
+ if (ss->cache->invert) {
+ /* When inverting the brush, pick the paint face mask ID from the mesh. */
+ ss->cache->paint_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ /* By default create a new Face Sets. */
+ ss->cache->paint_face_set = SCULPT_face_set_next_available_get(ss);
+ }
+ }
+
/* Only act if some verts are inside the brush area. */
if (totnode) {
float location[3];
@@ -6120,16 +5344,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
-
- /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the
- * vertices and uses regular coords undo. */
- if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time &&
- ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) {
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
- }
+ BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -6140,8 +5357,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0) {
- if (sculpt_automasking_enabled(ss, brush)) {
- sculpt_automasking_init(sd, ob);
+ if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ SCULPT_automasking_init(sd, ob);
}
}
@@ -6159,10 +5376,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
break;
case SCULPT_TOOL_SMOOTH:
if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) {
- do_smooth_brush(sd, ob, nodes, totnode);
+ SCULPT_do_smooth_brush(sd, ob, nodes, totnode);
}
else if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE) {
- do_surface_smooth_brush(sd, ob, nodes, totnode);
+ SCULPT_do_surface_smooth_brush(sd, ob, nodes, totnode);
}
break;
case SCULPT_TOOL_CREASE:
@@ -6245,22 +5462,22 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
SCULPT_do_cloth_brush(sd, ob, nodes, totnode);
break;
case SCULPT_TOOL_DRAW_FACE_SETS:
- do_draw_face_sets_brush(sd, ob, nodes, totnode);
+ SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode);
break;
}
if (!ELEM(brush->sculpt_tool, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_MASK) &&
brush->autosmooth_factor > 0) {
if (brush->flag & BRUSH_INVERSE_SMOOTH_PRESSURE) {
- smooth(sd,
- ob,
- nodes,
- totnode,
- brush->autosmooth_factor * (1.0f - ss->cache->pressure),
- false);
+ SCULPT_smooth(sd,
+ ob,
+ nodes,
+ totnode,
+ brush->autosmooth_factor * (1.0f - ss->cache->pressure),
+ false);
}
else {
- smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
+ SCULPT_smooth(sd, ob, nodes, totnode, brush->autosmooth_factor, false);
}
}
@@ -6269,7 +5486,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
}
/* The cloth brush adds the gravity as a regular force and it is processed in the solver. */
- if (ss->cache->supports_gravity && brush->sculpt_tool != SCULPT_TOOL_CLOTH) {
+ if (ss->cache->supports_gravity &&
+ !ELEM(brush->sculpt_tool, SCULPT_TOOL_CLOTH, SCULPT_TOOL_DRAW_FACE_SETS)) {
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
@@ -6354,7 +5572,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
add_v3_v3(val, proxies[p].co[vd.i]);
}
- sculpt_clip(sd, ss, vd.co, val);
+ SCULPT_clip(sd, ss, vd.co, val);
if (ss->deform_modifiers_active) {
sculpt_flush_pbvhvert_deform(ob, &vd);
@@ -6383,9 +5601,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
}
MEM_SAFE_FREE(nodes);
@@ -6415,7 +5633,7 @@ static void sculpt_update_keyblock(Object *ob)
}
}
-static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
+static void SCULPT_flush_stroke_deform_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
{
@@ -6439,7 +5657,7 @@ static void sculpt_flush_stroke_deform_task_cb(void *__restrict userdata,
}
/* Flush displacement from deformed PBVH to original layer. */
-static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
+void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -6471,9 +5689,9 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
.vertCos = vertCos,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
+ BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings);
if (vertCos) {
SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos);
@@ -6632,7 +5850,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
Brush *brush = BKE_paint_brush(&sd->paint);
MTex *mtex = &brush->mtex;
- if (ss->multires && mtex->tex && mtex->tex->type == TEX_NOISE) {
+ if (ss->multires.active && mtex->tex && mtex->tex->type == TEX_NOISE) {
multires_stitch_grids(ob);
}
}
@@ -6784,9 +6002,10 @@ static const char *sculpt_tool_name(Sculpt *sd)
void SCULPT_cache_free(StrokeCache *cache)
{
- if (cache->dial) {
- MEM_freeN(cache->dial);
- }
+ MEM_SAFE_FREE(cache->dial);
+ MEM_SAFE_FREE(cache->surface_smooth_laplacian_disp);
+ MEM_SAFE_FREE(cache->layer_displacement_factor);
+
if (cache->pose_ik_chain) {
SCULPT_pose_ik_chain_free(cache->pose_ik_chain);
}
@@ -6844,14 +6063,9 @@ static void sculpt_update_cache_invariants(
ss->cache = cache;
/* Set scaling adjustment. */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- max_scale = 1.0f;
- }
- else {
- max_scale = 0.0f;
- for (int i = 0; i < 3; i++) {
- max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
- }
+ max_scale = 0.0f;
+ for (int i = 0; i < 3; i++) {
+ max_scale = max_ff(max_scale, fabsf(ob->scale[i]));
}
cache->scale[0] = max_scale / ob->scale[0];
cache->scale[1] = max_scale / ob->scale[1];
@@ -6967,32 +6181,6 @@ static void sculpt_update_cache_invariants(
normalize_v3(cache->true_gravity_direction);
}
- /* Initialize layer brush displacements and persistent coords. */
- if (brush->sculpt_tool == SCULPT_TOOL_LAYER) {
- /* Not supported yet for multires or dynamic topology. */
- if (!ss->multires && !ss->bm && !ss->layer_co && (brush->flag & BRUSH_PERSISTENT)) {
- if (!ss->layer_co) {
- ss->layer_co = MEM_mallocN(sizeof(float) * 3 * ss->totvert, "sculpt mesh vertices copy");
- }
-
- if (ss->deform_cos) {
- memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
- }
- else {
- for (int i = 0; i < ss->totvert; i++) {
- copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
- }
- }
- }
-
- if (ss->bm) {
- /* Free any remaining layer displacements from nodes. If not and topology changes
- * from using another tool, then next layer toolstroke
- * can access past disp array bounds. */
- BKE_pbvh_free_layer_disp(ss->pbvh);
- }
- }
-
/* Make copies of the mesh vertex locations and normals for some tools. */
if (brush->flag & BRUSH_ANCHORED) {
cache->original = true;
@@ -7029,7 +6217,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
case SCULPT_TOOL_CLAY:
return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure));
case SCULPT_TOOL_CLAY_STRIPS:
- return max_ff(initial_size * 0.30f, initial_size * pow2f(cache->pressure));
+ return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f));
case SCULPT_TOOL_CLAY_THUMB: {
float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache);
return initial_size * clay_stabilized_pressure;
@@ -7039,6 +6227,34 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo
}
}
+/* In these brushes the grab delta is calculated always from the initial stroke location, which is
+ * generally used to create grab deformations. */
+static bool sculpt_needs_delta_from_anchored_origin(Brush *brush)
+{
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_POSE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ELASTIC_DEFORM) ||
+ SCULPT_is_cloth_deform_brush(brush);
+}
+
+/* In these brushes the grab delta is calculated from the previous stroke location, which is used
+ * to calculate to orientate the brush tip and deformation towards the stroke direction. */
+static bool sculpt_needs_delta_for_tip_orientation(Brush *brush)
+{
+ if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) {
+ return !SCULPT_is_cloth_deform_brush(brush);
+ }
+ return ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_MULTIPLANE_SCRAPE,
+ SCULPT_TOOL_CLAY_THUMB,
+ SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_SNAKE_HOOK);
+}
+
static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Brush *brush)
{
SculptSession *ss = ob->sculpt;
@@ -7082,38 +6298,27 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
/* Compute delta to move verts by. */
if (!cache->first_time) {
- switch (tool) {
- case SCULPT_TOOL_GRAB:
- case SCULPT_TOOL_POSE:
- case SCULPT_TOOL_THUMB:
- case SCULPT_TOOL_ELASTIC_DEFORM:
- sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, delta);
- add_v3_v3(cache->grab_delta, delta);
- break;
- case SCULPT_TOOL_CLAY_STRIPS:
- case SCULPT_TOOL_PINCH:
- case SCULPT_TOOL_CLOTH:
- case SCULPT_TOOL_MULTIPLANE_SCRAPE:
- case SCULPT_TOOL_CLAY_THUMB:
- case SCULPT_TOOL_NUDGE:
- case SCULPT_TOOL_SNAKE_HOOK:
- if (brush->flag & BRUSH_ANCHORED) {
- float orig[3];
- mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
- sub_v3_v3v3(cache->grab_delta, grab_location, orig);
- }
- else {
- sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- }
- invert_m4_m4(imat, ob->obmat);
- mul_mat3_m4_v3(imat, cache->grab_delta);
- break;
- default:
- /* Use for 'Brush.topology_rake_factor'. */
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
+ sub_v3_v3v3(delta, grab_location, cache->old_grab_location);
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, delta);
+ add_v3_v3(cache->grab_delta, delta);
+ }
+ else if (sculpt_needs_delta_for_tip_orientation(brush)) {
+ if (brush->flag & BRUSH_ANCHORED) {
+ float orig[3];
+ mul_v3_m4v3(orig, ob->obmat, cache->orig_grab_location);
+ sub_v3_v3v3(cache->grab_delta, grab_location, orig);
+ }
+ else {
sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
- break;
+ }
+ invert_m4_m4(imat, ob->obmat);
+ mul_mat3_m4_v3(imat, cache->grab_delta);
+ }
+ else {
+ /* Use for 'Brush.topology_rake_factor'. */
+ sub_v3_v3v3(cache->grab_delta, grab_location, cache->old_grab_location);
}
}
else {
@@ -7134,18 +6339,14 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
copy_v3_v3(cache->anchored_location, cache->true_location);
}
}
- else if (tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ else if (tool == SCULPT_TOOL_ELASTIC_DEFORM || SCULPT_is_cloth_deform_brush(brush)) {
copy_v3_v3(cache->anchored_location, cache->true_location);
}
else if (tool == SCULPT_TOOL_THUMB) {
copy_v3_v3(cache->anchored_location, cache->orig_grab_location);
}
- if (ELEM(tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ELASTIC_DEFORM,
- SCULPT_TOOL_POSE)) {
+ if (sculpt_needs_delta_from_anchored_origin(brush)) {
/* Location stays the same for finding vertices in brush radius. */
copy_v3_v3(cache->true_location, cache->orig_grab_location);
@@ -7216,9 +6417,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
if (cache->first_time ||
!((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) ||
- (brush->sculpt_tool == SCULPT_TOOL_ROTATE) ||
- (brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
- brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) {
+ (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || SCULPT_is_cloth_deform_brush(brush))) {
RNA_float_get_array(ptr, "location", cache->true_location);
}
@@ -7248,7 +6447,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Clay stabilized pressure. */
if (brush->sculpt_tool == SCULPT_TOOL_CLAY_THUMB) {
if (ss->cache->first_time) {
- for (int i = 0; i < CLAY_STABILIZER_LEN; i++) {
+ for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) {
ss->cache->clay_pressure_stabilizer[i] = 0.0f;
}
ss->cache->clay_pressure_stabilizer_index = 0;
@@ -7256,7 +6455,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
else {
cache->clay_pressure_stabilizer[cache->clay_pressure_stabilizer_index] = cache->pressure;
cache->clay_pressure_stabilizer_index += 1;
- if (cache->clay_pressure_stabilizer_index >= CLAY_STABILIZER_LEN) {
+ if (cache->clay_pressure_stabilizer_index >= SCULPT_CLAY_STABILIZER_LEN) {
cache->clay_pressure_stabilizer_index = 0;
}
}
@@ -7307,9 +6506,12 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po
/* Returns true if any of the smoothing modes are active (currently
* one of smooth brush, autosmooth, mask smooth, or shift-key
* smooth). */
-static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
+static bool sculpt_needs_connectivity_info(const Sculpt *sd,
+ const Brush *brush,
+ SculptSession *ss,
+ int stroke_mode)
{
- if (ss && ss->pbvh && sculpt_automasking_enabled(ss, brush)) {
+ if (ss && ss->pbvh && SCULPT_is_automasking_enabled(sd, ss, brush)) {
return true;
}
return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
@@ -7321,12 +6523,13 @@ static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss
(brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS));
}
-static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush)
{
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- bool need_pmap = sculpt_needs_connectivity_info(brush, ss, 0);
+ bool need_pmap = sculpt_needs_connectivity_info(sd, brush, ss, 0);
if (ss->shapekey_active || ss->deform_modifiers_active ||
(!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -7362,6 +6565,7 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
&srd->isect_precalc,
&srd->depth,
&srd->active_vertex_index,
+ &srd->active_face_grid_index,
srd->face_normal)) {
srd->hit = true;
*tmin = srd->depth;
@@ -7402,24 +6606,12 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
}
}
-static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
-{
- if (BKE_pbvh_node_get_tmin(node) < *tmin) {
- SculptDetailRaycastData *srd = data_v;
- if (BKE_pbvh_bmesh_node_raycast_detail(
- node, srd->ray_start, &srd->isect_precalc, &srd->depth, &srd->edge_length)) {
- srd->hit = true;
- *tmin = srd->depth;
- }
- }
-}
-
-static float sculpt_raycast_init(ViewContext *vc,
- const float mouse[2],
- float ray_start[3],
- float ray_end[3],
- float ray_normal[3],
- bool original)
+float SCULPT_raycast_init(ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original)
{
float obimat[4][4];
float dist;
@@ -7485,8 +6677,8 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
}
/* PBVH raycast to get active vertex and face normal. */
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
- sculpt_stroke_modifiers_check(C, ob, brush);
+ depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
SculptRaycastData srd = {
.original = original,
@@ -7512,6 +6704,21 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
ss->active_vertex_index = srd.active_vertex_index;
copy_v3_v3(out->active_vertex_co, SCULPT_active_vertex_co_get(ss));
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ ss->active_face_index = srd.active_face_grid_index;
+ ss->active_grid_index = 0;
+ break;
+ case PBVH_GRIDS:
+ ss->active_face_index = 0;
+ ss->active_grid_index = srd.active_face_grid_index;
+ break;
+ case PBVH_BMESH:
+ ss->active_face_index = 0;
+ ss->active_grid_index = 0;
+ break;
+ }
+
copy_v3_v3(out->location, ray_normal);
mul_v3_fl(out->location, srd.depth);
add_v3_v3(out->location, ray_start);
@@ -7590,9 +6797,9 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
- depth = sculpt_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
+ depth = SCULPT_raycast_init(&vc, mouse, ray_start, ray_end, ray_normal, original);
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BM_mesh_elem_table_ensure(ss->bm, BM_VERT);
@@ -7684,12 +6891,13 @@ static void sculpt_brush_stroke_init(bContext *C, wmOperator *op)
view3d_operator_needs_opengl(C);
sculpt_brush_init_tex(scene, sd, ss);
- is_smooth = sculpt_needs_connectivity_info(brush, ss, mode);
+ is_smooth = sculpt_needs_connectivity_info(sd, brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
{
+ SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
/* Restore the mesh before continuing with anchored stroke. */
@@ -7699,7 +6907,19 @@ static void sculpt_restore_mesh(Sculpt *sd, Object *ob)
brush->sculpt_tool == SCULPT_TOOL_CLOTH) &&
BKE_brush_use_size_pressure(brush)) ||
(brush->flag & BRUSH_DRAG_DOT)) {
+
+ SculptUndoNode *unode = SCULPT_undo_get_first_node();
+ if (unode && unode->type == SCULPT_UNDO_FACE_SETS) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = unode->face_sets[i];
+ }
+ }
+
paint_mesh_restore_co(sd, ob);
+
+ if (ss->cache) {
+ MEM_SAFE_FREE(ss->cache->layer_displacement_factor);
+ }
}
}
@@ -7714,13 +6934,13 @@ void SCULPT_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
SculptSession *ss = ob->sculpt;
ARegion *region = CTX_wm_region(C);
- MultiresModifierData *mmd = ss->multires;
+ MultiresModifierData *mmd = ss->multires.modifier;
View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -7774,7 +6994,7 @@ static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags)
{
/* After we are done drawing the stroke, check if we need to do a more
* expensive depsgraph tag to update geometry. */
@@ -7791,10 +7011,10 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate
rv3d->rflag &= ~RV3D_PAINTING;
}
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ SpaceLink *sl = area->spacedata.first;
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d != current_v3d) {
@@ -7804,7 +7024,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate
/* Tag all 3D viewports for redraw now that we are done. Others
* viewports did not get a full redraw, and anti-aliasing for the
* current viewport was deactivated. */
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
ED_region_tag_redraw(region);
}
@@ -7884,7 +7104,7 @@ static void sculpt_stroke_update_step(bContext *C,
SculptSession *ss = ob->sculpt;
const Brush *brush = BKE_paint_brush(&sd->paint);
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
sculpt_update_cache_variants(C, sd, ob, itemptr);
sculpt_restore_mesh(sd, ob);
@@ -7901,7 +7121,7 @@ static void sculpt_stroke_update_step(bContext *C,
(float)(sd->detail_size * U.pixelsize) / 0.4f);
}
- if (sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ if (SCULPT_stroke_is_dynamic_topology(ss, brush)) {
do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
@@ -7922,7 +7142,7 @@ static void sculpt_stroke_update_step(bContext *C,
* sculpt_flush_update_step().
*/
if (ss->deform_modifiers_active) {
- sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
+ SCULPT_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
@@ -7933,10 +7153,10 @@ static void sculpt_stroke_update_step(bContext *C,
/* Cleanup. */
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
}
else {
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
}
@@ -7965,7 +7185,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
BLI_assert(brush == ss->cache->brush); /* const, so we shouldn't change. */
ups->draw_inverted = false;
- sculpt_stroke_modifiers_check(C, ob, brush);
+ SCULPT_stroke_modifiers_check(C, ob, brush);
/* Alt-Smooth. */
if (ss->cache->alt_smooth) {
@@ -7984,8 +7204,8 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
}
}
- if (sculpt_automasking_enabled(ss, brush)) {
- sculpt_automasking_end(ob);
+ if (SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ SCULPT_automasking_end(ob);
}
SCULPT_cache_free(ss->cache);
@@ -7994,10 +7214,10 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
SCULPT_undo_push_end();
if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
}
else {
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
@@ -8074,7 +7294,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
/* XXX Canceling strokes that way does not work with dynamic topology,
* user will have to do real undo for now. See T46456. */
- if (ss->cache && !sculpt_stroke_is_dynamic_topology(ss, brush)) {
+ if (ss->cache && !SCULPT_stroke_is_dynamic_topology(ss, brush)) {
paint_mesh_restore_co(sd, ob);
}
@@ -8120,13 +7340,25 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op))
{
- SculptSession *ss = CTX_data_active_object(C)->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
if (ss) {
- if (ss->layer_co) {
- MEM_freeN(ss->layer_co);
+ SCULPT_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ MEM_SAFE_FREE(ss->layer_base);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ ss->layer_base = MEM_mallocN(sizeof(SculptLayerPersistentBase) * totvert,
+ "layer persistent base");
+
+ for (int i = 0; i < totvert; i++) {
+ copy_v3_v3(ss->layer_base[i].co, SCULPT_vertex_co_get(ss, i));
+ SCULPT_vertex_normal_get(ss, i, ss->layer_base[i].no);
+ ss->layer_base[i].disp = 0.0f;
}
- ss->layer_co = NULL;
}
return OPERATOR_FINISHED;
@@ -8146,384 +7378,18 @@ static void SCULPT_OT_set_persistent_base(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/************************** Dynamic Topology **************************/
-
-static void sculpt_dynamic_topology_triangulate(BMesh *bm)
-{
- if (bm->totloop != bm->totface * 3) {
- BM_mesh_triangulate(
- bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
- }
-}
-
-void sculpt_pbvh_clear(Object *ob)
-{
- SculptSession *ss = ob->sculpt;
-
- /* Clear out any existing DM and PBVH. */
- if (ss->pbvh) {
- BKE_pbvh_free(ss->pbvh);
- ss->pbvh = NULL;
- }
-
- if (ss->pmap) {
- MEM_freeN(ss->pmap);
- ss->pmap = NULL;
- }
-
- if (ss->pmap_mem) {
- MEM_freeN(ss->pmap_mem);
- ss->pmap_mem = NULL;
- }
-
- BKE_object_free_derived_caches(ob);
-
- /* Tag to rebuild PBVH in depsgraph. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
-}
-
-void sculpt_dyntopo_node_layers_add(SculptSession *ss)
-{
- int cd_node_layer_index;
-
- char layer_id[] = "_dyntopo_node_id";
-
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
- }
-
- ss->cd_vert_node_offset = CustomData_get_n_offset(
- &ss->bm->vdata,
- CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
-
- 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_INT, layer_id);
- if (cd_node_layer_index == -1) {
- BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
- cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
- }
-
- ss->cd_face_node_offset = CustomData_get_n_offset(
- &ss->bm->pdata,
- CD_PROP_INT,
- cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
-
- ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
-}
-
-static void sculpt_dynamic_topology_enable_ex(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
-
- sculpt_pbvh_clear(ob);
-
- ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
- 0;
-
- /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280]. */
- BKE_mesh_mselect_clear(me);
-
- /* Create triangles-only BMesh. */
- ss->bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = false,
- }));
-
- BM_mesh_bm_from_me(ss->bm,
- me,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- .use_shapekey = true,
- .active_shapekey = ob->shapenr,
- }));
- sculpt_dynamic_topology_triangulate(ss->bm);
- BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
- /* Make sure the data for existing faces are initialized. */
- if (me->totpoly != ss->bm->totface) {
- BM_mesh_normals_update(ss->bm);
- }
-
- /* Enable dynamic topology. */
- me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* Enable logging for undo/redo. */
- ss->bm_log = BM_log_create(ss->bm);
-
- /* Update dependency graph, so modifiers that depend on dyntopo being enabled
- * are re-evaluated and the PBVH is re-created. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
-}
-
-/* Free the sculpt BMesh and BMLog
- *
- * If 'unode' is given, the BMesh's data is copied out to the unode
- * before the BMesh is deleted so that it can be restored from. */
-static void sculpt_dynamic_topology_disable_ex(
- Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *me = ob->data;
-
- sculpt_pbvh_clear(ob);
-
- if (unode) {
- /* Free all existing custom data. */
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
-
- /* Copy over stored custom data. */
- me->totvert = unode->geom_totvert;
- me->totloop = unode->geom_totloop;
- me->totpoly = unode->geom_totpoly;
- me->totedge = unode->geom_totedge;
- me->totface = 0;
- CustomData_copy(
- &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
- CustomData_copy(
- &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
- CustomData_copy(
- &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
- CustomData_copy(
- &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
-
- BKE_mesh_update_customdata_pointers(me, false);
- }
- else {
- BKE_sculptsession_bm_to_me(ob, true);
- }
-
- /* Clear data. */
- me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
-
- /* Typically valid but with global-undo they can be NULL. [#36234] */
- if (ss->bm) {
- BM_mesh_free(ss->bm);
- ss->bm = NULL;
- }
- if (ss->bm_log) {
- BM_log_free(ss->bm_log);
- ss->bm_log = NULL;
- }
-
- BKE_particlesystem_reset_all(ob);
- BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
-
- /* Update dependency graph, so modifiers that depend on dyntopo being enabled
- * are re-evaluated and the PBVH is re-created. */
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- BKE_scene_graph_update_tagged(depsgraph, bmain);
-}
-
-void sculpt_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
-{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- sculpt_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
-}
-
-static void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->bm) {
- SCULPT_undo_push_begin("Dynamic topology disable");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
- sculpt_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
- SCULPT_undo_push_end();
- }
-}
-
-static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob)
-{
- SculptSession *ss = ob->sculpt;
- if (ss->bm == NULL) {
- SCULPT_undo_push_begin("Dynamic topology enable");
- sculpt_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
- SCULPT_undo_push_end();
- }
-}
-
-static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- WM_cursor_wait(true);
-
- if (ss->bm) {
- sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
- }
- else {
- sculpt_dynamic_topology_enable_with_undo(bmain, depsgraph, scene, ob);
- }
-
- WM_cursor_wait(false);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-enum eDynTopoWarnFlag {
- DYNTOPO_WARN_VDATA = (1 << 0),
- DYNTOPO_WARN_EDATA = (1 << 1),
- DYNTOPO_WARN_LDATA = (1 << 2),
- DYNTOPO_WARN_MODIFIER = (1 << 3),
-};
-
-static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
-{
- uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
- uiLayout *layout = UI_popup_menu_layout(pup);
-
- if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
- const char *msg_error = TIP_("Vertex Data Detected!");
- const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
-
- if (flag & DYNTOPO_WARN_MODIFIER) {
- const char *msg_error = TIP_("Generative Modifiers Detected!");
- const char *msg = TIP_(
- "Keeping the modifiers will increase polycount when returning to object mode");
-
- uiItemL(layout, msg_error, ICON_INFO);
- uiItemL(layout, msg, ICON_NONE);
- uiItemS(layout);
- }
-
- uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
-
- UI_popup_menu_end(C, pup);
-
- return OPERATOR_INTERFACE;
-}
-
-static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(Scene *scene, Object *ob)
-{
- Mesh *me = ob->data;
- SculptSession *ss = ob->sculpt;
-
- enum eDynTopoWarnFlag flag = 0;
-
- BLI_assert(ss->bm == NULL);
- UNUSED_VARS_NDEBUG(ss);
-
- for (int i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
- if (CustomData_has_layer(&me->vdata, i)) {
- flag |= DYNTOPO_WARN_VDATA;
- }
- if (CustomData_has_layer(&me->edata, i)) {
- flag |= DYNTOPO_WARN_EDATA;
- }
- if (CustomData_has_layer(&me->ldata, i)) {
- flag |= DYNTOPO_WARN_LDATA;
- }
- }
- }
-
- {
- VirtualModifierData virtualModifierData;
- ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
-
- /* Exception for shape keys because we can edit those. */
- for (; md; md = md->next) {
- const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
- continue;
- }
-
- if (mti->type == eModifierTypeType_Constructive) {
- flag |= DYNTOPO_WARN_MODIFIER;
- break;
- }
- }
- }
-
- return flag;
-}
-
-static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
-
- if (!ss->bm) {
- Scene *scene = CTX_data_scene(C);
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
-
- if (flag) {
- /* The mesh has customdata that will be lost, let the user confirm this is OK. */
- return dyntopo_warning_popup(C, op->type, flag);
- }
- }
-
- return sculpt_dynamic_topology_toggle_exec(C, op);
-}
-
-static void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Dynamic Topology Toggle";
- ot->idname = "SCULPT_OT_dynamic_topology_toggle";
- ot->description = "Dynamic topology alters the mesh topology while sculpting";
-
- /* API callbacks. */
- ot->invoke = sculpt_dynamic_topology_toggle_invoke;
- ot->exec = sculpt_dynamic_topology_toggle_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/************************* SCULPT_OT_optimize *************************/
static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
}
-static bool sculpt_and_dynamic_topology_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm;
-}
-
/* The BVH gets less optimal more quickly with dynamic topology than
* regular sculpting. There is no doubt more clever stuff we can do to
* optimize it on the fly, but for now this gives the user a nicer way
@@ -8553,7 +7419,7 @@ static bool sculpt_no_multires_poll(bContext *C)
return false;
}
-static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
+static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
const Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -8584,7 +7450,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
"symmetrize input=%avef direction=%i dist=%f",
sd->symmetrize_direction,
0.00001f);
- sculpt_dynamic_topology_triangulate(ss->bm);
+ SCULPT_dynamic_topology_triangulate(ss->bm);
/* Bisect operator flags edges (keep tags clean for edge queue). */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
@@ -8604,7 +7470,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
MirrorModifierData mmd = {{0}};
int axis = 0;
mmd.flag = 0;
- mmd.tolerance = 0.005f;
+ mmd.tolerance = RNA_float_get(op->ptr, "merge_tolerance");
switch (sd->symmetrize_direction) {
case BMO_SYMMETRIZE_NEGATIVE_X:
axis = 0;
@@ -8645,7 +7511,7 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Redraw. */
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
return OPERATOR_FINISHED;
@@ -8661,6 +7527,16 @@ static void SCULPT_OT_symmetrize(wmOperatorType *ot)
/* API callbacks. */
ot->exec = sculpt_symmetrize_exec;
ot->poll = sculpt_no_multires_poll;
+
+ RNA_def_float(ot->srna,
+ "merge_tolerance",
+ 0.001f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Limit",
+ "Distance within which symmetrical vertices are merged",
+ 0.0f,
+ 1.0f);
}
/**** Toggle operator for turning sculpt mode on or off ****/
@@ -8673,6 +7549,28 @@ static void sculpt_init_session(Depsgraph *depsgraph, Scene *scene, Object *ob)
ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session");
ob->sculpt->mode_type = OB_MODE_SCULPT;
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ /* Here we can detect geometry that was just added to Sculpt Mode as it has the
+ * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */
+ /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not
+ * initialized, which is used is some operators that modify the mesh topology to preform certain
+ * actions in the new polys. After these operations are finished, all polys should have a valid
+ * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility
+ * correctly. */
+ /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new
+ * objects, like moving the transform pivot position to the new area or masking existing
+ * geometry. */
+ SculptSession *ss = ob->sculpt;
+ const int new_face_set = SCULPT_face_set_next_available_get(ss);
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) {
+ ss->face_sets[i] = new_face_set;
+ }
+ }
+
+ /* Update the Face Sets visibility with the vertex visibility changes that may have been done
+ * outside Sculpt Mode */
+ SCULPT_visibility_sync_all_vertex_to_face_sets(ob->sculpt);
}
static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
@@ -8681,7 +7579,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene,
{
int flush_recalc = 0;
/* Multires in sculpt mode could have different from object mode subdivision level. */
- flush_recalc |= mmd && BKE_multires_sculpt_level_get(mmd) != mmd->lvl;
+ flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* If object has got active modifiers, it's dm could be different in sculpt mode. */
flush_recalc |= sculpt_has_active_modifiers(scene, ob);
return flush_recalc;
@@ -8738,7 +7636,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT);
BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT);
- paint_cursor_start_explicit(paint, bmain->wm.first, SCULPT_poll_view3d);
+ paint_cursor_start(paint, SCULPT_poll_view3d);
/* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes,
* As long as no data was added that is not supported. */
@@ -8751,7 +7649,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
message_unsupported = TIP_("multi-res modifier");
}
else {
- enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(scene, ob);
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
if (flag == 0) {
/* pass */
}
@@ -8780,7 +7678,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
if (has_undo) {
SCULPT_undo_push_begin("Dynamic topology enable");
}
- sculpt_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
if (has_undo) {
SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
SCULPT_undo_push_end();
@@ -8923,1764 +7821,6 @@ static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- return SCULPT_mode_poll(C) && ob->sculpt->bm &&
- (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
-}
-
-static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- float size;
- float bb_min[3], bb_max[3], center[3], dim[3];
- int totnodes;
- PBVHNode **nodes;
-
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
-
- if (!totnodes) {
- return OPERATOR_CANCELLED;
- }
-
- for (int i = 0; i < totnodes; i++) {
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
- /* Get the bounding box, it's center and size. */
- BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
- add_v3_v3v3(center, bb_min, bb_max);
- mul_v3_fl(center, 0.5f);
- sub_v3_v3v3(dim, bb_max, bb_min);
- size = max_fff(dim[0], dim[1], dim[2]);
-
- /* Update topology size. */
- 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("Dynamic topology flood fill");
- SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
-
- while (BKE_pbvh_bmesh_update_topology(
- ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
- for (int i = 0; i < totnodes; i++) {
- BKE_pbvh_node_mark_topology_update(nodes[i]);
- }
- }
-
- MEM_SAFE_FREE(nodes);
- SCULPT_undo_push_end();
-
- /* Force rebuild of pbvh for better BB placement. */
- sculpt_pbvh_clear(ob);
- /* Redraw. */
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Detail Flood Fill";
- ot->idname = "SCULPT_OT_detail_flood_fill";
- ot->description = "Flood fill the mesh with the selected detail setting";
-
- /* API callbacks. */
- ot->exec = sculpt_detail_flood_fill_exec;
- ot->poll = sculpt_and_constant_or_manual_detail_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-typedef enum eSculptSampleDetailModeTypes {
- SAMPLE_DETAIL_DYNTOPO = 0,
- SAMPLE_DETAIL_VOXEL = 1,
-} eSculptSampleDetailModeTypes;
-
-static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
- {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
- {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = vc->obact;
- Mesh *mesh = ob->data;
-
- SculptSession *ss = ob->sculpt;
- SculptCursorGeometryInfo sgi;
- SCULPT_vertex_random_access_init(ss);
-
- /* Update the active vertex. */
- float mouse[2] = {mx, my};
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
-
- /* Average the edge length of the connected edges to the active vertex. */
- int 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));
- tot += 1;
- }
- sculpt_vertex_neighbors_iter_end(ni);
- if (tot > 0) {
- mesh->remesh_voxel_size = edge_length / (float)tot;
- }
-}
-
-static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = vc->obact;
- Brush *brush = BKE_paint_brush(&sd->paint);
-
- sculpt_stroke_modifiers_check(C, ob, brush);
-
- float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
- float ray_start[3], ray_end[3], ray_normal[3];
- float depth = sculpt_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
-
- SculptDetailRaycastData srd;
- srd.hit = 0;
- srd.ray_start = ray_start;
- srd.depth = depth;
- srd.edge_length = 0.0f;
- isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
-
- BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
-
- if (srd.hit && srd.edge_length > 0.0f) {
- /* Convert edge length to world space detail resolution. */
- sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
- }
-}
-
-static int sample_detail(bContext *C, int mx, int my, int mode)
-{
- /* Find 3D view to pick from. */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
- ARegion *region = (sa) ? BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my) : NULL;
- if (region == NULL) {
- return OPERATOR_CANCELLED;
- }
-
- /* Set context to 3D view. */
- ScrArea *prev_sa = CTX_wm_area(C);
- ARegion *prev_ar = CTX_wm_region(C);
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, region);
-
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc, depsgraph);
-
- Object *ob = vc.obact;
- SculptSession *ss = ob->sculpt;
-
- if (!ss->pbvh) {
- return OPERATOR_CANCELLED;
- }
-
- /* Pick sample detail. */
- switch (mode) {
- case SAMPLE_DETAIL_DYNTOPO:
- if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
- return OPERATOR_CANCELLED;
- }
- sample_detail_dyntopo(C, &vc, region, mx, my);
- break;
- case SAMPLE_DETAIL_VOXEL:
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
- return OPERATOR_CANCELLED;
- }
- sample_detail_voxel(C, &vc, mx, my);
- break;
- }
-
- /* Restore context. */
- CTX_wm_area_set(C, prev_sa);
- CTX_wm_region_set(C, prev_ar);
-
- return OPERATOR_FINISHED;
-}
-
-static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
-{
- int ss_co[2];
- RNA_int_get_array(op->ptr, "location", ss_co);
- int mode = RNA_enum_get(op->ptr, "mode");
- return sample_detail(C, ss_co[0], ss_co[1], mode);
-}
-
-static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
-{
- ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
- WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- if (event->val == KM_PRESS) {
- int ss_co[2] = {event->x, event->y};
-
- int mode = RNA_enum_get(op->ptr, "mode");
- sample_detail(C, ss_co[0], ss_co[1], mode);
-
- RNA_int_set_array(op->ptr, "location", ss_co);
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
- WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
-
- return OPERATOR_FINISHED;
- }
- break;
-
- case RIGHTMOUSE: {
- WM_cursor_modal_restore(CTX_wm_window(C));
- ED_workspace_status_text(C, NULL);
-
- return OPERATOR_CANCELLED;
- }
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Sample Detail Size";
- ot->idname = "SCULPT_OT_sample_detail_size";
- ot->description = "Sample the mesh detail on clicked point";
-
- /* API callbacks. */
- ot->invoke = sculpt_sample_detail_size_invoke;
- ot->exec = sculpt_sample_detail_size_exec;
- ot->modal = sculpt_sample_detail_size_modal;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_int_array(ot->srna,
- "location",
- 2,
- NULL,
- 0,
- SHRT_MAX,
- "Location",
- "Screen Coordinates of sampling",
- 0,
- SHRT_MAX);
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_sample_detail_mode_types,
- SAMPLE_DETAIL_DYNTOPO,
- "Detail Mode",
- "Target sculpting workflow that is going to use the sampled size");
-}
-
-/* Dynamic-topology detail size.
- *
- * This should be improved further, perhaps by showing a triangle
- * grid rather than brush alpha. */
-static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
-{
- char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
- RNA_string_set(ptr, "data_path_primary", path);
- MEM_freeN(path);
-}
-
-static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
-
- PointerRNA props_ptr;
- wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
-
- WM_operator_properties_create_ptr(&props_ptr, ot);
-
- if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(
- &props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
- }
- else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
- set_brush_rc_props(&props_ptr, "constant_detail_resolution");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
- }
- else {
- set_brush_rc_props(&props_ptr, "detail_size");
- RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
- }
-
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
-
- WM_operator_properties_free(&props_ptr);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_set_detail_size(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Detail Size";
- ot->idname = "SCULPT_OT_set_detail_size";
- ot->description =
- "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
-
- /* API callbacks. */
- ot->exec = sculpt_set_detail_size_exec;
- ot->poll = sculpt_and_dynamic_topology_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-static void filter_cache_init_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- PBVHNode *node = data->nodes[i];
-
- SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
-}
-
-static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
-{
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
-
- ss->filter_cache->random_seed = rand();
-
- float center[3] = {0.0f};
- SculptSearchSphereData search_data = {
- .original = true,
- .center = center,
- .radius_squared = FLT_MAX,
- .ignore_fully_masked = true,
-
- };
- BKE_pbvh_search_gather(pbvh,
- SCULPT_search_sphere_cb,
- &search_data,
- &ss->filter_cache->nodes,
- &ss->filter_cache->totnode);
-
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]);
- }
-
- /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
- * Filters can't use normals in multires. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
- BKE_pbvh_update_normals(ss->pbvh, NULL);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
- 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
-}
-
-static void sculpt_filter_cache_free(SculptSession *ss)
-{
- if (ss->filter_cache->nodes) {
- MEM_freeN(ss->filter_cache->nodes);
- }
- if (ss->filter_cache->mask_update_it) {
- MEM_freeN(ss->filter_cache->mask_update_it);
- }
- if (ss->filter_cache->prev_mask) {
- MEM_freeN(ss->filter_cache->prev_mask);
- }
- if (ss->filter_cache->normal_factor) {
- MEM_freeN(ss->filter_cache->normal_factor);
- }
- if (ss->filter_cache->prev_face_set) {
- MEM_freeN(ss->filter_cache->prev_face_set);
- }
- if (ss->filter_cache->automask) {
- MEM_freeN(ss->filter_cache->automask);
- }
- if (ss->filter_cache->surface_smooth_laplacian_disp) {
- MEM_freeN(ss->filter_cache->surface_smooth_laplacian_disp);
- }
- MEM_freeN(ss->filter_cache);
- ss->filter_cache = NULL;
-}
-
-typedef enum eSculptMeshFilterTypes {
- MESH_FILTER_SMOOTH = 0,
- MESH_FILTER_SCALE = 1,
- MESH_FILTER_INFLATE = 2,
- MESH_FILTER_SPHERE = 3,
- MESH_FILTER_RANDOM = 4,
- MESH_FILTER_RELAX = 5,
- MESH_FILTER_RELAX_FACE_SETS = 6,
- MESH_FILTER_SURFACE_SMOOTH = 7,
-} eSculptMeshFilterTypes;
-
-static EnumPropertyItem prop_mesh_filter_types[] = {
- {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
- {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
- {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
- {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
- {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
- {MESH_FILTER_RELAX, "RELAX", 0, "Relax", "Relax mesh"},
- {MESH_FILTER_RELAX_FACE_SETS,
- "RELAX_FACE_SETS",
- 0,
- "Relax Face Sets",
- "Smooth the edges of all the Face Sets"},
- {MESH_FILTER_SURFACE_SMOOTH,
- "SURFACE_SMOOTH",
- 0,
- "Surface Smooth",
- "Smooth the surface of the mesh, preserving the volume"},
- {0, NULL, 0, NULL, NULL},
-};
-
-typedef enum eMeshFilterDeformAxis {
- MESH_FILTER_DEFORM_X = 1 << 0,
- MESH_FILTER_DEFORM_Y = 1 << 1,
- MESH_FILTER_DEFORM_Z = 1 << 2,
-} eMeshFilterDeformAxis;
-
-static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
- {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
- {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
- {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets)
-{
- return use_face_sets || ELEM(filter_type,
- MESH_FILTER_SMOOTH,
- MESH_FILTER_RELAX,
- MESH_FILTER_RELAX_FACE_SETS,
- MESH_FILTER_SURFACE_SMOOTH);
-}
-
-static void mesh_filter_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
-
- const int filter_type = data->filter_type;
-
- SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
-
- /* When using the relax face sets mehs filter, each 3 iterations, do a whole mesh relax to smooth
- * the contents of the Face Set. */
- /* This produces better results as the relax operation is no completely focused on the
- * boundaries. */
- const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
-
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
- float fade = vd.mask ? *vd.mask : 0.0f;
- fade = 1.0f - fade;
- fade *= data->filter_strength;
-
- if (fade == 0.0f) {
- continue;
- }
-
- 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)) {
- continue;
- }
- /* Skip the edges of the face set when relaxing or smoothing. There is a relax face set
- * option to relax the boindaries independently. */
- if (filter_type == MESH_FILTER_RELAX) {
- if (!sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- continue;
- }
- }
- }
-
- if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
- copy_v3_v3(orig_co, vd.co);
- }
- else {
- copy_v3_v3(orig_co, orig_data.co);
- }
-
- if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
- if (relax_face_sets == sculpt_vertex_has_unique_face_set(ss, vd.index)) {
- continue;
- }
- }
-
- switch (filter_type) {
- case MESH_FILTER_SMOOTH:
- CLAMP(fade, -1.0f, 1.0f);
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- neighbor_average(ss, avg, vd.index);
- break;
- case PBVH_BMESH:
- bmesh_neighbor_average(avg, vd.bm_vert);
- break;
- case PBVH_GRIDS:
- SCULPT_neighbor_coords_average(ss, avg, vd.index);
- break;
- }
- sub_v3_v3v3(val, avg, orig_co);
- madd_v3_v3v3fl(val, orig_co, val, fade);
- sub_v3_v3v3(disp, val, orig_co);
- break;
- case MESH_FILTER_INFLATE:
- normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_v3fl(disp, normal, fade);
- break;
- case MESH_FILTER_SCALE:
- unit_m3(transform);
- scale_m3_fl(transform, 1.0f + fade);
- copy_v3_v3(val, orig_co);
- mul_m3_v3(transform, val);
- sub_v3_v3v3(disp, val, orig_co);
- break;
- case MESH_FILTER_SPHERE:
- normalize_v3_v3(disp, orig_co);
- if (fade > 0.0f) {
- mul_v3_v3fl(disp, disp, fade);
- }
- else {
- mul_v3_v3fl(disp, disp, -fade);
- }
-
- unit_m3(transform);
- if (fade > 0.0f) {
- scale_m3_fl(transform, 1.0f - fade);
- }
- else {
- scale_m3_fl(transform, 1.0f + fade);
- }
- copy_v3_v3(val, orig_co);
- mul_m3_v3(transform, val);
- sub_v3_v3v3(disp2, val, orig_co);
-
- mid_v3_v3v3(disp, disp, disp2);
- break;
- case MESH_FILTER_RANDOM: {
- normal_short_to_float_v3(normal, orig_data.no);
- /* Index is not unique for multires, so hash by vertex coordinates. */
- const uint *hash_co = (const uint *)orig_co;
- const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
- BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
- mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
- mul_v3_v3fl(disp, normal, fade);
- break;
- }
- case MESH_FILTER_RELAX: {
- SCULPT_relax_vertex(
- ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val);
- sub_v3_v3v3(disp, val, vd.co);
- break;
- }
- case MESH_FILTER_RELAX_FACE_SETS: {
- SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), relax_face_sets, val);
- sub_v3_v3v3(disp, val, vd.co);
- break;
- }
- case MESH_FILTER_SURFACE_SMOOTH: {
- surface_smooth_laplacian_step(ss,
- disp,
- vd.co,
- ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
- orig_data.co,
- ss->filter_cache->surface_smooth_shape_preservation);
- break;
- }
- }
-
- for (int it = 0; it < 3; it++) {
- if (!ss->filter_cache->enabled_axis[it]) {
- disp[it] = 0.0f;
- }
- }
-
- if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
- madd_v3_v3v3fl(final_pos, vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
- }
- else {
- add_v3_v3v3(final_pos, orig_co, disp);
- }
- copy_v3_v3(vd.co, final_pos);
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(node);
-}
-
-static void mesh_filter_surface_smooth_displace_task_cb(
- void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float fade = vd.mask ? *vd.mask : 0.0f;
- fade = 1.0f - fade;
- fade *= data->filter_strength;
- if (fade == 0.0f) {
- continue;
- }
- surface_smooth_displace_step(ss,
- vd.co,
- ss->filter_cache->surface_smooth_laplacian_disp,
- vd.index,
- ss->filter_cache->surface_smooth_current_vertex,
- clamp_f(fade, 0.0f, 1.0f));
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int filter_type = RNA_enum_get(op->ptr, "type");
- float filter_strength = RNA_float_get(op->ptr, "strength");
- const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
-
- if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
- sculpt_filter_cache_free(ss);
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
- return OPERATOR_FINISHED;
- }
-
- if (event->type != MOUSEMOVE) {
- return OPERATOR_RUNNING_MODAL;
- }
-
- float len = event->prevclickx - event->mval[0];
- filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
-
- SCULPT_vertex_random_access_init(ss);
-
- bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .filter_type = filter_type,
- .filter_strength = filter_strength,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
-
- if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
- BKE_pbvh_parallel_range(0,
- ss->filter_cache->totnode,
- &data,
- mesh_filter_surface_smooth_displace_task_cb,
- &settings);
- }
-
- ss->filter_cache->iteration_count++;
-
- if (ss->deform_modifiers_active || ss->shapekey_active) {
- sculpt_flush_stroke_deform(sd, ob, true);
- }
-
- /* The relax mesh filter needs the updated normals of the modified mesh after each iteration. */
- if (ELEM(MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
- BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Object *ob = CTX_data_active_object(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int filter_type = RNA_enum_get(op->ptr, "type");
- SculptSession *ss = ob->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
- if (deform_axis == 0) {
- return OPERATOR_CANCELLED;
- }
-
- if (RNA_boolean_get(op->ptr, "use_face_sets")) {
- /* Update the active vertex */
- float mouse[2];
- SculptCursorGeometryInfo sgi;
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- }
-
- const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
-
- SCULPT_vertex_random_access_init(ss);
-
- bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("Mesh filter");
-
- sculpt_filter_cache_init(ob, sd);
-
- if (use_face_sets) {
- ss->filter_cache->active_face_set = SCULPT_vertex_face_set_get(ss,
- SCULPT_active_vertex_get(ss));
- }
- else {
- ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
- }
-
- if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) {
- ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(
- 3 * sizeof(float) * SCULPT_vertex_count_get(ss), "surface smooth disp");
- ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get(
- op->ptr, "surface_smooth_shape_preservation");
- ss->filter_cache->surface_smooth_current_vertex = RNA_float_get(
- op->ptr, "surface_smooth_current_vertex");
- }
-
- ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
- ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
- ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
-
- if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) {
- const int totvert = SCULPT_vertex_count_get(ss);
- ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float),
- "Relax filter edge automask");
- for (int i = 0; i < totvert; i++) {
- ss->filter_cache->automask[i] = 1.0f;
- }
- sculpt_boundary_edges_automasking_init(ob, 1, ss->filter_cache->automask);
- }
-
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Filter mesh";
- ot->idname = "SCULPT_OT_mesh_filter";
- ot->description = "Applies a filter to modify the current mesh";
-
- /* API callbacks. */
- ot->invoke = sculpt_mesh_filter_invoke;
- ot->modal = sculpt_mesh_filter_modal;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* RNA. */
- RNA_def_enum(ot->srna,
- "type",
- prop_mesh_filter_types,
- MESH_FILTER_INFLATE,
- "Filter type",
- "Operation that is going to be applied to the mesh");
- RNA_def_float(
- ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
- RNA_def_enum_flag(ot->srna,
- "deform_axis",
- prop_mesh_filter_deform_axis_items,
- MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
- "Deform axis",
- "Apply the deformation in the selected axis");
- ot->prop = RNA_def_boolean(ot->srna,
- "use_face_sets",
- false,
- "Use Face Sets",
- "Apply the filter only to the Face Mask under the cursor");
-
- /* Surface Smooth Mesh Filter properties. */
- RNA_def_float(ot->srna,
- "surface_smooth_shape_preservation",
- 0.5f,
- 0.0f,
- 1.0f,
- "Shape Preservation",
- "How much of the original shape is preserved when smoothing",
- 0.0f,
- 1.0f);
- RNA_def_float(ot->srna,
- "surface_smooth_current_vertex",
- 0.5f,
- 0.0f,
- 1.0f,
- "Per Vertex Displacement",
- "How much the position of each individual vertex influences the final result",
- 0.0f,
- 1.0f);
-}
-
-typedef enum eSculptMaskFilterTypes {
- MASK_FILTER_SMOOTH = 0,
- MASK_FILTER_SHARPEN = 1,
- MASK_FILTER_GROW = 2,
- MASK_FILTER_SHRINK = 3,
- MASK_FILTER_CONTRAST_INCREASE = 5,
- MASK_FILTER_CONTRAST_DECREASE = 6,
-} eSculptMaskFilterTypes;
-
-static EnumPropertyItem prop_mask_filter_types[] = {
- {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
- {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
- {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
- {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
- {MASK_FILTER_CONTRAST_INCREASE,
- "CONTRAST_INCREASE",
- 0,
- "Increase contrast",
- "Increase the contrast of the paint mask"},
- {MASK_FILTER_CONTRAST_DECREASE,
- "CONTRAST_DECREASE",
- 0,
- "Decrease contrast",
- "Decrease the contrast of the paint mask"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static void mask_filter_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- bool update = false;
-
- const int mode = data->filter_type;
- float contrast = 0.0f;
-
- PBVHVertexIter vd;
-
- if (mode == MASK_FILTER_CONTRAST_INCREASE) {
- contrast = 0.1f;
- }
-
- if (mode == MASK_FILTER_CONTRAST_DECREASE) {
- contrast = -0.1f;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float delta, gain, offset, max, min;
- float prev_val = *vd.mask;
- SculptVertexNeighborIter ni;
- switch (mode) {
- case MASK_FILTER_SMOOTH:
- case MASK_FILTER_SHARPEN: {
- float val = 0.0f;
-
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- val = neighbor_average_mask(ss, vd.index);
- break;
- case PBVH_BMESH:
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset);
- break;
- case PBVH_GRIDS:
- val = grids_neighbor_average_mask(ss, vd.index);
- break;
- }
-
- val -= *vd.mask;
-
- if (mode == MASK_FILTER_SMOOTH) {
- *vd.mask += val;
- }
- else if (mode == MASK_FILTER_SHARPEN) {
- if (*vd.mask > 0.5f) {
- *vd.mask += 0.05f;
- }
- else {
- *vd.mask -= 0.05f;
- }
- *vd.mask += val / 2.0f;
- }
- break;
- }
- case MASK_FILTER_GROW:
- max = 0.0f;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
- float vmask_f = data->prev_mask[ni.index];
- if (vmask_f > max) {
- max = vmask_f;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- *vd.mask = max;
- break;
- case MASK_FILTER_SHRINK:
- min = 1.0f;
- sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
- {
- float vmask_f = data->prev_mask[ni.index];
- if (vmask_f < min) {
- min = vmask_f;
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- *vd.mask = min;
- break;
- case MASK_FILTER_CONTRAST_INCREASE:
- case MASK_FILTER_CONTRAST_DECREASE:
- delta = contrast / 2.0f;
- gain = 1.0f - delta * 2.0f;
- if (contrast > 0) {
- gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
- offset = gain * (-delta);
- }
- else {
- delta *= -1.0f;
- offset = gain * (delta);
- }
- *vd.mask = gain * (*vd.mask) + offset;
- break;
- }
- CLAMP(*vd.mask, 0.0f, 1.0f);
- if (*vd.mask != prev_val) {
- update = true;
- }
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- if (update) {
- BKE_pbvh_node_mark_update_mask(node);
- }
-}
-
-static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
-{
- ARegion *region = CTX_wm_region(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int totnode;
- int filter_type = RNA_enum_get(op->ptr, "filter_type");
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- SCULPT_vertex_random_access_init(ss);
-
- if (!ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- int num_verts = SCULPT_vertex_count_get(ss);
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin("Mask filter");
-
- for (int i = 0; i < totnode; i++) {
- SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
- }
-
- float *prev_mask = NULL;
- int iterations = RNA_int_get(op->ptr, "iterations");
-
- /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
- * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
- * One iteration per 50000 vertices in the mesh should be fine in most cases.
- * Maybe we want this to be configurable. */
- if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
- iterations = (int)(num_verts / 50000.0f) + 1;
- }
-
- for (int i = 0; i < iterations; i++) {
- 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);
- }
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .filter_type = filter_type,
- .prev_mask = prev_mask,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
-
- if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
- MEM_freeN(prev_mask);
- }
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Mask Filter";
- ot->idname = "SCULPT_OT_mask_filter";
- ot->description = "Applies a filter to modify the current mask";
-
- /* API callbacks. */
- ot->exec = sculpt_mask_filter_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* RNA. */
- RNA_def_enum(ot->srna,
- "filter_type",
- prop_mask_filter_types,
- MASK_FILTER_SMOOTH,
- "Type",
- "Filter that is going to be applied to the mask");
- RNA_def_int(ot->srna,
- "iterations",
- 1,
- 1,
- 100,
- "Iterations",
- "Number of times that the filter is going to be applied",
- 1,
- 100);
- RNA_def_boolean(
- ot->srna,
- "auto_iteration_count",
- false,
- "Auto Iteration Count",
- "Use a automatic number of iterations based on the number of vertices of the sculpt");
-}
-
-static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
-{
- int total = 0;
- float avg[3];
- zero_v3(avg);
-
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
- {
- float normalized[3];
- sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
- normalize_v3(normalized);
- add_v3_v3(avg, normalized);
- total++;
- }
- sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- float normal[3];
- if (vd->no) {
- normal_short_to_float_v3(normal, vd->no);
- }
- else {
- copy_v3_v3(normal, vd->fno);
- }
- float dot = dot_v3v3(avg, normal);
- float angle = max_ff(saacosf(dot), 0.0f);
- return angle;
- }
- return 0.0f;
-}
-
-typedef struct DirtyMaskRangeData {
- float min, max;
-} DirtyMaskRangeData;
-
-static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict tls)
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- DirtyMaskRangeData *range = tls->userdata_chunk;
- PBVHVertexIter vd;
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float dirty_mask = neighbor_dirty_mask(ss, &vd);
- range->min = min_ff(dirty_mask, range->min);
- range->max = max_ff(dirty_mask, range->max);
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata),
- void *__restrict chunk_join,
- void *__restrict chunk)
-{
- DirtyMaskRangeData *join = chunk_join;
- DirtyMaskRangeData *range = chunk;
- join->min = min_ff(range->min, join->min);
- join->max = max_ff(range->max, join->max);
-}
-
-static void dirty_mask_apply_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
-
- const bool dirty_only = data->dirty_mask_dirty_only;
- const float min = data->dirty_mask_min;
- const float max = data->dirty_mask_max;
-
- float range = max - min;
- if (range < 0.0001f) {
- range = 0.0f;
- }
- else {
- range = 1.0f / range;
- }
-
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- float dirty_mask = neighbor_dirty_mask(ss, &vd);
- float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range));
- if (dirty_only) {
- mask = fminf(mask, 0.5f) * 2.0f;
- }
- *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_update_mask(node);
-}
-
-static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
-{
- ARegion *region = CTX_wm_region(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- int totnode;
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- SCULPT_vertex_random_access_init(ss);
-
- if (!ob->sculpt->pmap) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- SCULPT_undo_push_begin("Dirty Mask");
-
- for (int i = 0; i < totnode; i++) {
- SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = nodes,
- .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
- };
- DirtyMaskRangeData range = {
- .min = FLT_MAX,
- .max = -FLT_MAX,
- };
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
-
- settings.func_reduce = dirty_mask_compute_range_reduce;
- settings.userdata_chunk = &range;
- settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
-
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
- data.dirty_mask_min = range.min;
- data.dirty_mask_max = range.max;
- BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
-
- MEM_SAFE_FREE(nodes);
-
- BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
-
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Dirty Mask";
- ot->idname = "SCULPT_OT_dirty_mask";
- ot->description = "Generates a mask based on the geometry cavity and pointiness";
-
- /* API callbacks. */
- ot->exec = sculpt_dirty_mask_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER;
-
- /* RNA. */
- RNA_def_boolean(
- ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
-}
-
-static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- MEM_freeN(op->customdata);
-
- for (int n = 0; n < ss->filter_cache->totnode; n++) {
- PBVHNode *node = ss->filter_cache->nodes[n];
- if (create_face_set) {
- for (int i = 0; i < ss->totpoly; i++) {
- ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
- }
- }
- else {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- *vd.mask = ss->filter_cache->prev_mask[vd.index];
- }
- BKE_pbvh_vertex_iter_end;
- }
-
- BKE_pbvh_node_mark_redraw(node);
- }
-
- if (!create_face_set) {
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
- }
- sculpt_filter_cache_free(ss);
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
- ED_workspace_status_text(C, NULL);
-}
-
-static void sculpt_expand_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
- PBVHVertexIter vd;
- int update_it = data->mask_expand_update_it;
-
- 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)] <
- ss->filter_cache->normal_factor[vd.index]) {
- final_mask = 1.0f;
- }
- else {
- final_mask = 0.0f;
- }
- }
- else {
- if (ss->filter_cache->mask_update_it[vi] <= update_it &&
- ss->filter_cache->mask_update_it[vi] != 0) {
- final_mask = 1.0f;
- }
- else {
- final_mask = 0.0f;
- }
- }
-
- 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);
- }
- BKE_pbvh_node_mark_redraw(node);
- }
- else {
-
- if (data->mask_expand_keep_prev_mask) {
- final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
- }
-
- if (data->mask_expand_invert_mask) {
- final_mask = 1.0f - final_mask;
- }
-
- if (*vd.mask != final_mask) {
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- *vd.mask = final_mask;
- BKE_pbvh_node_mark_update_mask(node);
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
-}
-
-static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- ARegion *region = CTX_wm_region(C);
- float prevclick_f[2];
- copy_v2_v2(prevclick_f, op->customdata);
- int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
- int len = (int)len_v2v2_int(prevclick, event->mval);
- len = abs(len);
- int mask_speed = RNA_int_get(op->ptr, "mask_speed");
- int mask_expand_update_it = len / mask_speed;
- mask_expand_update_it = mask_expand_update_it + 1;
-
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- if (RNA_boolean_get(op->ptr, "use_cursor")) {
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
- mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
- }
-
- if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
- (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
- /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
- * undo. Better solution could be to make paint_mesh_restore_co work
- * for this case. */
- sculpt_mask_expand_cancel(C, op);
- return OPERATOR_FINISHED;
- }
-
- if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
- (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
- (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
-
- /* Smooth iterations. */
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .filter_type = MASK_FILTER_SMOOTH,
- };
-
- int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
- for (int i = 0; i < smooth_iterations; i++) {
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
- }
-
- /* Pivot position. */
- if (RNA_boolean_get(op->ptr, "update_pivot")) {
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- const float threshold = 0.2f;
- float avg[3];
- int total = 0;
- zero_v3(avg);
-
- for (int n = 0; n < ss->filter_cache->totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
- if (SCULPT_check_vertex_pivot_symmetry(
- vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- copy_v3_v3(ss->pivot_pos, avg);
- }
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
- }
-
- MEM_freeN(op->customdata);
-
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
-
- sculpt_filter_cache_free(ss);
-
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
- ED_workspace_status_text(C, NULL);
- return OPERATOR_FINISHED;
- }
-
- /* When pressing Ctrl, expand directly to the max number of iterations. This allows to flood fill
- * mask and face sets by connectivity directly. */
- if (event->ctrl) {
- mask_expand_update_it = ss->filter_cache->mask_update_last_it - 1;
- }
-
- if (!ELEM(event->type, MOUSEMOVE, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
- return OPERATOR_RUNNING_MODAL;
- }
-
- if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
- ED_region_tag_redraw(region);
- return OPERATOR_RUNNING_MODAL;
- }
-
- if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
-
- if (create_face_set) {
- for (int i = 0; i < ss->totpoly; i++) {
- ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
- }
- }
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .mask_expand_update_it = mask_expand_update_it,
- .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
- .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
- .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
- .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
- };
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
- ss->filter_cache->mask_update_current_it = mask_expand_update_it;
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-typedef struct MaskExpandFloodFillData {
- float original_normal[3];
- float edge_sensitivity;
- bool use_normals;
-} MaskExpandFloodFillData;
-
-static bool mask_expand_floodfill_cb(
- SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
-{
- MaskExpandFloodFillData *data = userdata;
-
- 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;
- if (to_it > ss->filter_cache->mask_update_last_it) {
- ss->filter_cache->mask_update_last_it = to_it;
- }
-
- if (data->use_normals) {
- 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);
- }
- }
- else {
- /* PBVH_GRIDS duplicate handling. */
- ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
- 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];
- }
- }
-
- return true;
-}
-
-static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- PBVH *pbvh = ob->sculpt->pbvh;
-
- const bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
- const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
-
- SculptCursorGeometryInfo sgi;
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
-
- SCULPT_vertex_random_access_init(ss);
-
- op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
- copy_v2_v2(op->customdata, mouse);
-
- SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- int vertex_count = SCULPT_vertex_count_get(ss);
-
- ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
-
- SCULPT_undo_push_begin("Mask Expand");
-
- if (create_face_set) {
- SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
- }
- else {
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- SCULPT_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
- }
- }
-
- ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
- "mask update iteration");
- if (use_normals) {
- ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
- "mask update normal factor");
- ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count,
- "mask update normal factor");
- for (int i = 0; i < vertex_count; i++) {
- ss->filter_cache->edge_factor[i] = 1.0f;
- }
- }
-
- if (create_face_set) {
- ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totpoly, "prev face mask");
- for (int i = 0; i < ss->totpoly; i++) {
- ss->filter_cache->prev_face_set[i] = ss->face_sets[i];
- }
- ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss);
- }
- 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);
- }
- }
-
- 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;
-
- copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
-
- SculptFloodFill flood;
- SCULPT_floodfill_init(ss, &flood);
- SCULPT_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
-
- MaskExpandFloodFillData fdata = {
- .use_normals = use_normals,
- .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
- };
- SCULPT_active_vertex_normal_get(ss, fdata.original_normal);
- SCULPT_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
- SCULPT_floodfill_free(&flood);
-
- if (use_normals) {
- for (int repeat = 0; repeat < 2; repeat++) {
- for (int i = 0; i < vertex_count; i++) {
- float avg = 0.0f;
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, i, ni)
- {
- avg += ss->filter_cache->normal_factor[ni.index];
- }
- sculpt_vertex_neighbors_iter_end(ni);
- ss->filter_cache->normal_factor[i] = avg / ni.size;
- }
- }
-
- MEM_SAFE_FREE(ss->filter_cache->edge_factor);
- }
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- .mask_expand_update_it = 0,
- .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
- .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
- .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
- .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
- };
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
-
- const char *status_str = TIP_(
- "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: "
- "cancel");
- ED_workspace_status_text(C, status_str);
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
- WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void SCULPT_OT_mask_expand(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Mask Expand";
- ot->idname = "SCULPT_OT_mask_expand";
- ot->description = "Expands a mask from the initial active vertex under the cursor";
-
- /* API callbacks. */
- ot->invoke = sculpt_mask_expand_invoke;
- ot->modal = sculpt_mask_expand_modal;
- ot->cancel = sculpt_mask_expand_cancel;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
- ot->prop = RNA_def_boolean(
- ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
- ot->prop = RNA_def_boolean(ot->srna,
- "update_pivot",
- true,
- "Update Pivot Position",
- "Set the pivot position to the mask border after creating the mask");
- ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
- ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
-
- ot->prop = RNA_def_boolean(ot->srna,
- "use_normals",
- true,
- "Use Normals",
- "Generate the mask using the normals and curvature of the model");
- ot->prop = RNA_def_boolean(ot->srna,
- "keep_previous_mask",
- false,
- "Keep Previous Mask",
- "Generate the new mask on top of the current one");
- ot->prop = RNA_def_int(ot->srna,
- "edge_sensitivity",
- 300,
- 0,
- 2000,
- "Edge Detection Sensitivity",
- "Sensitivity for expanding the mask across sculpted sharp edges when "
- "using normals to generate the mask",
- 0,
- 2000);
- ot->prop = RNA_def_boolean(ot->srna,
- "create_face_set",
- false,
- "Expand Face Mask",
- "Expand a new Face Mask instead of the sculpt mask");
-}
-
void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
@@ -10703,8 +7843,7 @@ 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));
- char *visited_vertices = MEM_callocN(SCULPT_vertex_count_get(ss) * sizeof(char),
- "visited vertices");
+ BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
/* Assuming an average of 6 edges per vertex in a triangulated mesh. */
const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2;
@@ -10721,16 +7860,15 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
int from_v;
BLI_gsqueue_pop(not_visited_vertices, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, from_v, 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;
totpoints++;
ss->preview_vert_index_list[totpoints] = to_v;
totpoints++;
- if (visited_vertices[to_v] == 0) {
- visited_vertices[to_v] = 1;
+ if (!BLI_BITMAP_TEST(visited_vertices, to_v)) {
+ BLI_BITMAP_ENABLE(visited_vertices, to_v);
const float *co = SCULPT_vertex_co_get(ss, to_v);
if (len_squared_v3v3(brush_co, co) < radius * radius) {
BLI_gsqueue_push(not_visited_vertices, &to_v);
@@ -10738,7 +7876,7 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
}
}
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
}
BLI_gsqueue_free(not_visited_vertices);
@@ -10747,1069 +7885,6 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
ss->preview_vert_index_count = totpoints;
}
-void ED_sculpt_init_transform(struct bContext *C)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
- copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
-
- SCULPT_undo_push_begin("Transform");
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
-
- ss->pivot_rot[3] = 1.0f;
-
- SCULPT_vertex_random_access_init(ss);
- sculpt_filter_cache_init(ob, sd);
-}
-
-static void sculpt_transform_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
-{
-
- SculptThreadedTaskData *data = userdata;
- SculptSession *ss = data->ob->sculpt;
- PBVHNode *node = data->nodes[i];
-
- SculptOrigVertData orig_data;
- SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
-
- PBVHVertexIter vd;
-
- SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
- BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
- {
- SCULPT_orig_vert_data_update(&orig_data, &vd);
- float transformed_co[3], orig_co[3], disp[3];
- float fade = vd.mask ? *vd.mask : 0.0f;
- copy_v3_v3(orig_co, orig_data.co);
- char symm_area = SCULPT_get_vertex_symm_area(orig_co);
-
- copy_v3_v3(transformed_co, orig_co);
- mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
- sub_v3_v3v3(disp, transformed_co, orig_co);
- mul_v3_fl(disp, 1.0f - fade);
-
- add_v3_v3v3(vd.co, orig_co, disp);
-
- if (vd.mvert) {
- vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- BKE_pbvh_node_mark_update(node);
-}
-
-void ED_sculpt_update_modal_transform(struct bContext *C)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
-
- SCULPT_vertex_random_access_init(ss);
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
-
- SculptThreadedTaskData data = {
- .sd = sd,
- .ob = ob,
- .nodes = ss->filter_cache->nodes,
- };
-
- float final_pivot_pos[3], d_t[3], d_r[4];
- float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
- transform_mat[4][4];
-
- copy_v3_v3(final_pivot_pos, ss->pivot_pos);
- for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
- ePaintSymmetryAreas v_symm = i;
-
- copy_v3_v3(final_pivot_pos, ss->pivot_pos);
-
- unit_m4(pivot_mat);
-
- unit_m4(t_mat);
- unit_m4(r_mat);
- unit_m4(s_mat);
-
- /* Translation matrix. */
- sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
- SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, ss->init_pivot_pos);
- translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
-
- /* Rotation matrix. */
- sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
- normalize_qt(d_r);
- SCULPT_flip_quat_by_symm_area(d_r, symm, v_symm, ss->init_pivot_pos);
- quat_to_mat4(r_mat, d_r);
-
- /* Scale matrix. */
- size_to_mat4(s_mat, ss->pivot_scale);
-
- /* Pivot matrix. */
- SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, ss->init_pivot_pos);
- translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
- invert_m4_m4(pivot_imat, pivot_mat);
-
- /* Final transform matrix. */
- mul_m4_m4m4(transform_mat, r_mat, t_mat);
- mul_m4_m4m4(transform_mat, transform_mat, s_mat);
- mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
- mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
- }
-
- PBVHParallelSettings settings;
- BKE_pbvh_parallel_range_settings(
- &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
- BKE_pbvh_parallel_range(
- 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
-
- if (ss->deform_modifiers_active || ss->shapekey_active) {
- sculpt_flush_stroke_deform(sd, ob, true);
- }
-
- sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
-}
-
-void ED_sculpt_end_transform(struct bContext *C)
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- if (ss->filter_cache) {
- sculpt_filter_cache_free(ss);
- }
- SCULPT_undo_push_end();
- sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
-}
-
-typedef enum eSculptPivotPositionModes {
- SCULPT_PIVOT_POSITION_ORIGIN = 0,
- SCULPT_PIVOT_POSITION_UNMASKED = 1,
- SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
- SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
- SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
-} eSculptPivotPositionModes;
-
-static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
- {SCULPT_PIVOT_POSITION_ORIGIN,
- "ORIGIN",
- 0,
- "Origin",
- "Sets the pivot to the origin of the sculpt"},
- {SCULPT_PIVOT_POSITION_UNMASKED,
- "UNMASKED",
- 0,
- "Unmasked",
- "Sets the pivot position to the average position of the unmasked vertices"},
- {SCULPT_PIVOT_POSITION_MASK_BORDER,
- "BORDER",
- 0,
- "Mask border",
- "Sets the pivot position to the center of the border of the mask"},
- {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
- "ACTIVE",
- 0,
- "Active vertex",
- "Sets the pivot position to the active vertex position"},
- {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
- "SURFACE",
- 0,
- "Surface",
- "Sets the pivot position to the surface under the cursor"},
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
-{
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
-
- int mode = RNA_enum_get(op->ptr, "mode");
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
-
- /* Pivot to center. */
- if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
- zero_v3(ss->pivot_pos);
- }
- /* Pivot to active vertex. */
- else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
- copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
- }
- /* Pivot to raycast surface. */
- else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
- float stroke_location[3];
- float mouse[2];
- mouse[0] = RNA_float_get(op->ptr, "mouse_x");
- mouse[1] = RNA_float_get(op->ptr, "mouse_y");
- if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
- copy_v3_v3(ss->pivot_pos, stroke_location);
- }
- }
- else {
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-
- float avg[3];
- int total = 0;
- zero_v3(avg);
-
- /* Pivot to unmasked. */
- if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
- for (int n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < 1.0f) {
- if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- }
- /* Pivot to mask border. */
- else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
- const float threshold = 0.2f;
-
- for (int n = 0; n < totnode; n++) {
- PBVHVertexIter vd;
- BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
- {
- const float mask = (vd.mask) ? *vd.mask : 0.0f;
- if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
- if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
- add_v3_v3(avg, vd.co);
- total++;
- }
- }
- }
- BKE_pbvh_vertex_iter_end;
- }
- }
-
- if (total > 0) {
- mul_v3_fl(avg, 1.0f / total);
- copy_v3_v3(ss->pivot_pos, avg);
- }
-
- MEM_SAFE_FREE(nodes);
- }
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
- RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
- return sculpt_set_pivot_position_exec(C, op);
-}
-
-static void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Set Pivot Position";
- ot->idname = "SCULPT_OT_set_pivot_position";
- ot->description = "Sets the sculpt transform pivot position";
-
- /* API callbacks. */
- ot->invoke = sculpt_set_pivot_position_invoke;
- ot->exec = sculpt_set_pivot_position_exec;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_pivot_position_types,
- SCULPT_PIVOT_POSITION_UNMASKED,
- "Mode",
- "");
-
- RNA_def_float(ot->srna,
- "mouse_x",
- 0.0f,
- 0.0f,
- FLT_MAX,
- "Mouse Position X",
- "Position of the mouse used for \"Surface\" mode",
- 0.0f,
- 10000.0f);
- RNA_def_float(ot->srna,
- "mouse_y",
- 0.0f,
- 0.0f,
- FLT_MAX,
- "Mouse Position Y",
- "Position of the mouse used for \"Surface\" mode",
- 0.0f,
- 10000.0f);
-}
-
-typedef enum eSculptFaceGroupsCreateModes {
- SCULPT_FACE_SET_MASKED = 0,
- SCULPT_FACE_SET_VISIBLE = 1,
- SCULPT_FACE_SET_ALL = 2,
- SCULPT_FACE_SET_SELECTION = 3,
-} eSculptFaceGroupsCreateModes;
-
-static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
- {
- SCULPT_FACE_SET_MASKED,
- "MASKED",
- 0,
- "Face Set From Masked",
- "Create a new Face Set from the masked faces",
- },
- {
- SCULPT_FACE_SET_VISIBLE,
- "VISIBLE",
- 0,
- "Face Set From Visible",
- "Create a new Face Set from the visible vertices",
- },
- {
- SCULPT_FACE_SET_ALL,
- "ALL",
- 0,
- "Face Set Full Mesh",
- "Create an unique Face Set with all faces in the sculpt",
- },
- {
- SCULPT_FACE_SET_SELECTION,
- "SELECTION",
- 0,
- "Face Set From Edit Mode Selection",
- "Create an Face Set corresponding to the Edit Mode face selection",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_face_set_create_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- float threshold = 0.5f;
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("face set change");
- 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);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBLE) {
- 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);
- }
- }
- }
-
- if (mode == SCULPT_FACE_SET_ALL) {
- for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_face_set_set(ss, i, next_face_set);
- }
- }
-
- if (mode == SCULPT_FACE_SET_SELECTION) {
- Mesh *mesh = ob->data;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
-
- BMIter iter;
- BMFace *f;
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- ss->face_sets[BM_elem_index_get(f)] = next_face_set;
- }
- }
- BM_mesh_free(bm);
- }
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- SCULPT_undo_push_end();
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_create(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Create Face Set";
- ot->idname = "SCULPT_OT_face_sets_create";
- ot->description = "Create a new Face Set";
-
- /* api callbacks */
- ot->invoke = sculpt_face_set_create_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", "");
-}
-
-typedef enum eSculptFaceSetsInitMode {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0,
- SCULPT_FACE_SETS_FROM_MATERIALS = 1,
- SCULPT_FACE_SETS_FROM_NORMALS = 2,
- SCULPT_FACE_SETS_FROM_UV_SEAMS = 3,
- SCULPT_FACE_SETS_FROM_CREASES = 4,
- SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
- SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
-} eSculptFaceSetsInitMode;
-
-static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
- {
- SCULPT_FACE_SETS_FROM_LOOSE_PARTS,
- "LOOSE_PARTS",
- 0,
- "Face Sets From Loose Parts",
- "Create a Face Set per loose part in the mesh",
- },
- {
- SCULPT_FACE_SETS_FROM_MATERIALS,
- "MATERIALS",
- 0,
- "Face Sets From Material Slots",
- "Create a Face Set per Material Slot",
- },
- {
- SCULPT_FACE_SETS_FROM_NORMALS,
- "NORMALS",
- 0,
- "Face Sets From Mesh Normals",
- "Create Face Sets for Faces that have similar normal",
- },
- {
- SCULPT_FACE_SETS_FROM_UV_SEAMS,
- "UV_SEAMS",
- 0,
- "Face Sets From UV Seams",
- "Create Face Sets using UV Seams as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_CREASES,
- "CREASES",
- 0,
- "Face Sets From Edge Creases",
- "Create Face Sets using Edge Creases as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT,
- "BEVEL_WEIGHT",
- 0,
- "Face Sets From Bevel Weight",
- "Create Face Sets using Bevel Weights as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_SHARP_EDGES,
- "SHARP_EDGES",
- 0,
- "Face Sets From Sharp Edges",
- "Create Face Sets using Sharp Edges as boundaries",
- },
- {
- SCULPT_FACE_SETS_FROM_FACE_MAPS,
- "FACE_MAPS",
- 0,
- "Face Sets From Face Maps",
- "Create a Face Set per Face Map",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-typedef bool (*face_sets_flood_fill_test)(
- BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold);
-
-static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *UNUSED(from_e),
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return true;
-}
-
-static bool sculpt_face_sets_init_normals_test(
- BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold)
-{
- return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold;
-}
-
-static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return !BM_elem_flag_test(from_e, BM_ELEM_SEAM);
-}
-
-static bool sculpt_face_sets_init_crease_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold;
-}
-
-static bool sculpt_face_sets_init_bevel_weight_test(
- BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
-{
- return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold;
-}
-
-static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
- BMFace *UNUSED(from_f),
- BMEdge *from_e,
- BMFace *UNUSED(to_f),
- const float UNUSED(threshold))
-{
- return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
-}
-
-static void sculpt_face_sets_init_flood_fill(Object *ob,
- face_sets_flood_fill_test test,
- const float threshold)
-{
- SculptSession *ss = ob->sculpt;
- Mesh *mesh = ob->data;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
-
- bool *visited_faces = MEM_callocN(sizeof(bool) * mesh->totpoly, "visited faces");
- const int totfaces = mesh->totpoly;
-
- int *face_sets = ss->face_sets;
-
- BM_mesh_elem_table_init(bm, BM_FACE);
- BM_mesh_elem_table_ensure(bm, BM_FACE);
-
- int next_face_set = 1;
-
- for (int i = 0; i < totfaces; i++) {
- if (!visited_faces[i]) {
- GSQueue *queue;
- queue = BLI_gsqueue_new(sizeof(int));
-
- face_sets[i] = next_face_set;
- visited_faces[i] = true;
- BLI_gsqueue_push(queue, &i);
-
- while (!BLI_gsqueue_is_empty(queue)) {
- int from_f;
- BLI_gsqueue_pop(queue, &from_f);
-
- BMFace *f, *f_neighbor;
- BMEdge *ed;
- BMIter iter_a, iter_b;
-
- f = BM_face_at_index(bm, from_f);
-
- BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) {
- BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
- if (f_neighbor != f) {
- int neighbor_face_index = BM_elem_index_get(f_neighbor);
- if (!visited_faces[neighbor_face_index]) {
- if (test(bm, f, ed, f_neighbor, threshold)) {
- face_sets[neighbor_face_index] = next_face_set;
- visited_faces[neighbor_face_index] = true;
- BLI_gsqueue_push(queue, &neighbor_face_index);
- }
- }
- }
- }
- }
- }
-
- next_face_set += 1;
-
- BLI_gsqueue_free(queue);
- }
- }
-
- MEM_SAFE_FREE(visited_faces);
-
- BM_mesh_free(bm);
-}
-
-static void sculpt_face_sets_init_loop(Object *ob, const int mode)
-{
- Mesh *mesh = ob->data;
- SculptSession *ss = ob->sculpt;
- BMesh *bm;
- const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
- bm = BM_mesh_create(&allocsize,
- &((struct BMeshCreateParams){
- .use_toolflags = true,
- }));
-
- BM_mesh_bm_from_me(bm,
- mesh,
- (&(struct BMeshFromMeshParams){
- .calc_face_normal = true,
- }));
- BMIter iter;
- BMFace *f;
-
- const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
-
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
- ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1);
- }
- else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) {
- if (cd_fmaps_offset != -1) {
- ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2;
- }
- else {
- ss->face_sets[BM_elem_index_get(f)] = 1;
- }
- }
- }
- BM_mesh_free(bm);
-}
-
-static int sculpt_face_set_init_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- const int mode = RNA_enum_get(op->ptr, "mode");
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (!nodes) {
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_begin("face set change");
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- const float threshold = RNA_float_get(op->ptr, "threshold");
-
- switch (mode) {
- case SCULPT_FACE_SETS_FROM_LOOSE_PARTS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_MATERIALS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS);
- break;
- case SCULPT_FACE_SETS_FROM_NORMALS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_UV_SEAMS:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_CREASES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_SHARP_EDGES:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
- sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
- break;
- case SCULPT_FACE_SETS_FROM_FACE_MAPS:
- sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
- break;
- }
-
- SCULPT_undo_push_end();
-
- /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-
- ED_region_tag_redraw(region);
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_init(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Init Face Sets";
- ot->idname = "SCULPT_OT_face_sets_init";
- ot->description = "Initializes all Face Sets in the mesh";
-
- /* api callbacks */
- ot->invoke = sculpt_face_set_init_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(
- ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", "");
- RNA_def_float(
- ot->srna,
- "threshold",
- 0.5f,
- 0.0f,
- 1.0f,
- "Threshold",
- "Minimum value to consider a certain atribute a boundary when creating the Face Sets",
- 0.0f,
- 1.0f);
-}
-
-typedef enum eSculptFaceGroupVisibilityModes {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1,
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2,
- SCULPT_FACE_SET_VISIBILITY_INVERT = 3,
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4,
-} eSculptFaceGroupVisibilityModes;
-
-static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = {
- {
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "TOGGLE",
- 0,
- "Toggle Visibility",
- "Hide all Face Sets except for the active one",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE,
- "SHOW_ACTIVE",
- 0,
- "Show Active Face Set",
- "Show Active Face Set",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE,
- "HIDE_ACTIVE",
- 0,
- "Hide Active Face Sets",
- "Hide Active Face Sets",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_INVERT,
- "INVERT",
- 0,
- "Invert Face Set Visibility",
- "Invert Face Set Visibility",
- },
- {
- SCULPT_FACE_SET_VISIBILITY_SHOW_ALL,
- "SHOW_ALL",
- 0,
- "Show All Face Sets",
- "Show All Face Sets",
- },
- {0, NULL, 0, NULL, NULL},
-};
-
-static int sculpt_face_sets_change_visibility_invoke(bContext *C,
- wmOperator *op,
- const wmEvent *UNUSED(event))
-{
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
- Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
-
- const int tot_vert = SCULPT_vertex_count_get(ss);
- const int mode = RNA_enum_get(op->ptr, "mode");
- int active_vertex_index = SCULPT_active_vertex_get(ss);
- int active_face_set = SCULPT_vertex_face_set_get(ss, active_vertex_index);
-
- SCULPT_undo_push_begin("Hide area");
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
-
- if (totnode == 0) {
- MEM_SAFE_FREE(nodes);
- return OPERATOR_CANCELLED;
- }
-
- SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
- bool hidden_vertex = false;
-
- /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
- * 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)) {
- hidden_vertex = true;
- break;
- }
- }
- }
-
- for (int i = 0; i < ss->totpoly; i++) {
- if (ss->face_sets[i] <= 0) {
- hidden_vertex = true;
- break;
- }
- }
-
- if (hidden_vertex) {
- SCULPT_face_sets_visibility_all_set(ss, true);
- }
- else {
- SCULPT_face_sets_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
- SCULPT_face_sets_visibility_all_set(ss, true);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
- SCULPT_face_sets_visibility_all_set(ss, false);
- SCULPT_face_set_visibility_set(ss, active_face_set, true);
- for (int i = 0; i < tot_vert; i++) {
- SCULPT_vertex_visible_set(ss,
- i,
- SCULPT_vertex_visible_get(ss, i) &&
- SCULPT_vertex_has_face_set(ss, i, active_face_set));
- }
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
- SCULPT_face_set_visibility_set(ss, active_face_set, false);
- }
-
- if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
- SCULPT_face_sets_visibility_invert(ss);
- }
-
- /* For modes that use the cursor active vertex, update the rotation origin for viewport
- * navigation. */
- if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- float location[3];
- copy_v3_v3(location, SCULPT_active_vertex_co_get(ss));
- mul_m4_v3(ob->obmat, location);
- copy_v3_v3(ups->average_stroke_accum, location);
- ups->average_stroke_counter = 1;
- ups->last_stroke_valid = true;
- }
-
- /* Sync face sets visibility and vertex visibility. */
- SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
-
- SCULPT_undo_push_end();
-
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_update_visibility(nodes[i]);
- }
-
- BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
-
- MEM_SAFE_FREE(nodes);
-
- if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
- BKE_mesh_flush_hidden_from_verts(ob->data);
- }
-
- ED_region_tag_redraw(region);
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Face Sets Visibility";
- ot->idname = "SCULPT_OT_face_set_change_visibility";
- ot->description = "Change the visibility of the Face Sets of the sculpt";
-
- /* Api callbacks. */
- ot->invoke = sculpt_face_sets_change_visibility_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna,
- "mode",
- prop_sculpt_face_sets_change_visibility_types,
- SCULPT_FACE_SET_VISIBILITY_TOGGLE,
- "Mode",
- "");
-}
-
-static int sculpt_face_sets_randomize_colors_invoke(bContext *C,
- wmOperator *UNUSED(op),
- const wmEvent *UNUSED(event))
-{
-
- Object *ob = CTX_data_active_object(C);
- SculptSession *ss = ob->sculpt;
- ARegion *region = CTX_wm_region(C);
-
- /* Dyntopo and Multires not supported for now. */
- if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
- return OPERATOR_CANCELLED;
- }
-
- PBVH *pbvh = ob->sculpt->pbvh;
- PBVHNode **nodes;
- int totnode;
- Mesh *mesh = ob->data;
-
- mesh->face_sets_color_seed += 1;
- if (ss->face_sets) {
- const int random_index = clamp_i(
- ss->totpoly * BLI_hash_int_01(mesh->face_sets_color_seed), 0, max_ii(0, ss->totpoly - 1));
- mesh->face_sets_color_default = ss->face_sets[random_index];
- }
- BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
-
- BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_redraw(nodes[i]);
- }
-
- MEM_SAFE_FREE(nodes);
-
- View3D *v3d = CTX_wm_view3d(C);
- if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
- }
-
- ED_region_tag_redraw(region);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
-{
- /* Identifiers. */
- ot->name = "Randomize Face Sets Colors";
- ot->idname = "SCULPT_OT_face_sets_randomize_colors";
- ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
-
- /* Api callbacks. */
- ot->invoke = sculpt_face_sets_randomize_colors_invoke;
- ot->poll = SCULPT_mode_poll;
-
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
void ED_operatortypes_sculpt(void)
{
@@ -11831,4 +7906,5 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_face_sets_change_visibility);
WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
WM_operatortype_append(SCULPT_OT_face_sets_init);
+ WM_operatortype_append(SCULPT_OT_cloth_filter);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c
new file mode 100644
index 00000000000..bfa657147fd
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c
@@ -0,0 +1,304 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
+ const Brush *br,
+ const eAutomasking_flag mode)
+{
+ return br->automasking_flags & mode || sd->automasking_flags & mode;
+}
+
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br)
+{
+ if (SCULPT_stroke_is_dynamic_topology(ss, br)) {
+ return false;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_TOPOLOGY)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_FACE_SETS)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
+ return true;
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, br, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
+ return true;
+ }
+ return false;
+}
+
+float SCULPT_automasking_factor_get(SculptSession *ss, int vert)
+{
+ if (ss->cache && ss->cache->automask) {
+ return ss->cache->automask[vert];
+ }
+ else {
+ return 1.0f;
+ }
+}
+
+void SCULPT_automasking_end(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->cache && ss->cache->automask) {
+ MEM_freeN(ss->cache->automask);
+ }
+}
+
+static bool sculpt_automasking_is_constrained_by_radius(Brush *br)
+{
+ /* 2D falloff is not constrained by radius. */
+ if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
+ return false;
+ }
+
+ if (ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE)) {
+ return true;
+ }
+ return false;
+}
+
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
+
+static bool automask_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool UNUSED(is_duplicate), void *userdata)
+{
+ AutomaskFloodFillData *data = userdata;
+
+ data->automask_factor[to_v] = 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));
+}
+
+static float *SCULPT_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Topology masking: pmap missing");
+ return NULL;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 0.0f;
+ }
+
+ /* Flood fill automask to connected vertices. Limited to vertices inside
+ * the brush radius if the tool requires it. */
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, ss->cache->radius);
+
+ AutomaskFloodFillData fdata = {
+ .automask_factor = automask_factor,
+ .radius = ss->cache->radius,
+ .use_radius = sculpt_automasking_is_constrained_by_radius(brush),
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ };
+ copy_v3_v3(fdata.location, SCULPT_active_vertex_co_get(ss));
+ SCULPT_floodfill_execute(ss, &flood, automask_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ return automask_factor;
+}
+
+static float *sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return NULL;
+ }
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Face Sets automasking: pmap missing");
+ return NULL;
+ }
+
+ int tot_vert = SCULPT_vertex_count_get(ss);
+ int active_face_set = SCULPT_active_face_set_get(ss);
+ for (int i = 0; i < tot_vert; i++) {
+ if (!SCULPT_vertex_has_face_set(ss, i, active_face_set)) {
+ automask_factor[i] *= 0.0f;
+ }
+ }
+
+ return automask_factor;
+}
+
+#define EDGE_DISTANCE_INF -1
+
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"Boundary Edges masking: pmap missing");
+ return NULL;
+ }
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ int *edge_distance = MEM_callocN(sizeof(int) * totvert, "automask_factor");
+
+ for (int i = 0; i < totvert; i++) {
+ edge_distance[i] = EDGE_DISTANCE_INF;
+ switch (mode) {
+ case AUTOMASK_INIT_BOUNDARY_EDGES:
+ if (!SCULPT_vertex_is_boundary(ss, i)) {
+ edge_distance[i] = 0;
+ }
+ break;
+ case AUTOMASK_INIT_BOUNDARY_FACE_SETS:
+ if (!SCULPT_vertex_has_unique_face_set(ss, i)) {
+ edge_distance[i] = 0;
+ }
+ break;
+ }
+ }
+
+ for (int propagation_it = 0; propagation_it < propagation_steps; propagation_it++) {
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] == EDGE_DISTANCE_INF) {
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ if (edge_distance[ni.index] == propagation_it) {
+ edge_distance[i] = propagation_it + 1;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ }
+ }
+ }
+
+ for (int i = 0; i < totvert; i++) {
+ if (edge_distance[i] != EDGE_DISTANCE_INF) {
+ const float p = 1.0f - ((float)edge_distance[i] / (float)propagation_steps);
+ const float edge_boundary_automask = pow2f(p);
+ automask_factor[i] *= (1.0f - edge_boundary_automask);
+ }
+ }
+
+ MEM_SAFE_FREE(edge_distance);
+ return automask_factor;
+}
+
+void SCULPT_automasking_init(Sculpt *sd, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ if (!SCULPT_is_automasking_enabled(sd, ss, brush)) {
+ return;
+ }
+
+ ss->cache->automask = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss),
+ "automask_factor");
+
+ for (int i = 0; i < totvert; i++) {
+ ss->cache->automask[i] = 1.0f;
+ }
+
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_TOPOLOGY)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_topology_automasking_init(sd, ob, ss->cache->automask);
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_FACE_SETS)) {
+ SCULPT_vertex_random_access_init(ss);
+ sculpt_face_sets_automasking_init(sd, ob, ss->cache->automask);
+ }
+
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_EDGES)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_boundary_automasking_init(ob,
+ AUTOMASK_INIT_BOUNDARY_EDGES,
+ brush->automasking_boundary_edges_propagation_steps,
+ ss->cache->automask);
+ }
+ if (SCULPT_is_automasking_mode_enabled(sd, brush, BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS)) {
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_boundary_automasking_init(ob,
+ AUTOMASK_INIT_BOUNDARY_FACE_SETS,
+ brush->automasking_boundary_edges_propagation_steps,
+ ss->cache->automask);
+ }
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c
index 12aaf756cf3..3203282c30c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_cloth.c
+++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -106,9 +106,11 @@
#define CLOTH_MAX_CONSTRAINTS_PER_VERTEX 1024
#define CLOTH_SIMULATION_TIME_STEP 0.01f
-static void cloth_brush_add_length_constraint(SculptSession *ss, const int v1, const int v2)
+static void cloth_brush_add_length_constraint(SculptSession *ss,
+ SculptClothSimulation *cloth_sim,
+ const int v1,
+ const int v2)
{
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v1 = v1;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].v2 = v2;
cloth_sim->length_constraints[cloth_sim->tot_length_constraints].length = len_v3v3(
@@ -133,24 +135,22 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
SculptSession *ss = data->ob->sculpt;
PBVHVertexIter vd;
- const float radius = ss->cache->initial_radius;
- const float limit = radius + (radius * data->brush->cloth_sim_limit);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- if (len_squared_v3v3(vd.co, ss->cache->initial_location) < limit * limit) {
+ if (len_squared_v3v3(vd.co, data->cloth_sim_initial_location) <
+ data->cloth_sim_radius * data->cloth_sim_radius) {
SculptVertexNeighborIter ni;
int build_indices[CLOTH_MAX_CONSTRAINTS_PER_VERTEX];
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.index, ni) {
build_indices[tot_indices] = ni.index;
tot_indices++;
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
/* As we don't know the order of the neighbor vertices, we create all possible combinations
* between the neighbor and the original vertex as length constraints. */
@@ -160,7 +160,8 @@ static void do_cloth_brush_build_constraints_task_cb_ex(
for (int c_i = 0; c_i < tot_indices; c_i++) {
for (int c_j = 0; c_j < tot_indices; c_j++) {
if (c_i != c_j) {
- cloth_brush_add_length_constraint(ss, build_indices[c_i], build_indices[c_j]);
+ cloth_brush_add_length_constraint(
+ ss, data->cloth_sim, build_indices[c_i], build_indices[c_j]);
}
}
}
@@ -193,11 +194,11 @@ static float cloth_brush_simulation_falloff_get(const Brush *brush,
}
}
-static void cloth_brush_apply_force_to_vertex(SculptSession *ss,
+static void cloth_brush_apply_force_to_vertex(SculptSession *UNUSED(ss),
+ SculptClothSimulation *cloth_sim,
const float force[3],
const int vertex_index)
{
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
madd_v3_v3fl(cloth_sim->acceleration[vertex_index], force, 1.0f / cloth_sim->mass);
}
@@ -213,8 +214,9 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float *grab_delta = data->grab_delta;
float(*imat)[4] = data->mat;
- const bool use_falloff_plane = brush->cloth_force_falloff_type ==
- BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
+ const bool use_falloff_plane = !SCULPT_is_cloth_deform_brush(brush) &&
+ brush->cloth_force_falloff_type ==
+ BRUSH_CLOTH_FORCE_FALLOFF_PLANE;
PBVHVertexIter vd;
const float bstrength = ss->cache->bstrength;
@@ -222,6 +224,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* For Pich Perpendicular Deform Type. */
float x_object_space[3];
@@ -246,14 +249,29 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
gravity, ss->cache->gravity_direction, -ss->cache->radius * data->sd->gravity_factor);
}
+ /* Original data for deform brushes. */
+ SculptOrigVertData orig_data;
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]);
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
float force[3];
const float sim_factor = cloth_brush_simulation_falloff_get(
brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]);
+ float current_vertex_location[3];
+ if (SCULPT_is_cloth_deform_brush(brush)) {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ copy_v3_v3(current_vertex_location, orig_data.co);
+ }
+ else {
+ copy_v3_v3(current_vertex_location, vd.co);
+ }
+
/* When using the plane falloff mode the falloff is not constrained by the brush radius. */
- if (sculpt_brush_test_sq_fn(&test, vd.co) || use_falloff_plane) {
+ if (sculpt_brush_test_sq_fn(&test, current_vertex_location) || use_falloff_plane) {
float dist = sqrtf(test.dist);
@@ -264,17 +282,16 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
const float fade = sim_factor * bstrength *
SCULPT_brush_strength_factor(ss,
brush,
- vd.co,
+ current_vertex_location,
dist,
vd.no,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
float brush_disp[3];
float normal[3];
-
if (vd.no) {
normal_short_to_float_v3(normal, vd.no);
}
@@ -293,7 +310,10 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(force, offset, -fade);
break;
case BRUSH_CLOTH_DEFORM_GRAB:
- mul_v3_v3fl(force, grab_delta, fade);
+ /* Grab writes the positions in the simulation directly without applying forces. */
+ madd_v3_v3v3fl(
+ cloth_sim->pos[vd.index], orig_data.co, ss->cache->grab_delta_symmetry, fade);
+ zero_v3(force);
break;
case BRUSH_CLOTH_DEFORM_PINCH_POINT:
if (use_falloff_plane) {
@@ -329,13 +349,15 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata,
madd_v3_v3fl(force, gravity, fade);
- cloth_brush_apply_force_to_vertex(ss, force, vd.index);
+ cloth_brush_apply_force_to_vertex(ss, ss->cache->cloth_sim, force, vd.index);
}
}
BKE_pbvh_vertex_iter_end;
}
-static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, Brush *brush)
+static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss,
+ const float cloth_mass,
+ const float cloth_damping)
{
const int totverts = SCULPT_vertex_count_get(ss);
SculptClothSimulation *cloth_sim;
@@ -354,8 +376,8 @@ static SculptClothSimulation *cloth_brush_simulation_create(SculptSession *ss, B
cloth_sim->length_constraint_tweak = MEM_callocN(sizeof(float) * totverts,
"cloth sim length tweak");
- cloth_sim->mass = brush->cloth_mass;
- cloth_sim->damping = brush->cloth_damping;
+ cloth_sim->mass = cloth_mass;
+ cloth_sim->damping = cloth_damping;
return cloth_sim;
}
@@ -367,12 +389,16 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
SculptSession *ss = data->ob->sculpt;
const Brush *brush = data->brush;
PBVHVertexIter vd;
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
+ SculptClothSimulation *cloth_sim = data->cloth_sim;
const float time_step = data->cloth_time_step;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
- const float sim_factor = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[vd.index]);
+ const float sim_factor = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[vd.index]) :
+ 1.0f;
if (sim_factor > 0.0f) {
int i = vd.index;
float temp[3];
@@ -393,7 +419,7 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
copy_v3_fl(cloth_sim->acceleration[i], 0.0f);
- copy_v3_v3(vd.co, ss->cache->cloth_sim->pos[vd.index]);
+ copy_v3_v3(vd.co, cloth_sim->pos[vd.index]);
if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
@@ -405,7 +431,10 @@ static void do_cloth_brush_solve_simulation_task_cb_ex(
static void cloth_brush_build_nodes_constraints(Sculpt *sd,
Object *ob,
PBVHNode **nodes,
- int totnode)
+ int totnode,
+ SculptClothSimulation *cloth_sim,
+ float initial_location[3],
+ const float radius)
{
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -413,7 +442,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
* storing the constraints per node. */
/* Currently all constrains are added to the same global array which can't be accessed from
* different threads. */
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, false, totnode);
SculptThreadedTaskData build_constraints_data = {
@@ -421,8 +450,11 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd,
.ob = ob,
.brush = brush,
.nodes = nodes,
+ .cloth_sim = cloth_sim,
+ .cloth_sim_initial_location = initial_location,
+ .cloth_sim_radius = radius,
};
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings);
}
@@ -461,10 +493,18 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
const float mask_v2 = (1.0f - SCULPT_vertex_mask_get(ss, v2)) *
SCULPT_automasking_factor_get(ss, v2);
- const float sim_factor_v1 = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v1]);
- const float sim_factor_v2 = cloth_brush_simulation_falloff_get(
- brush, ss->cache->radius, ss->cache->initial_location, cloth_sim->init_pos[v2]);
+ const float sim_factor_v1 = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[v1]) :
+ 1.0f;
+ const float sim_factor_v2 = ss->cache ? cloth_brush_simulation_falloff_get(
+ brush,
+ ss->cache->radius,
+ ss->cache->initial_location,
+ cloth_sim->init_pos[v2]) :
+ 1.0f;
madd_v3_v3fl(cloth_sim->pos[v1], correction_vector_half, 1.0f * mask_v1 * sim_factor_v1);
madd_v3_v3fl(cloth_sim->pos[v2], correction_vector_half, -1.0f * mask_v2 * sim_factor_v2);
@@ -472,13 +512,12 @@ static void cloth_brush_satisfy_constraints(SculptSession *ss,
}
}
-static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+static void cloth_brush_do_simulation_step(
+ Sculpt *sd, Object *ob, SculptClothSimulation *cloth_sim, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- SculptClothSimulation *cloth_sim = ss->cache->cloth_sim;
-
/* Update the constraints. */
cloth_brush_satisfy_constraints(ss, brush, cloth_sim);
@@ -489,11 +528,12 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no
.brush = brush,
.nodes = nodes,
.cloth_time_step = CLOTH_SIMULATION_TIME_STEP,
+ .cloth_sim = cloth_sim,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings);
}
@@ -566,9 +606,9 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod
}
}
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings);
}
@@ -589,7 +629,8 @@ 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 (ss->cache->mirror_symmetry_pass == 0) {
- ss->cache->cloth_sim = cloth_brush_simulation_create(ss, brush);
+ ss->cache->cloth_sim = cloth_brush_simulation_create(
+ ss, brush->cloth_mass, brush->cloth_damping);
for (int i = 0; i < totverts; i++) {
copy_v3_v3(ss->cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
copy_v3_v3(ss->cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
@@ -597,7 +638,10 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
}
/* Build the constraints. */
- cloth_brush_build_nodes_constraints(sd, ob, nodes, totnode);
+ const float radius = ss->cache->initial_radius;
+ const float limit = radius + (radius * brush->cloth_sim_limit);
+ cloth_brush_build_nodes_constraints(
+ sd, ob, nodes, totnode, ss->cache->cloth_sim, ss->cache->location, limit);
return;
}
@@ -611,7 +655,7 @@ void SCULPT_do_cloth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cloth_brush_apply_brush_foces(sd, ob, nodes, totnode);
/* Update and write the simulation to the nodes. */
- cloth_brush_do_simulation_step(sd, ob, nodes, totnode);
+ cloth_brush_do_simulation_step(sd, ob, ss->cache->cloth_sim, nodes, totnode);
return;
}
@@ -687,3 +731,246 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
immEnd();
}
+
+/* Cloth Filter. */
+
+typedef enum eSculpClothFilterType {
+ CLOTH_FILTER_GRAVITY,
+ CLOTH_FILTER_INFLATE,
+ CLOTH_FILTER_EXPAND,
+ CLOTH_FILTER_PINCH,
+} eSculptClothFilterType;
+
+static EnumPropertyItem prop_cloth_filter_type[] = {
+ {CLOTH_FILTER_GRAVITY, "GRAVITY", 0, "Gravity", "Applies gravity to the simulation"},
+ {CLOTH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflates the cloth"},
+ {CLOTH_FILTER_EXPAND, "EXPAND", 0, "Expand", "Expands the cloth's dimensions"},
+ {CLOTH_FILTER_PINCH,
+ "PINCH",
+ 0,
+ "Pinch",
+ "Pinches the cloth to the point were the cursor was when the filter started"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void cloth_filter_apply_forces_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ Sculpt *sd = data->sd;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptClothSimulation *cloth_sim = ss->filter_cache->cloth_sim;
+ const int filter_type = data->filter_type;
+
+ float sculpt_gravity[3] = {0.0f};
+ if (sd->gravity_object) {
+ copy_v3_v3(sculpt_gravity, sd->gravity_object->obmat[2]);
+ }
+ else {
+ sculpt_gravity[2] = -1.0f;
+ }
+ mul_v3_fl(sculpt_gravity, sd->gravity_factor * data->filter_strength);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ float force[3] = {0.0f, 0.0f, 0.0f};
+
+ 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)) {
+ continue;
+ }
+ }
+
+ switch (filter_type) {
+ case CLOTH_FILTER_GRAVITY:
+ force[2] = -data->filter_strength * fade;
+ break;
+ case CLOTH_FILTER_INFLATE: {
+ float normal[3];
+ SCULPT_vertex_normal_get(ss, vd.index, normal);
+ mul_v3_v3fl(force, normal, fade * data->filter_strength);
+ } break;
+ case CLOTH_FILTER_EXPAND:
+ cloth_sim->length_constraint_tweak[vd.index] += fade * data->filter_strength * 0.01f;
+ zero_v3(force);
+ break;
+ case CLOTH_FILTER_PINCH:
+ sub_v3_v3v3(force, ss->filter_cache->cloth_sim_pinch_point, vd.co);
+ normalize_v3(force);
+ mul_v3_fl(force, fade * data->filter_strength);
+ break;
+ }
+
+ add_v3_v3(force, sculpt_gravity);
+
+ cloth_brush_apply_force_to_vertex(ss, cloth_sim, force, vd.index);
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ SCULPT_vertex_random_access_init(ss);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ 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));
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, cloth_filter_apply_forces_task_cb, &settings);
+
+ /* Update and write the simulation to the nodes. */
+ cloth_brush_do_simulation_step(
+ sd, ob, ss->filter_cache->cloth_sim, ss->filter_cache->nodes, ss->filter_cache->totnode);
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_cloth_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ SculptSession *ss = ob->sculpt;
+
+ /* Update the active vertex */
+ float mouse[2];
+ SculptCursorGeometryInfo sgi;
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ /* Needs mask data to be available as it is used when solving the constraints. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_undo_push_begin("Cloth filter");
+ SCULPT_filter_cache_init(ob, sd);
+
+ const float cloth_mass = RNA_float_get(op->ptr, "cloth_mass");
+ const float cloth_damping = RNA_float_get(op->ptr, "cloth_damping");
+ ss->filter_cache->cloth_sim = cloth_brush_simulation_create(ss, cloth_mass, cloth_damping);
+ copy_v3_v3(ss->filter_cache->cloth_sim_pinch_point, SCULPT_active_vertex_co_get(ss));
+
+ const int totverts = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totverts; i++) {
+ copy_v3_v3(ss->filter_cache->cloth_sim->prev_pos[i], SCULPT_vertex_co_get(ss, i));
+ copy_v3_v3(ss->filter_cache->cloth_sim->init_pos[i], SCULPT_vertex_co_get(ss, i));
+ }
+
+ float origin[3] = {0.0f, 0.0f, 0.0f};
+ cloth_brush_build_nodes_constraints(sd,
+ ob,
+ ss->filter_cache->nodes,
+ ss->filter_cache->totnode,
+ ss->filter_cache->cloth_sim,
+ origin,
+ FLT_MAX);
+
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+ if (use_face_sets) {
+ ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
+ }
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_cloth_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Filter cloth";
+ ot->idname = "SCULPT_OT_cloth_filter";
+ ot->description = "Applies a cloth simulation deformation to the entire mesh";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_cloth_filter_invoke;
+ ot->modal = sculpt_cloth_filter_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_cloth_filter_type,
+ CLOTH_FILTER_GRAVITY,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_float(ot->srna,
+ "cloth_mass",
+ 1.0f,
+ 0.0f,
+ 2.0f,
+ "Cloth Mass",
+ "Mass of each simulation particle",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "cloth_damping",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Cloth Damping",
+ "How much the applied forces are propagated through the cloth",
+ 0.0f,
+ 1.0f);
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_face_sets",
+ false,
+ "Use Face Sets",
+ "Apply the filter only to the Face Set under the cursor");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c
new file mode 100644
index 00000000000..b7d1cd8c005
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_detail.c
@@ -0,0 +1,428 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef struct {
+ const float *ray_start;
+ bool hit;
+ float depth;
+ float edge_length;
+
+ struct IsectRayPrecalc isect_precalc;
+} SculptDetailRaycastData;
+
+static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ return SCULPT_mode_poll(C) && ob->sculpt->bm &&
+ (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL));
+}
+
+static bool sculpt_and_dynamic_topology_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+
+ return SCULPT_mode_poll(C) && ob->sculpt->bm;
+}
+
+static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ float size;
+ float bb_min[3], bb_max[3], center[3], dim[3];
+ int totnodes;
+ PBVHNode **nodes;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
+
+ if (!totnodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ for (int i = 0; i < totnodes; i++) {
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
+ /* Get the bounding box, it's center and size. */
+ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max);
+ add_v3_v3v3(center, bb_min, bb_max);
+ mul_v3_fl(center, 0.5f);
+ sub_v3_v3v3(dim, bb_max, bb_min);
+ size = max_fff(dim[0], dim[1], dim[2]);
+
+ /* Update topology size. */
+ 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("Dynamic topology flood fill");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS);
+
+ while (BKE_pbvh_bmesh_update_topology(
+ ss->pbvh, PBVH_Collapse | PBVH_Subdivide, center, NULL, size, false, false)) {
+ for (int i = 0; i < totnodes; i++) {
+ BKE_pbvh_node_mark_topology_update(nodes[i]);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+ SCULPT_undo_push_end();
+
+ /* Force rebuild of pbvh for better BB placement. */
+ SCULPT_pbvh_clear(ob);
+ /* Redraw. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_detail_flood_fill(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Detail Flood Fill";
+ ot->idname = "SCULPT_OT_detail_flood_fill";
+ ot->description = "Flood fill the mesh with the selected detail setting";
+
+ /* API callbacks. */
+ ot->exec = sculpt_detail_flood_fill_exec;
+ ot->poll = sculpt_and_constant_or_manual_detail_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+typedef enum eSculptSampleDetailModeTypes {
+ SAMPLE_DETAIL_DYNTOPO = 0,
+ SAMPLE_DETAIL_VOXEL = 1,
+} eSculptSampleDetailModeTypes;
+
+static EnumPropertyItem prop_sculpt_sample_detail_mode_types[] = {
+ {SAMPLE_DETAIL_DYNTOPO, "DYNTOPO", 0, "Dyntopo", "Sample dyntopo detail"},
+ {SAMPLE_DETAIL_VOXEL, "VOXEL", 0, "Voxel", "Sample mesh voxel size"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void sample_detail_voxel(bContext *C, ViewContext *vc, int mx, int my)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = vc->obact;
+ Mesh *mesh = ob->data;
+
+ SculptSession *ss = ob->sculpt;
+ SculptCursorGeometryInfo sgi;
+ SCULPT_vertex_random_access_init(ss);
+
+ /* Update the active vertex. */
+ float mouse[2] = {mx, my};
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+
+ /* Average the edge length of the connected edges to the active vertex. */
+ int 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));
+ tot += 1;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (tot > 0) {
+ mesh->remesh_voxel_size = edge_length / (float)tot;
+ }
+}
+
+static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
+{
+ if (BKE_pbvh_node_get_tmin(node) < *tmin) {
+ SculptDetailRaycastData *srd = data_v;
+ if (BKE_pbvh_bmesh_node_raycast_detail(
+ node, srd->ray_start, &srd->isect_precalc, &srd->depth, &srd->edge_length)) {
+ srd->hit = true;
+ *tmin = srd->depth;
+ }
+ }
+}
+
+static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region, int mx, int my)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = vc->obact;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ SCULPT_stroke_modifiers_check(C, ob, brush);
+
+ float mouse[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
+ float ray_start[3], ray_end[3], ray_normal[3];
+ float depth = SCULPT_raycast_init(vc, mouse, ray_start, ray_end, ray_normal, false);
+
+ SculptDetailRaycastData srd;
+ srd.hit = 0;
+ srd.ray_start = ray_start;
+ srd.depth = depth;
+ srd.edge_length = 0.0f;
+ isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
+
+ BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
+
+ if (srd.hit && srd.edge_length > 0.0f) {
+ /* Convert edge length to world space detail resolution. */
+ sd->constant_detail = 1 / (srd.edge_length * mat4_to_scale(ob->obmat));
+ }
+}
+
+static int sample_detail(bContext *C, int mx, int my, int mode)
+{
+ /* Find 3D view to pick from. */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my);
+ ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL;
+ if (region == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Set context to 3D view. */
+ ScrArea *prev_area = CTX_wm_area(C);
+ ARegion *prev_region = CTX_wm_region(C);
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+
+ Object *ob = vc.obact;
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->pbvh) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Pick sample detail. */
+ switch (mode) {
+ case SAMPLE_DETAIL_DYNTOPO:
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_BMESH) {
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+ return OPERATOR_CANCELLED;
+ }
+ sample_detail_dyntopo(C, &vc, region, mx, my);
+ break;
+ case SAMPLE_DETAIL_VOXEL:
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) {
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+ return OPERATOR_CANCELLED;
+ }
+ sample_detail_voxel(C, &vc, mx, my);
+ break;
+ }
+
+ /* Restore context. */
+ CTX_wm_area_set(C, prev_area);
+ CTX_wm_region_set(C, prev_region);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
+{
+ int ss_co[2];
+ RNA_int_get_array(op->ptr, "location", ss_co);
+ int mode = RNA_enum_get(op->ptr, "mode");
+ return sample_detail(C, ss_co[0], ss_co[1], mode);
+}
+
+static int sculpt_sample_detail_size_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e))
+{
+ ED_workspace_status_text(C, TIP_("Click on the mesh to set the detail"));
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_sample_detail_size_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ switch (event->type) {
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ int ss_co[2] = {event->x, event->y};
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+ sample_detail(C, ss_co[0], ss_co[1], mode);
+
+ RNA_int_set_array(op->ptr, "location", ss_co);
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ case RIGHTMOUSE: {
+ WM_cursor_modal_restore(CTX_wm_window(C));
+ ED_workspace_status_text(C, NULL);
+
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_sample_detail_size(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Sample Detail Size";
+ ot->idname = "SCULPT_OT_sample_detail_size";
+ ot->description = "Sample the mesh detail on clicked point";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_sample_detail_size_invoke;
+ ot->exec = sculpt_sample_detail_size_exec;
+ ot->modal = sculpt_sample_detail_size_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int_array(ot->srna,
+ "location",
+ 2,
+ NULL,
+ 0,
+ SHRT_MAX,
+ "Location",
+ "Screen Coordinates of sampling",
+ 0,
+ SHRT_MAX);
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_sample_detail_mode_types,
+ SAMPLE_DETAIL_DYNTOPO,
+ "Detail Mode",
+ "Target sculpting workflow that is going to use the sampled size");
+}
+
+/* Dynamic-topology detail size.
+ *
+ * This should be improved further, perhaps by showing a triangle
+ * grid rather than brush alpha. */
+static void set_brush_rc_props(PointerRNA *ptr, const char *prop)
+{
+ char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop);
+ RNA_string_set(ptr, "data_path_primary", path);
+ MEM_freeN(path);
+}
+
+static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_radial_control", true);
+
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+
+ if (sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL)) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(
+ &props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution");
+ }
+ else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) {
+ set_brush_rc_props(&props_ptr, "constant_detail_resolution");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent");
+ }
+ else {
+ set_brush_rc_props(&props_ptr, "detail_size");
+ RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_size");
+ }
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+
+ WM_operator_properties_free(&props_ptr);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_set_detail_size(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Detail Size";
+ ot->idname = "SCULPT_OT_set_detail_size";
+ ot->description =
+ "Set the mesh detail (either relative or constant one, depending on current dyntopo mode)";
+
+ /* API callbacks. */
+ ot->exec = sculpt_set_detail_size_exec;
+ ot->poll = sculpt_and_dynamic_topology_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
new file mode 100644
index 00000000000..eefd8529dbf
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c
@@ -0,0 +1,439 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_particle.h"
+#include "BKE_pbvh.h"
+#include "BKE_pointcache.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+void SCULPT_dynamic_topology_triangulate(BMesh *bm)
+{
+ if (bm->totloop != bm->totface * 3) {
+ BM_mesh_triangulate(
+ bm, MOD_TRIANGULATE_QUAD_BEAUTY, MOD_TRIANGULATE_NGON_EARCLIP, 4, false, NULL, NULL, NULL);
+ }
+}
+
+void SCULPT_pbvh_clear(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ /* Clear out any existing DM and PBVH. */
+ if (ss->pbvh) {
+ BKE_pbvh_free(ss->pbvh);
+ ss->pbvh = NULL;
+ }
+
+ if (ss->pmap) {
+ MEM_freeN(ss->pmap);
+ ss->pmap = NULL;
+ }
+
+ if (ss->pmap_mem) {
+ MEM_freeN(ss->pmap_mem);
+ ss->pmap_mem = NULL;
+ }
+
+ BKE_object_free_derived_caches(ob);
+
+ /* Tag to rebuild PBVH in depsgraph. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+}
+
+void SCULPT_dyntopo_node_layers_add(SculptSession *ss)
+{
+ int cd_node_layer_index;
+
+ char layer_id[] = "_dyntopo_node_id";
+
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->vdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id);
+ }
+
+ ss->cd_vert_node_offset = CustomData_get_n_offset(
+ &ss->bm->vdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT));
+
+ 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_INT, layer_id);
+ if (cd_node_layer_index == -1) {
+ BM_data_layer_add_named(ss->bm, &ss->bm->pdata, CD_PROP_INT, layer_id);
+ cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id);
+ }
+
+ ss->cd_face_node_offset = CustomData_get_n_offset(
+ &ss->bm->pdata,
+ CD_PROP_INT,
+ cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT));
+
+ ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY;
+}
+
+void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me);
+
+ SCULPT_pbvh_clear(ob);
+
+ ss->bm_smooth_shading = (scene->toolsettings->sculpt->flags & SCULPT_DYNTOPO_SMOOTH_SHADING) !=
+ 0;
+
+ /* Dynamic topology doesn't ensure selection state is valid, so remove [#36280]. */
+ BKE_mesh_mselect_clear(me);
+
+ /* Create triangles-only BMesh. */
+ ss->bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = false,
+ }));
+
+ BM_mesh_bm_from_me(ss->bm,
+ me,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ .use_shapekey = true,
+ .active_shapekey = ob->shapenr,
+ }));
+ SCULPT_dynamic_topology_triangulate(ss->bm);
+ BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
+ SCULPT_dyntopo_node_layers_add(ss);
+ /* Make sure the data for existing faces are initialized. */
+ if (me->totpoly != ss->bm->totface) {
+ BM_mesh_normals_update(ss->bm);
+ }
+
+ /* Enable dynamic topology. */
+ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Enable logging for undo/redo. */
+ ss->bm_log = BM_log_create(ss->bm);
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+/* Free the sculpt BMesh and BMLog
+ *
+ * If 'unode' is given, the BMesh's data is copied out to the unode
+ * before the BMesh is deleted so that it can be restored from. */
+static void SCULPT_dynamic_topology_disable_ex(
+ Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob, SculptUndoNode *unode)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *me = ob->data;
+
+ SCULPT_pbvh_clear(ob);
+
+ if (unode) {
+ /* Free all existing custom data. */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
+
+ /* Copy over stored custom data. */
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ me->totvert = geometry->totvert;
+ me->totloop = geometry->totloop;
+ me->totpoly = geometry->totpoly;
+ me->totedge = geometry->totedge;
+ me->totface = 0;
+ CustomData_copy(
+ &geometry->vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert);
+ CustomData_copy(
+ &geometry->edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge);
+ CustomData_copy(
+ &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);
+ }
+ ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ ss->face_sets[i] = 1;
+ }
+ 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;
+ me->mvert[i].flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+
+ /* Clear data. */
+ me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY;
+
+ /* Typically valid but with global-undo they can be NULL. [#36234] */
+ if (ss->bm) {
+ BM_mesh_free(ss->bm);
+ ss->bm = NULL;
+ }
+ if (ss->bm_log) {
+ BM_log_free(ss->bm_log);
+ ss->bm_log = NULL;
+ }
+
+ BKE_particlesystem_reset_all(ob);
+ BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_OUTDATED);
+
+ /* Update dependency graph, so modifiers that depend on dyntopo being enabled
+ * are re-evaluated and the PBVH is re-created. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
+}
+
+void SCULPT_dynamic_topology_disable(bContext *C, SculptUndoNode *unode)
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, unode);
+}
+
+void sculpt_dynamic_topology_disable_with_undo(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm) {
+ SCULPT_undo_push_begin("Dynamic topology disable");
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END);
+ SCULPT_dynamic_topology_disable_ex(bmain, depsgraph, scene, ob, NULL);
+ SCULPT_undo_push_end();
+ }
+}
+
+static void sculpt_dynamic_topology_enable_with_undo(Main *bmain,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ if (ss->bm == NULL) {
+ SCULPT_undo_push_begin("Dynamic topology enable");
+ SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob);
+ SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN);
+ SCULPT_undo_push_end();
+ }
+}
+
+static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Main *bmain = CTX_data_main(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ WM_cursor_wait(true);
+
+ if (ss->bm) {
+ sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob);
+ }
+ else {
+ sculpt_dynamic_topology_enable_with_undo(bmain, depsgraph, scene, ob);
+ }
+
+ WM_cursor_wait(false);
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag)
+{
+ uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR);
+ uiLayout *layout = UI_popup_menu_layout(pup);
+
+ if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) {
+ const char *msg_error = TIP_("Vertex Data Detected!");
+ const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ if (flag & DYNTOPO_WARN_MODIFIER) {
+ const char *msg_error = TIP_("Generative Modifiers Detected!");
+ const char *msg = TIP_(
+ "Keeping the modifiers will increase polycount when returning to object mode");
+
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, NULL);
+
+ UI_popup_menu_end(C, pup);
+
+ return OPERATOR_INTERFACE;
+}
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ SculptSession *ss = ob->sculpt;
+
+ enum eDynTopoWarnFlag flag = 0;
+
+ BLI_assert(ss->bm == NULL);
+ UNUSED_VARS_NDEBUG(ss);
+
+ for (int i = 0; i < CD_NUMTYPES; i++) {
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) {
+ if (CustomData_has_layer(&me->vdata, i)) {
+ flag |= DYNTOPO_WARN_VDATA;
+ }
+ if (CustomData_has_layer(&me->edata, i)) {
+ flag |= DYNTOPO_WARN_EDATA;
+ }
+ if (CustomData_has_layer(&me->ldata, i)) {
+ flag |= DYNTOPO_WARN_LDATA;
+ }
+ }
+ }
+
+ {
+ VirtualModifierData virtualModifierData;
+ ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
+
+ /* Exception for shape keys because we can edit those. */
+ for (; md; md = md->next) {
+ const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type);
+ if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
+ continue;
+ }
+
+ if (mti->type == eModifierTypeType_Constructive) {
+ flag |= DYNTOPO_WARN_MODIFIER;
+ break;
+ }
+ }
+ }
+
+ return flag;
+}
+
+static int sculpt_dynamic_topology_toggle_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ if (!ss->bm) {
+ Scene *scene = CTX_data_scene(C);
+ enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob);
+
+ if (flag) {
+ /* The mesh has customdata that will be lost, let the user confirm this is OK. */
+ return dyntopo_warning_popup(C, op->type, flag);
+ }
+ }
+
+ return sculpt_dynamic_topology_toggle_exec(C, op);
+}
+
+void SCULPT_OT_dynamic_topology_toggle(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Dynamic Topology Toggle";
+ ot->idname = "SCULPT_OT_dynamic_topology_toggle";
+ ot->description = "Dynamic topology alters the mesh topology while sculpting";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_dynamic_topology_toggle_invoke;
+ ot->exec = sculpt_dynamic_topology_toggle_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c
new file mode 100644
index 00000000000..cbdbab14690
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c
@@ -0,0 +1,980 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+/* Draw Face Sets Brush. */
+
+static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
+ MeshElemMap *vert_map = &ss->pmap[vd.index];
+ for (int j = 0; j < ss->pmap[vd.index].count; j++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[j]];
+
+ float poly_center[3];
+ BKE_mesh_calc_poly_center(p, &ss->mloop[p->loopstart], ss->mvert, poly_center);
+
+ if (sculpt_brush_test_sq_fn(&test, poly_center)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) {
+ ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set);
+ }
+ }
+ }
+ }
+
+ else if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ if (fade > 0.05f) {
+ SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set);
+ }
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ float bstrength = ss->cache->bstrength;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const bool relax_face_sets = !(ss->cache->iteration_count % 3 == 0);
+ /* This operations needs a stregth tweak as the relax deformation is too weak by default. */
+ if (relax_face_sets) {
+ bstrength *= 2.0f;
+ }
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ if (relax_face_sets != SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ vd.mask ? *vd.mask : 0.0f,
+ vd.index,
+ thread_id);
+
+ SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ BKE_curvemapping_initialize(brush->curve);
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ if (ss->cache->alt_smooth) {
+ for (int i = 0; i < 4; i++) {
+ BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings);
+ }
+ }
+ else {
+ BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings);
+ }
+}
+
+/* Face Sets Operators */
+
+typedef enum eSculptFaceGroupsCreateModes {
+ SCULPT_FACE_SET_MASKED = 0,
+ SCULPT_FACE_SET_VISIBLE = 1,
+ SCULPT_FACE_SET_ALL = 2,
+ SCULPT_FACE_SET_SELECTION = 3,
+} eSculptFaceGroupsCreateModes;
+
+static EnumPropertyItem prop_sculpt_face_set_create_types[] = {
+ {
+ SCULPT_FACE_SET_MASKED,
+ "MASKED",
+ 0,
+ "Face Set From Masked",
+ "Create a new Face Set from the masked faces",
+ },
+ {
+ SCULPT_FACE_SET_VISIBLE,
+ "VISIBLE",
+ 0,
+ "Face Set From Visible",
+ "Create a new Face Set from the visible vertices",
+ },
+ {
+ SCULPT_FACE_SET_ALL,
+ "ALL",
+ 0,
+ "Face Set Full Mesh",
+ "Create an unique Face Set with all faces in the sculpt",
+ },
+ {
+ SCULPT_FACE_SET_SELECTION,
+ "SELECTION",
+ 0,
+ "Face Set From Edit Mode Selection",
+ "Create an Face Set corresponding to the Edit Mode face selection",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_face_set_create_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* Dyntopo not suported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, mode == SCULPT_FACE_SET_MASKED);
+
+ const int tot_vert = SCULPT_vertex_count_get(ss);
+ float threshold = 0.5f;
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (!nodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("face set change");
+ 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);
+ }
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBLE) {
+
+ /* If all vertices in the sculpt are visible, create the new face set and update the default
+ * color. This way the new face set will be white, which is a quick way of disabling all face
+ * 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)) {
+ all_visible = false;
+ break;
+ }
+ }
+
+ if (all_visible) {
+ Mesh *mesh = ob->data;
+ mesh->face_sets_color_default = next_face_set;
+ BKE_pbvh_face_sets_color_set(
+ ss->pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
+ }
+
+ 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);
+ }
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_ALL) {
+ for (int i = 0; i < tot_vert; i++) {
+ SCULPT_vertex_face_set_set(ss, i, next_face_set);
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_SELECTION) {
+ Mesh *mesh = ob->data;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BMIter iter;
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ ss->face_sets[BM_elem_index_get(f)] = next_face_set;
+ }
+ }
+ BM_mesh_free(bm);
+ }
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_redraw(nodes[i]);
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Face Set";
+ ot->idname = "SCULPT_OT_face_sets_create";
+ ot->description = "Create a new Face Set";
+
+ /* api callbacks */
+ ot->exec = sculpt_face_set_create_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(
+ ot->srna, "mode", prop_sculpt_face_set_create_types, SCULPT_FACE_SET_MASKED, "Mode", "");
+}
+
+typedef enum eSculptFaceSetsInitMode {
+ SCULPT_FACE_SETS_FROM_LOOSE_PARTS = 0,
+ SCULPT_FACE_SETS_FROM_MATERIALS = 1,
+ SCULPT_FACE_SETS_FROM_NORMALS = 2,
+ SCULPT_FACE_SETS_FROM_UV_SEAMS = 3,
+ SCULPT_FACE_SETS_FROM_CREASES = 4,
+ SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5,
+ SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6,
+ SCULPT_FACE_SETS_FROM_FACE_MAPS = 7,
+} eSculptFaceSetsInitMode;
+
+static EnumPropertyItem prop_sculpt_face_sets_init_types[] = {
+ {
+ SCULPT_FACE_SETS_FROM_LOOSE_PARTS,
+ "LOOSE_PARTS",
+ 0,
+ "Face Sets From Loose Parts",
+ "Create a Face Set per loose part in the mesh",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_MATERIALS,
+ "MATERIALS",
+ 0,
+ "Face Sets From Material Slots",
+ "Create a Face Set per Material Slot",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_NORMALS,
+ "NORMALS",
+ 0,
+ "Face Sets From Mesh Normals",
+ "Create Face Sets for Faces that have similar normal",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_UV_SEAMS,
+ "UV_SEAMS",
+ 0,
+ "Face Sets From UV Seams",
+ "Create Face Sets using UV Seams as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_CREASES,
+ "CREASES",
+ 0,
+ "Face Sets From Edge Creases",
+ "Create Face Sets using Edge Creases as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT,
+ "BEVEL_WEIGHT",
+ 0,
+ "Face Sets From Bevel Weight",
+ "Create Face Sets using Bevel Weights as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_SHARP_EDGES,
+ "SHARP_EDGES",
+ 0,
+ "Face Sets From Sharp Edges",
+ "Create Face Sets using Sharp Edges as boundaries",
+ },
+ {
+ SCULPT_FACE_SETS_FROM_FACE_MAPS,
+ "FACE_MAPS",
+ 0,
+ "Face Sets From Face Maps",
+ "Create a Face Set per Face Map",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef bool (*face_sets_flood_fill_test)(
+ BMesh *bm, BMFace *from_f, BMEdge *from_e, BMFace *to_f, const float threshold);
+
+static bool sculpt_face_sets_init_loose_parts_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *UNUSED(from_e),
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return true;
+}
+
+static bool sculpt_face_sets_init_normals_test(
+ BMesh *UNUSED(bm), BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float threshold)
+{
+ return fabsf(dot_v3v3(from_f->no, to_f->no)) > threshold;
+}
+
+static bool sculpt_face_sets_init_uv_seams_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *from_e,
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return !BM_elem_flag_test(from_e, BM_ELEM_SEAM);
+}
+
+static bool sculpt_face_sets_init_crease_test(
+ BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
+{
+ return BM_elem_float_data_get(&bm->edata, from_e, CD_CREASE) < threshold;
+}
+
+static bool sculpt_face_sets_init_bevel_weight_test(
+ BMesh *bm, BMFace *UNUSED(from_f), BMEdge *from_e, BMFace *UNUSED(to_f), const float threshold)
+{
+ return BM_elem_float_data_get(&bm->edata, from_e, CD_BWEIGHT) < threshold;
+}
+
+static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm),
+ BMFace *UNUSED(from_f),
+ BMEdge *from_e,
+ BMFace *UNUSED(to_f),
+ const float UNUSED(threshold))
+{
+ return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH);
+}
+
+static void sculpt_face_sets_init_flood_fill(Object *ob,
+ face_sets_flood_fill_test test,
+ const float threshold)
+{
+ SculptSession *ss = ob->sculpt;
+ Mesh *mesh = ob->data;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+
+ BLI_bitmap *visited_faces = BLI_BITMAP_NEW(mesh->totpoly, "visited faces");
+ const int totfaces = mesh->totpoly;
+
+ int *face_sets = ss->face_sets;
+
+ BM_mesh_elem_table_init(bm, BM_FACE);
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ int next_face_set = 1;
+
+ for (int i = 0; i < totfaces; i++) {
+ if (!BLI_BITMAP_TEST(visited_faces, i)) {
+ GSQueue *queue;
+ queue = BLI_gsqueue_new(sizeof(int));
+
+ face_sets[i] = next_face_set;
+ BLI_BITMAP_ENABLE(visited_faces, i);
+ BLI_gsqueue_push(queue, &i);
+
+ while (!BLI_gsqueue_is_empty(queue)) {
+ int from_f;
+ BLI_gsqueue_pop(queue, &from_f);
+
+ BMFace *f, *f_neighbor;
+ BMEdge *ed;
+ BMIter iter_a, iter_b;
+
+ f = BM_face_at_index(bm, from_f);
+
+ BM_ITER_ELEM (ed, &iter_a, f, BM_EDGES_OF_FACE) {
+ BM_ITER_ELEM (f_neighbor, &iter_b, ed, BM_FACES_OF_EDGE) {
+ if (f_neighbor != f) {
+ int neighbor_face_index = BM_elem_index_get(f_neighbor);
+ if (!BLI_BITMAP_TEST(visited_faces, neighbor_face_index)) {
+ if (test(bm, f, ed, f_neighbor, threshold)) {
+ face_sets[neighbor_face_index] = next_face_set;
+ BLI_BITMAP_ENABLE(visited_faces, neighbor_face_index);
+ BLI_gsqueue_push(queue, &neighbor_face_index);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ next_face_set += 1;
+
+ BLI_gsqueue_free(queue);
+ }
+ }
+
+ MEM_SAFE_FREE(visited_faces);
+
+ BM_mesh_free(bm);
+}
+
+static void sculpt_face_sets_init_loop(Object *ob, const int mode)
+{
+ Mesh *mesh = ob->data;
+ SculptSession *ss = ob->sculpt;
+ BMesh *bm;
+ const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+ bm = BM_mesh_create(&allocsize,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ BM_mesh_bm_from_me(bm,
+ mesh,
+ (&(struct BMeshFromMeshParams){
+ .calc_face_normal = true,
+ }));
+ BMIter iter;
+ BMFace *f;
+
+ const int cd_fmaps_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (mode == SCULPT_FACE_SETS_FROM_MATERIALS) {
+ ss->face_sets[BM_elem_index_get(f)] = (int)(f->mat_nr + 1);
+ }
+ else if (mode == SCULPT_FACE_SETS_FROM_FACE_MAPS) {
+ if (cd_fmaps_offset != -1) {
+ ss->face_sets[BM_elem_index_get(f)] = BM_ELEM_CD_GET_INT(f, cd_fmaps_offset) + 2;
+ }
+ else {
+ ss->face_sets[BM_elem_index_get(f)] = 1;
+ }
+ }
+ }
+ BM_mesh_free(bm);
+}
+
+static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ const int mode = RNA_enum_get(op->ptr, "mode");
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (!nodes) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("face set change");
+ SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+ const float threshold = RNA_float_get(op->ptr, "threshold");
+
+ switch (mode) {
+ case SCULPT_FACE_SETS_FROM_LOOSE_PARTS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_loose_parts_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_MATERIALS:
+ sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_MATERIALS);
+ break;
+ case SCULPT_FACE_SETS_FROM_NORMALS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_normals_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_UV_SEAMS:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_uv_seams_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_CREASES:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_crease_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_SHARP_EDGES:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_sharp_edges_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT:
+ sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold);
+ break;
+ case SCULPT_FACE_SETS_FROM_FACE_MAPS:
+ sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS);
+ break;
+ }
+
+ SCULPT_undo_push_end();
+
+ /* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
+ SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_update_visibility(nodes[i]);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
+
+ MEM_SAFE_FREE(nodes);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
+ BKE_mesh_flush_hidden_from_verts(ob->data);
+ }
+
+ ED_region_tag_redraw(region);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_init(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Init Face Sets";
+ ot->idname = "SCULPT_OT_face_sets_init";
+ ot->description = "Initializes all Face Sets in the mesh";
+
+ /* api callbacks */
+ ot->exec = sculpt_face_set_init_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(
+ ot->srna, "mode", prop_sculpt_face_sets_init_types, SCULPT_FACE_SET_MASKED, "Mode", "");
+ RNA_def_float(
+ ot->srna,
+ "threshold",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Threshold",
+ "Minimum value to consider a certain attribute a boundary when creating the Face Sets",
+ 0.0f,
+ 1.0f);
+}
+
+typedef enum eSculptFaceGroupVisibilityModes {
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE = 0,
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE = 1,
+ SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE = 2,
+ SCULPT_FACE_SET_VISIBILITY_INVERT = 3,
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ALL = 4,
+} eSculptFaceGroupVisibilityModes;
+
+static EnumPropertyItem prop_sculpt_face_sets_change_visibility_types[] = {
+ {
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE,
+ "TOGGLE",
+ 0,
+ "Toggle Visibility",
+ "Hide all Face Sets except for the active one",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE,
+ "SHOW_ACTIVE",
+ 0,
+ "Show Active Face Set",
+ "Show Active Face Set",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE,
+ "HIDE_ACTIVE",
+ 0,
+ "Hide Active Face Sets",
+ "Hide Active Face Sets",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_INVERT,
+ "INVERT",
+ 0,
+ "Invert Face Set Visibility",
+ "Invert Face Set Visibility",
+ },
+ {
+ SCULPT_FACE_SET_VISIBILITY_SHOW_ALL,
+ "SHOW_ALL",
+ 0,
+ "Show All Face Sets",
+ "Show All Face Sets",
+ },
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_face_sets_change_visibility_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ const int tot_vert = SCULPT_vertex_count_get(ss);
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ const int active_face_set = SCULPT_active_face_set_get(ss);
+
+ SCULPT_undo_push_begin("Hide area");
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+
+ if (totnode == 0) {
+ MEM_SAFE_FREE(nodes);
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_TOGGLE) {
+ bool hidden_vertex = false;
+
+ /* This can fail with regular meshes with non-manifold geometry as the visibility state can't
+ * 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)) {
+ hidden_vertex = true;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < ss->totfaces; i++) {
+ if (ss->face_sets[i] <= 0) {
+ hidden_vertex = true;
+ break;
+ }
+ }
+
+ if (hidden_vertex) {
+ SCULPT_face_sets_visibility_all_set(ss, true);
+ }
+ else {
+ SCULPT_face_sets_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ALL) {
+ SCULPT_face_sets_visibility_all_set(ss, true);
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE) {
+ SCULPT_face_sets_visibility_all_set(ss, false);
+ SCULPT_face_set_visibility_set(ss, active_face_set, true);
+ for (int i = 0; i < tot_vert; i++) {
+ SCULPT_vertex_visible_set(ss,
+ i,
+ SCULPT_vertex_visible_get(ss, i) &&
+ SCULPT_vertex_has_face_set(ss, i, active_face_set));
+ }
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_HIDE_ACTIVE) {
+ SCULPT_face_set_visibility_set(ss, active_face_set, false);
+ }
+
+ if (mode == SCULPT_FACE_SET_VISIBILITY_INVERT) {
+ SCULPT_face_sets_visibility_invert(ss);
+ }
+
+ /* For modes that use the cursor active vertex, update the rotation origin for viewport
+ * navigation. */
+ if (ELEM(mode, SCULPT_FACE_SET_VISIBILITY_TOGGLE, SCULPT_FACE_SET_VISIBILITY_SHOW_ACTIVE)) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ float location[3];
+ copy_v3_v3(location, SCULPT_active_vertex_co_get(ss));
+ mul_m4_v3(ob->obmat, location);
+ copy_v3_v3(ups->average_stroke_accum, location);
+ ups->average_stroke_counter = 1;
+ ups->last_stroke_valid = true;
+ }
+
+ /* Sync face sets visibility and vertex visibility. */
+ SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
+ SCULPT_undo_push_end();
+
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_update_visibility(nodes[i]);
+ }
+
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
+
+ MEM_SAFE_FREE(nodes);
+
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
+ BKE_mesh_flush_hidden_from_verts(ob->data);
+ }
+
+ ED_region_tag_redraw(region);
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Face Sets Visibility";
+ ot->idname = "SCULPT_OT_face_set_change_visibility";
+ ot->description = "Change the visibility of the Face Sets of the sculpt";
+
+ /* Api callbacks. */
+ ot->exec = sculpt_face_sets_change_visibility_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_face_sets_change_visibility_types,
+ SCULPT_FACE_SET_VISIBILITY_TOGGLE,
+ "Mode",
+ "");
+}
+
+static int sculpt_face_sets_randomize_colors_exec(bContext *C, wmOperator *UNUSED(op))
+{
+
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+
+ /* Dyntopo not supported. */
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
+ return OPERATOR_CANCELLED;
+ }
+
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ int totnode;
+ Mesh *mesh = ob->data;
+
+ mesh->face_sets_color_seed += 1;
+ if (ss->face_sets) {
+ const int random_index = clamp_i(ss->totfaces * BLI_hash_int_01(mesh->face_sets_color_seed),
+ 0,
+ max_ii(0, ss->totfaces - 1));
+ mesh->face_sets_color_default = ss->face_sets[random_index];
+ }
+ BKE_pbvh_face_sets_color_set(pbvh, mesh->face_sets_color_seed, mesh->face_sets_color_default);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ for (int i = 0; i < totnode; i++) {
+ BKE_pbvh_node_mark_redraw(nodes[i]);
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ View3D *v3d = CTX_wm_view3d(C);
+ if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
+ }
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Randomize Face Sets Colors";
+ ot->idname = "SCULPT_OT_face_sets_randomize_colors";
+ ot->description = "Generates a new set of random colors to render the Face Sets in the viewport";
+
+ /* Api callbacks. */
+ ot->exec = sculpt_face_sets_randomize_colors_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
new file mode 100644
index 00000000000..d2a683461a7
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c
@@ -0,0 +1,502 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+typedef enum eSculptMaskFilterTypes {
+ MASK_FILTER_SMOOTH = 0,
+ MASK_FILTER_SHARPEN = 1,
+ MASK_FILTER_GROW = 2,
+ MASK_FILTER_SHRINK = 3,
+ MASK_FILTER_CONTRAST_INCREASE = 5,
+ MASK_FILTER_CONTRAST_DECREASE = 6,
+} eSculptMaskFilterTypes;
+
+static EnumPropertyItem prop_mask_filter_types[] = {
+ {MASK_FILTER_SMOOTH, "SMOOTH", 0, "Smooth Mask", "Smooth mask"},
+ {MASK_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen Mask", "Sharpen mask"},
+ {MASK_FILTER_GROW, "GROW", 0, "Grow Mask", "Grow mask"},
+ {MASK_FILTER_SHRINK, "SHRINK", 0, "Shrink Mask", "Shrink mask"},
+ {MASK_FILTER_CONTRAST_INCREASE,
+ "CONTRAST_INCREASE",
+ 0,
+ "Increase contrast",
+ "Increase the contrast of the paint mask"},
+ {MASK_FILTER_CONTRAST_DECREASE,
+ "CONTRAST_DECREASE",
+ 0,
+ "Decrease contrast",
+ "Decrease the contrast of the paint mask"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static void mask_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ bool update = false;
+
+ const int mode = data->filter_type;
+ float contrast = 0.0f;
+
+ PBVHVertexIter vd;
+
+ if (mode == MASK_FILTER_CONTRAST_INCREASE) {
+ contrast = 0.1f;
+ }
+
+ if (mode == MASK_FILTER_CONTRAST_DECREASE) {
+ contrast = -0.1f;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float delta, gain, offset, max, min;
+ float prev_val = *vd.mask;
+ SculptVertexNeighborIter ni;
+ switch (mode) {
+ case MASK_FILTER_SMOOTH:
+ case MASK_FILTER_SHARPEN: {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index);
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
+ }
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2.0f;
+ }
+ break;
+ }
+ case MASK_FILTER_GROW:
+ max = 0.0f;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ *vd.mask = max;
+ break;
+ case MASK_FILTER_SHRINK:
+ min = 1.0f;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f < min) {
+ min = vmask_f;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ *vd.mask = min;
+ break;
+ case MASK_FILTER_CONTRAST_INCREASE:
+ case MASK_FILTER_CONTRAST_DECREASE:
+ delta = contrast / 2.0f;
+ gain = 1.0f - delta * 2.0f;
+ if (contrast > 0) {
+ gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON);
+ offset = gain * (-delta);
+ }
+ else {
+ delta *= -1.0f;
+ offset = gain * (delta);
+ }
+ *vd.mask = gain * (*vd.mask) + offset;
+ break;
+ }
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ if (*vd.mask != prev_val) {
+ update = true;
+ }
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ if (update) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+}
+
+static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
+{
+ ARegion *region = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+ int filter_type = RNA_enum_get(op->ptr, "filter_type");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ int num_verts = SCULPT_vertex_count_get(ss);
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SCULPT_undo_push_begin("Mask filter");
+
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ float *prev_mask = NULL;
+ int iterations = RNA_int_get(op->ptr, "iterations");
+
+ /* Auto iteration count calculates the number of iteration based on the vertices of the mesh to
+ * avoid adding an unnecessary amount of undo steps when using the operator from a shortcut.
+ * One iteration per 50000 vertices in the mesh should be fine in most cases.
+ * Maybe we want this to be configurable. */
+ if (RNA_boolean_get(op->ptr, "auto_iteration_count")) {
+ iterations = (int)(num_verts / 50000.0f) + 1;
+ }
+
+ for (int i = 0; i < iterations; i++) {
+ 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);
+ }
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = filter_type,
+ .prev_mask = prev_mask,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+
+ if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) {
+ MEM_freeN(prev_mask);
+ }
+ }
+
+ MEM_SAFE_FREE(nodes);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations)
+{
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .filter_type = MASK_FILTER_SMOOTH,
+ };
+
+ for (int i = 0; i < smooth_iterations; i++) {
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ }
+}
+
+void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Mask Filter";
+ ot->idname = "SCULPT_OT_mask_filter";
+ ot->description = "Applies a filter to modify the current mask";
+
+ /* API callbacks. */
+ ot->exec = sculpt_mask_filter_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "filter_type",
+ prop_mask_filter_types,
+ MASK_FILTER_SMOOTH,
+ "Type",
+ "Filter that is going to be applied to the mask");
+ RNA_def_int(ot->srna,
+ "iterations",
+ 1,
+ 1,
+ 100,
+ "Iterations",
+ "Number of times that the filter is going to be applied",
+ 1,
+ 100);
+ RNA_def_boolean(
+ ot->srna,
+ "auto_iteration_count",
+ false,
+ "Auto Iteration Count",
+ "Use a automatic number of iterations based on the number of vertices of the sculpt");
+}
+
+static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd)
+{
+ int total = 0;
+ float avg[3];
+ zero_v3(avg);
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) {
+ float normalized[3];
+ sub_v3_v3v3(normalized, SCULPT_vertex_co_get(ss, ni.index), vd->co);
+ normalize_v3(normalized);
+ add_v3_v3(avg, normalized);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ float normal[3];
+ if (vd->no) {
+ normal_short_to_float_v3(normal, vd->no);
+ }
+ else {
+ copy_v3_v3(normal, vd->fno);
+ }
+ float dot = dot_v3v3(avg, normal);
+ float angle = max_ff(saacosf(dot), 0.0f);
+ return angle;
+ }
+ return 0.0f;
+}
+
+typedef struct DirtyMaskRangeData {
+ float min, max;
+} DirtyMaskRangeData;
+
+static void dirty_mask_compute_range_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ DirtyMaskRangeData *range = tls->userdata_chunk;
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ range->min = min_ff(dirty_mask, range->min);
+ range->max = max_ff(dirty_mask, range->max);
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ DirtyMaskRangeData *join = chunk_join;
+ DirtyMaskRangeData *range = chunk;
+ join->min = min_ff(range->min, join->min);
+ join->max = max_ff(range->max, join->max);
+}
+
+static void dirty_mask_apply_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+
+ const bool dirty_only = data->dirty_mask_dirty_only;
+ const float min = data->dirty_mask_min;
+ const float max = data->dirty_mask_max;
+
+ float range = max - min;
+ if (range < 0.0001f) {
+ range = 0.0f;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ float mask = *vd.mask + (1.0f - ((dirty_mask - min) * range));
+ if (dirty_only) {
+ mask = fminf(mask, 0.5f) * 2.0f;
+ }
+ *vd.mask = CLAMPIS(mask, 0.0f, 1.0f);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ BKE_pbvh_node_mark_update_mask(node);
+}
+
+static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
+{
+ ARegion *region = CTX_wm_region(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PBVH *pbvh = ob->sculpt->pbvh;
+ PBVHNode **nodes;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int totnode;
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ SCULPT_vertex_random_access_init(ss);
+
+ if (!ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SCULPT_undo_push_begin("Dirty Mask");
+
+ for (int i = 0; i < totnode; i++) {
+ SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ settings.func_reduce = dirty_mask_compute_range_reduce;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
+
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings);
+ data.dirty_mask_min = range.min;
+ data.dirty_mask_max = range.max;
+ BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings);
+
+ MEM_SAFE_FREE(nodes);
+
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
+ SCULPT_undo_push_end();
+
+ ED_region_tag_redraw(region);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Dirty Mask";
+ ot->idname = "SCULPT_OT_dirty_mask";
+ ot->description = "Generates a mask based on the geometry cavity and pointiness";
+
+ /* API callbacks. */
+ ot->exec = sculpt_dirty_mask_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER;
+
+ /* RNA. */
+ RNA_def_boolean(
+ ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
new file mode 100644
index 00000000000..fd0f67f040a
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c
@@ -0,0 +1,660 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+static void filter_cache_init_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ PBVHNode *node = data->nodes[i];
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+}
+
+void SCULPT_filter_cache_init(Object *ob, Sculpt *sd)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ ss->filter_cache->random_seed = rand();
+
+ float center[3] = {0.0f};
+ SculptSearchSphereData search_data = {
+ .original = true,
+ .center = center,
+ .radius_squared = FLT_MAX,
+ .ignore_fully_masked = true,
+
+ };
+ BKE_pbvh_search_gather(pbvh,
+ SCULPT_search_sphere_cb,
+ &search_data,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_normals_update(ss->filter_cache->nodes[i]);
+ }
+
+ /* mesh->runtime.subdiv_ccg is not available. Updating of the normals is done during drawing.
+ * Filters can't use normals in multires. */
+ if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
+ BKE_pbvh_update_normals(ss->pbvh, NULL);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings);
+}
+
+void SCULPT_filter_cache_free(SculptSession *ss)
+{
+ if (ss->filter_cache->cloth_sim) {
+ SCULPT_cloth_simulation_free(ss->filter_cache->cloth_sim);
+ }
+ MEM_SAFE_FREE(ss->filter_cache->nodes);
+ MEM_SAFE_FREE(ss->filter_cache->mask_update_it);
+ MEM_SAFE_FREE(ss->filter_cache->prev_mask);
+ MEM_SAFE_FREE(ss->filter_cache->normal_factor);
+ MEM_SAFE_FREE(ss->filter_cache->prev_face_set);
+ MEM_SAFE_FREE(ss->filter_cache->automask);
+ MEM_SAFE_FREE(ss->filter_cache->surface_smooth_laplacian_disp);
+ MEM_SAFE_FREE(ss->filter_cache->sharpen_factor);
+ MEM_SAFE_FREE(ss->filter_cache);
+}
+
+typedef enum eSculptMeshFilterTypes {
+ MESH_FILTER_SMOOTH = 0,
+ MESH_FILTER_SCALE = 1,
+ MESH_FILTER_INFLATE = 2,
+ MESH_FILTER_SPHERE = 3,
+ MESH_FILTER_RANDOM = 4,
+ MESH_FILTER_RELAX = 5,
+ MESH_FILTER_RELAX_FACE_SETS = 6,
+ MESH_FILTER_SURFACE_SMOOTH = 7,
+ MESH_FILTER_SHARPEN = 8,
+} eSculptMeshFilterTypes;
+
+static EnumPropertyItem prop_mesh_filter_types[] = {
+ {MESH_FILTER_SMOOTH, "SMOOTH", 0, "Smooth", "Smooth mesh"},
+ {MESH_FILTER_SCALE, "SCALE", 0, "Scale", "Scale mesh"},
+ {MESH_FILTER_INFLATE, "INFLATE", 0, "Inflate", "Inflate mesh"},
+ {MESH_FILTER_SPHERE, "SPHERE", 0, "Sphere", "Morph into sphere"},
+ {MESH_FILTER_RANDOM, "RANDOM", 0, "Random", "Randomize vertex positions"},
+ {MESH_FILTER_RELAX, "RELAX", 0, "Relax", "Relax mesh"},
+ {MESH_FILTER_RELAX_FACE_SETS,
+ "RELAX_FACE_SETS",
+ 0,
+ "Relax Face Sets",
+ "Smooth the edges of all the Face Sets"},
+ {MESH_FILTER_SURFACE_SMOOTH,
+ "SURFACE_SMOOTH",
+ 0,
+ "Surface Smooth",
+ "Smooth the surface of the mesh, preserving the volume"},
+ {MESH_FILTER_SHARPEN, "SHARPEN", 0, "Sharpen", "Sharpen the cavities of the mesh"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+typedef enum eMeshFilterDeformAxis {
+ MESH_FILTER_DEFORM_X = 1 << 0,
+ MESH_FILTER_DEFORM_Y = 1 << 1,
+ MESH_FILTER_DEFORM_Z = 1 << 2,
+} eMeshFilterDeformAxis;
+
+static EnumPropertyItem prop_mesh_filter_deform_axis_items[] = {
+ {MESH_FILTER_DEFORM_X, "X", 0, "X", "Deform in the X axis"},
+ {MESH_FILTER_DEFORM_Y, "Y", 0, "Y", "Deform in the Y axis"},
+ {MESH_FILTER_DEFORM_Z, "Z", 0, "Z", "Deform in the Z axis"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static bool sculpt_mesh_filter_needs_pmap(int filter_type, bool use_face_sets)
+{
+ return use_face_sets || ELEM(filter_type,
+ MESH_FILTER_SMOOTH,
+ MESH_FILTER_RELAX,
+ MESH_FILTER_RELAX_FACE_SETS,
+ MESH_FILTER_SURFACE_SMOOTH,
+ MESH_FILTER_SHARPEN);
+}
+
+static void mesh_filter_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ const int filter_type = data->filter_type;
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ /* When using the relax face sets meshes filter,
+ * each 3 iterations, do a whole mesh relax to smooth the contents of the Face Set. */
+ /* This produces better results as the relax operation is no completely focused on the
+ * boundaries. */
+ const bool relax_face_sets = !(ss->filter_cache->iteration_count % 3 == 0);
+
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ fade *= data->filter_strength;
+
+ if (fade == 0.0f) {
+ continue;
+ }
+
+ 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)) {
+ /* Surface Smooth can't skip the loop for this vertex as it needs to calculate its
+ * laplacian_disp. This value is accessed from the vertex neighbors when deforming the
+ * vertices, so it is needed for all vertices even if they are not going to be displaced.
+ */
+ if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
+ fade = 0.0f;
+ }
+ else {
+ continue;
+ }
+ }
+ /* Skip the edges of the face set when relaxing or smoothing.
+ * There is a relax face set option to relax the boundaries independently. */
+ if (filter_type == MESH_FILTER_RELAX) {
+ if (!SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ continue;
+ }
+ }
+ }
+
+ if (ELEM(filter_type, MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
+ copy_v3_v3(orig_co, vd.co);
+ }
+ else {
+ copy_v3_v3(orig_co, orig_data.co);
+ }
+
+ if (filter_type == MESH_FILTER_RELAX_FACE_SETS) {
+ if (relax_face_sets == SCULPT_vertex_has_unique_face_set(ss, vd.index)) {
+ continue;
+ }
+ }
+
+ switch (filter_type) {
+ case MESH_FILTER_SMOOTH:
+ CLAMP(fade, -1.0f, 1.0f);
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ SCULPT_neighbor_average(ss, avg, vd.index);
+ break;
+ case PBVH_BMESH:
+ SCULPT_bmesh_neighbor_average(avg, vd.bm_vert);
+ break;
+ case PBVH_GRIDS:
+ SCULPT_neighbor_coords_average(ss, avg, vd.index);
+ break;
+ }
+ sub_v3_v3v3(val, avg, orig_co);
+ madd_v3_v3v3fl(val, orig_co, val, fade);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_INFLATE:
+ normal_short_to_float_v3(normal, orig_data.no);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ case MESH_FILTER_SCALE:
+ unit_m3(transform);
+ scale_m3_fl(transform, 1.0f + fade);
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp, val, orig_co);
+ break;
+ case MESH_FILTER_SPHERE:
+ normalize_v3_v3(disp, orig_co);
+ if (fade > 0.0f) {
+ mul_v3_v3fl(disp, disp, fade);
+ }
+ else {
+ mul_v3_v3fl(disp, disp, -fade);
+ }
+
+ unit_m3(transform);
+ if (fade > 0.0f) {
+ scale_m3_fl(transform, 1.0f - fade);
+ }
+ else {
+ scale_m3_fl(transform, 1.0f + fade);
+ }
+ copy_v3_v3(val, orig_co);
+ mul_m3_v3(transform, val);
+ sub_v3_v3v3(disp2, val, orig_co);
+
+ mid_v3_v3v3(disp, disp, disp2);
+ break;
+ case MESH_FILTER_RANDOM: {
+ normal_short_to_float_v3(normal, orig_data.no);
+ /* Index is not unique for multires, so hash by vertex coordinates. */
+ const uint *hash_co = (const uint *)orig_co;
+ const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^
+ BLI_hash_int_2d(hash_co[2], ss->filter_cache->random_seed);
+ mul_v3_fl(normal, hash * (1.0f / (float)0xFFFFFFFF) - 0.5f);
+ mul_v3_v3fl(disp, normal, fade);
+ break;
+ }
+ case MESH_FILTER_RELAX: {
+ SCULPT_relax_vertex(
+ ss, &vd, clamp_f(fade * ss->filter_cache->automask[vd.index], 0.0f, 1.0f), false, val);
+ sub_v3_v3v3(disp, val, vd.co);
+ break;
+ }
+ case MESH_FILTER_RELAX_FACE_SETS: {
+ SCULPT_relax_vertex(ss, &vd, clamp_f(fade, 0.0f, 1.0f), relax_face_sets, val);
+ sub_v3_v3v3(disp, val, vd.co);
+ break;
+ }
+ case MESH_FILTER_SURFACE_SMOOTH: {
+ SCULPT_surface_smooth_laplacian_step(ss,
+ disp,
+ vd.co,
+ ss->filter_cache->surface_smooth_laplacian_disp,
+ vd.index,
+ orig_data.co,
+ ss->filter_cache->surface_smooth_shape_preservation);
+ break;
+ }
+ case MESH_FILTER_SHARPEN: {
+ const float smooth_ratio = ss->filter_cache->sharpen_smooth_ratio;
+
+ /* This filter can't work at full strength as it needs multiple iterations to reach a
+ * stable state. */
+ fade = clamp_f(fade, 0.0f, 0.5f);
+ float disp_sharpen[3] = {0.0f, 0.0f, 0.0f};
+
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
+ float disp_n[3];
+ sub_v3_v3v3(
+ disp_n, SCULPT_vertex_co_get(ss, ni.index), SCULPT_vertex_co_get(ss, vd.index));
+ mul_v3_fl(disp_n, ss->filter_cache->sharpen_factor[ni.index]);
+ add_v3_v3(disp_sharpen, disp_n);
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ mul_v3_fl(disp_sharpen, 1.0f - ss->filter_cache->sharpen_factor[vd.index]);
+
+ float disp_avg[3];
+ float avg_co[3];
+ SCULPT_neighbor_coords_average(ss, avg_co, vd.index);
+ 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]));
+ add_v3_v3v3(disp, disp_avg, disp_sharpen);
+ break;
+ }
+ }
+
+ for (int it = 0; it < 3; it++) {
+ if (!ss->filter_cache->enabled_axis[it]) {
+ disp[it] = 0.0f;
+ }
+ }
+
+ if (ELEM(filter_type, MESH_FILTER_SURFACE_SMOOTH, MESH_FILTER_SHARPEN)) {
+ madd_v3_v3v3fl(final_pos, vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
+ }
+ else {
+ add_v3_v3v3(final_pos, orig_co, disp);
+ }
+ copy_v3_v3(vd.co, final_pos);
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+static void mesh_filter_sharpen_init_factors(SculptSession *ss)
+{
+ const int totvert = SCULPT_vertex_count_get(ss);
+ for (int i = 0; i < totvert; i++) {
+ float avg[3];
+ SCULPT_neighbor_coords_average(ss, avg, i);
+ ss->filter_cache->sharpen_factor[i] = len_v3v3(avg, SCULPT_vertex_co_get(ss, i));
+ }
+ float max_factor = 0.0f;
+ for (int i = 0; i < totvert; i++) {
+ if (ss->filter_cache->sharpen_factor[i] > max_factor) {
+ max_factor = ss->filter_cache->sharpen_factor[i];
+ }
+ }
+
+ max_factor = 1.0f / max_factor;
+ for (int i = 0; i < totvert; i++) {
+ ss->filter_cache->sharpen_factor[i] *= max_factor;
+ ss->filter_cache->sharpen_factor[i] = 1.0f - pow2f(1.0f - ss->filter_cache->sharpen_factor[i]);
+ }
+}
+
+static void mesh_filter_surface_smooth_displace_task_cb(
+ void *__restrict userdata, const int i, const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ fade = 1.0f - fade;
+ fade *= data->filter_strength;
+ if (fade == 0.0f) {
+ continue;
+ }
+
+ 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)) {
+ continue;
+ }
+ }
+
+ SCULPT_surface_smooth_displace_step(ss,
+ vd.co,
+ ss->filter_cache->surface_smooth_laplacian_disp,
+ vd.index,
+ ss->filter_cache->surface_smooth_current_vertex,
+ clamp_f(fade, 0.0f, 1.0f));
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ float filter_strength = RNA_float_get(op->ptr, "strength");
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ float len = event->prevclickx - event->mval[0];
+ filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC;
+
+ SCULPT_vertex_random_access_init(ss);
+
+ bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = filter_type,
+ .filter_strength = filter_strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+
+ if (filter_type == MESH_FILTER_SURFACE_SMOOTH) {
+ BLI_task_parallel_range(0,
+ ss->filter_cache->totnode,
+ &data,
+ mesh_filter_surface_smooth_displace_task_cb,
+ &settings);
+ }
+
+ ss->filter_cache->iteration_count++;
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+
+ /* The relax mesh filter needs the updated normals of the modified mesh after each iteration. */
+ if (ELEM(MESH_FILTER_RELAX, MESH_FILTER_RELAX_FACE_SETS)) {
+ BKE_pbvh_update_normals(ss->pbvh, ss->subdiv_ccg);
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ int filter_type = RNA_enum_get(op->ptr, "type");
+ SculptSession *ss = ob->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
+ if (deform_axis == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (RNA_boolean_get(op->ptr, "use_face_sets")) {
+ /* Update the active vertex */
+ float mouse[2];
+ SculptCursorGeometryInfo sgi;
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ }
+
+ const bool use_face_sets = RNA_boolean_get(op->ptr, "use_face_sets");
+
+ SCULPT_vertex_random_access_init(ss);
+
+ bool needs_pmap = sculpt_mesh_filter_needs_pmap(filter_type, use_face_sets);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, needs_pmap, false);
+
+ const int totvert = SCULPT_vertex_count_get(ss);
+ if (BKE_pbvh_type(pbvh) == PBVH_FACES && needs_pmap && !ob->sculpt->pmap) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SCULPT_undo_push_begin("Mesh filter");
+
+ SCULPT_filter_cache_init(ob, sd);
+
+ if (use_face_sets) {
+ ss->filter_cache->active_face_set = SCULPT_active_face_set_get(ss);
+ }
+ else {
+ ss->filter_cache->active_face_set = SCULPT_FACE_SET_NONE;
+ }
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SURFACE_SMOOTH) {
+ ss->filter_cache->surface_smooth_laplacian_disp = MEM_mallocN(3 * sizeof(float) * totvert,
+ "surface smooth disp");
+ ss->filter_cache->surface_smooth_shape_preservation = RNA_float_get(
+ op->ptr, "surface_smooth_shape_preservation");
+ ss->filter_cache->surface_smooth_current_vertex = RNA_float_get(
+ op->ptr, "surface_smooth_current_vertex");
+ }
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_SHARPEN) {
+ ss->filter_cache->sharpen_smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio");
+ ss->filter_cache->sharpen_factor = MEM_mallocN(sizeof(float) * totvert, "sharpen factor");
+
+ mesh_filter_sharpen_init_factors(ss);
+ }
+
+ ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X;
+ ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y;
+ ss->filter_cache->enabled_axis[2] = deform_axis & MESH_FILTER_DEFORM_Z;
+
+ if (RNA_enum_get(op->ptr, "type") == MESH_FILTER_RELAX) {
+ ss->filter_cache->automask = MEM_mallocN(totvert * sizeof(float),
+ "Relax filter edge automask");
+ for (int i = 0; i < totvert; i++) {
+ ss->filter_cache->automask[i] = 1.0f;
+ }
+ SCULPT_boundary_automasking_init(
+ ob, AUTOMASK_INIT_BOUNDARY_EDGES, 1, ss->filter_cache->automask);
+ }
+
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Filter mesh";
+ ot->idname = "SCULPT_OT_mesh_filter";
+ ot->description = "Applies a filter to modify the current mesh";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_mesh_filter_invoke;
+ ot->modal = sculpt_mesh_filter_modal;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* RNA. */
+ RNA_def_enum(ot->srna,
+ "type",
+ prop_mesh_filter_types,
+ MESH_FILTER_INFLATE,
+ "Filter type",
+ "Operation that is going to be applied to the mesh");
+ RNA_def_float(
+ ot->srna, "strength", 1.0f, -10.0f, 10.0f, "Strength", "Filter Strength", -10.0f, 10.0f);
+ RNA_def_enum_flag(ot->srna,
+ "deform_axis",
+ prop_mesh_filter_deform_axis_items,
+ MESH_FILTER_DEFORM_X | MESH_FILTER_DEFORM_Y | MESH_FILTER_DEFORM_Z,
+ "Deform axis",
+ "Apply the deformation in the selected axis");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_face_sets",
+ false,
+ "Use Face Sets",
+ "Apply the filter only to the Face Mask under the cursor");
+
+ /* Surface Smooth Mesh Filter properties. */
+ RNA_def_float(ot->srna,
+ "surface_smooth_shape_preservation",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Shape Preservation",
+ "How much of the original shape is preserved when smoothing",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "surface_smooth_current_vertex",
+ 0.5f,
+ 0.0f,
+ 1.0f,
+ "Per Vertex Displacement",
+ "How much the position of each individual vertex influences the final result",
+ 0.0f,
+ 1.0f);
+ RNA_def_float(ot->srna,
+ "sharpen_smooth_ratio",
+ 0.35f,
+ 0.0f,
+ 1.0f,
+ "Smooth Ratio",
+ "How much smoothing is applied to polished surfaces",
+ 0.0f,
+ 1.0f);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index d8e29d0e773..50808b04276 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
@@ -24,6 +24,7 @@
#ifndef __SCULPT_INTERN_H__
#define __SCULPT_INTERN_H__
+#include "DNA_brush_types.h"
#include "DNA_key_types.h"
#include "DNA_listBase.h"
#include "DNA_vec_types.h"
@@ -57,6 +58,10 @@ typedef enum SculptUpdateType {
SCULPT_UPDATE_VISIBILITY = 1 << 2,
} SculptUpdateType;
+void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags);
+void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags);
+void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used);
+
/* Stroke */
typedef struct SculptCursorGeometryInfo {
@@ -72,11 +77,20 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
bool use_sampled_normal);
void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush);
+float SCULPT_raycast_init(struct ViewContext *vc,
+ const float mouse[2],
+ float ray_start[3],
+ float ray_end[3],
+ float ray_normal[3],
+ bool original);
+
/* Sculpt PBVH abstraction API */
void SCULPT_vertex_random_access_init(struct SculptSession *ss);
int SCULPT_vertex_count_get(struct SculptSession *ss);
const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index);
+void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]);
float SCULPT_vertex_mask_get(struct SculptSession *ss, int index);
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
@@ -102,29 +116,61 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SculptVertexNeighborIter *iter);
/* Iterator over neighboring vertices. */
-#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
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 = ni.neighbors[ni.i];
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
* first since they are nearest for floodfill. */
-#define sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
+#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \
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 = ni.neighbors[ni.i]; \
- neighbor_iterator.is_duplicate = (ni.i >= \
+ neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \
+ neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
-#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
+#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \
} \
if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
MEM_freeN(neighbor_iterator.neighbors); \
} \
((void)0)
+int 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]);
+
+bool SCULPT_vertex_is_boundary(SculptSession *ss, const int index);
+
+/* 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_visibility_sync_all_face_sets_to_vertices(struct SculptSession *ss);
+void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
+
+/* Face Sets API */
+
+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);
+
+bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set);
+bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index);
+
+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(SculptSession *ss, int index);
+bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index);
+
+void SCULPT_face_sets_visibility_invert(SculptSession *ss);
+void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible);
+
/* Sculpt Original Data */
typedef struct {
struct BMLog *bm_log;
@@ -143,11 +189,6 @@ typedef struct {
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node);
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter);
-/* Dynamic topology */
-void sculpt_pbvh_clear(Object *ob);
-void sculpt_dyntopo_node_layers_add(struct SculptSession *ss);
-void sculpt_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
-
/* Utils. */
void SCULPT_calc_brush_plane(struct Sculpt *sd,
struct Object *ob,
@@ -169,11 +210,16 @@ int SCULPT_plane_point_side(const float co[3], const float plane[4]);
int SCULPT_plane_trim(const struct StrokeCache *cache,
const struct Brush *brush,
const float val[3]);
+void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]);
float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss);
ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]);
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm);
+bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3],
+ const float br_co[3],
+ float radius,
+ char symm);
bool SCULPT_is_symmetry_iteration_valid(char i, char symm);
void SCULPT_flip_v3_by_symm_area(float v[3],
const ePaintSymmetryFlags symm,
@@ -187,7 +233,7 @@ void SCULPT_flip_quat_by_symm_area(float quat[3],
/* Flood Fill. */
typedef struct {
GSQueue *queue;
- char *visited_vertices;
+ BLI_bitmap *visited_vertices;
} SculptFloodFill;
void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood);
@@ -196,6 +242,13 @@ void SCULPT_floodfill_add_active(struct Sculpt *sd,
struct SculptSession *ss,
SculptFloodFill *flood,
float radius);
+void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ SculptFloodFill *flood,
+ int index,
+ float radius);
+void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index);
void SCULPT_floodfill_execute(
struct SculptSession *ss,
SculptFloodFill *flood,
@@ -203,9 +256,61 @@ void SCULPT_floodfill_execute(
void *userdata);
void SCULPT_floodfill_free(SculptFloodFill *flood);
+/* Dynamic topology */
+
+enum eDynTopoWarnFlag {
+ DYNTOPO_WARN_VDATA = (1 << 0),
+ DYNTOPO_WARN_EDATA = (1 << 1),
+ DYNTOPO_WARN_LDATA = (1 << 2),
+ DYNTOPO_WARN_MODIFIER = (1 << 3),
+};
+
+void SCULPT_dynamic_topology_enable_ex(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode);
+void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain,
+ struct Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob);
+
+bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush);
+
+void SCULPT_dynamic_topology_triangulate(struct BMesh *bm);
+void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss);
+
+enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob);
+
+void SCULPT_pbvh_clear(Object *ob);
+
/* Automasking. */
float SCULPT_automasking_factor_get(SculptSession *ss, int vert);
+void SCULPT_automasking_init(Sculpt *sd, Object *ob);
+void SCULPT_automasking_end(Object *ob);
+
+bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd,
+ const Brush *br,
+ const eAutomasking_flag mode);
+bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br);
+
+typedef enum eBoundaryAutomaskMode {
+ AUTOMASK_INIT_BOUNDARY_EDGES = 1,
+ AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2,
+} eBoundaryAutomaskMode;
+float *SCULPT_boundary_automasking_init(Object *ob,
+ eBoundaryAutomaskMode mode,
+ int propagation_steps,
+ float *automask_factor);
+
+/* Filters. */
+void SCULPT_filter_cache_init(Object *ob, Sculpt *sd);
+void SCULPT_filter_cache_free(SculptSession *ss);
+
+void SCULPT_mask_filter_smooth_apply(
+ Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations);
+
/* Brushes. */
/* Cloth Brush. */
@@ -228,6 +333,13 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr,
struct SculptSession *ss,
const float outline_col[3],
float outline_alpha);
+
+BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush)
+{
+ return brush->sculpt_tool == SCULPT_TOOL_CLOTH &&
+ brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB;
+}
+
/* Pose Brush. */
void SCULPT_do_pose_brush(struct Sculpt *sd,
struct Object *ob,
@@ -259,6 +371,43 @@ void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
SculptSession *ss,
const float outline_col[3],
const float outline_alpha);
+/* Draw Face Sets Brush. */
+void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Smooth Brush. */
+
+void SCULPT_neighbor_average(SculptSession *ss, float avg[3], uint vert);
+void SCULPT_bmesh_neighbor_average(float avg[3], struct BMVert *v);
+
+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_smooth(Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ const int totnode,
+ float bstrength,
+ const bool smooth_mask);
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
+
+/* Surface Smooth Brush. */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float origco[3],
+ const float alpha);
+void SCULPT_surface_smooth_displace_step(SculptSession *ss,
+ float *co,
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float beta,
+ const float fade);
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
/* Slide/Relax */
void SCULPT_relax_vertex(struct SculptSession *ss,
@@ -267,10 +416,6 @@ void SCULPT_relax_vertex(struct SculptSession *ss,
bool filter_boundary_face_sets,
float *r_final_pos);
-/* Sculpt Visibility API */
-void SCULPT_visibility_sync_all_face_sets_to_vertices(struct SculptSession *ss);
-void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss);
-
/* Undo */
typedef enum {
@@ -284,6 +429,23 @@ typedef enum {
SCULPT_UNDO_FACE_SETS,
} SculptUndoType;
+/* Storage of geometry for the undo node.
+ * Is used as a storage for either original or modified geometry. */
+typedef struct SculptUndoNodeGeometry {
+ /* Is used for sanity check, helping with ensuring that two and only two
+ * geometry pushes happened in the undo stack. */
+ bool is_initialized;
+
+ CustomData vdata;
+ CustomData edata;
+ CustomData ldata;
+ CustomData pdata;
+ int totvert;
+ int totedge;
+ int totloop;
+ int totpoly;
+} SculptUndoNodeGeometry;
+
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
@@ -317,15 +479,18 @@ typedef struct SculptUndoNode {
/* shape keys */
char shapeName[sizeof(((KeyBlock *)0))->name];
- /* geometry modification operations and bmesh enter data */
- CustomData geom_vdata;
- CustomData geom_edata;
- CustomData geom_ldata;
- CustomData geom_pdata;
- int geom_totvert;
- int geom_totedge;
- int geom_totloop;
- int geom_totpoly;
+ /* Geometry modification operations.
+ *
+ * Original geometry is stored before some modification is run and is used to restore state of
+ * the object when undoing the operation
+ *
+ * Modified geometry is stored after the modification and is used to redo the modification. */
+ bool geometry_clear_pbvh;
+ SculptUndoNodeGeometry geometry_original;
+ SculptUndoNodeGeometry geometry_modified;
+
+ /* Geometry at the bmesh enter moment. */
+ SculptUndoNodeGeometry geometry_bmesh_enter;
/* pivot */
float pivot_pos[3];
@@ -427,6 +592,9 @@ typedef struct SculptThreadedTaskData {
float transform_mats[8][4][4];
float cloth_time_step;
+ SculptClothSimulation *cloth_sim;
+ float *cloth_sim_initial_location;
+ float cloth_sim_radius;
float dirty_mask_min;
float dirty_mask_max;
@@ -441,6 +609,7 @@ typedef struct SculptThreadedTaskData {
/*************** Brush testing declarations ****************/
typedef struct SculptBrushTest {
float radius_squared;
+ float radius;
float location[3];
float dist;
int mirror_symmetry_pass;
@@ -517,7 +686,7 @@ bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush,
* For descriptions of these settings, check the operator properties.
*/
-#define CLAY_STABILIZER_LEN 10
+#define SCULPT_CLAY_STABILIZER_LEN 10
typedef struct StrokeCache {
/* Invariants */
@@ -608,7 +777,7 @@ typedef struct StrokeCache {
/* Angle of the front tilting plane of the brush to simulate clay accumulation. */
float clay_thumb_front_angle;
/* Stores pressure samples to get an stabilized strength and radius variation. */
- float clay_pressure_stabilizer[CLAY_STABILIZER_LEN];
+ float clay_pressure_stabilizer[SCULPT_CLAY_STABILIZER_LEN];
int clay_pressure_stabilizer_index;
/* Cloth brush */
@@ -622,6 +791,9 @@ typedef struct StrokeCache {
/* Stores the displacement produced by the laplacian step of HC smooth. */
float (*surface_smooth_laplacian_disp)[3];
+ /* Layer brush */
+ float *layer_displacement_factor;
+
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
struct Dial *dial;
@@ -659,10 +831,18 @@ typedef struct FilterCache {
float surface_smooth_shape_preservation;
float surface_smooth_current_vertex;
+ /* Sharpen mesh filter. */
+ float sharpen_smooth_ratio;
+ float *sharpen_factor;
+
/* unmasked nodes */
PBVHNode **nodes;
int totnode;
+ /* Cloth filter. */
+ SculptClothSimulation *cloth_sim;
+ float cloth_sim_pinch_point[3];
+
/* mask expand iteration caches */
int mask_update_current_it;
int mask_update_last_it;
@@ -689,8 +869,10 @@ 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_first_node(void);
void SCULPT_undo_push_begin(const char *name);
void SCULPT_undo_push_end(void);
+void SCULPT_undo_push_end_ex(const bool use_nested_undo);
void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]);
@@ -701,4 +883,36 @@ bool SCULPT_get_redraw_rect(struct ARegion *region,
Object *ob,
rcti *rect);
+/* Operators. */
+
+/* Face Sets. */
+void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
+void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
+
+/* Transform. */
+void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
+
+/* Mesh Filter. */
+void SCULPT_OT_mesh_filter(struct wmOperatorType *ot);
+
+/* Cloth Filter. */
+void SCULPT_OT_cloth_filter(struct wmOperatorType *ot);
+
+/* Mask filter and Dirty Mask. */
+void SCULPT_OT_mask_filter(struct wmOperatorType *ot);
+void SCULPT_OT_dirty_mask(struct wmOperatorType *ot);
+
+/* Mask and Face Sets Expand. */
+void SCULPT_OT_mask_expand(struct wmOperatorType *ot);
+
+/* Detail size. */
+void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot);
+void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot);
+void SCULPT_OT_set_detail_size(struct wmOperatorType *ot);
+
+/* Dyntopo. */
+void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot);
+
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
new file mode 100644
index 00000000000..cbb198e14a3
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c
@@ -0,0 +1,526 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_ccg.h"
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_multires.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "ED_view3d.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ MEM_freeN(op->customdata);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ if (create_face_set) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
+ }
+ }
+ else {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ *vd.mask = ss->filter_cache->prev_mask[vd.index];
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ BKE_pbvh_node_mark_redraw(node);
+ }
+
+ if (!create_face_set) {
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ SCULPT_filter_cache_free(ss);
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+}
+
+static void sculpt_expand_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ int update_it = data->mask_expand_update_it;
+
+ 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)] <
+ ss->filter_cache->normal_factor[vd.index]) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+ else {
+ if (ss->filter_cache->mask_update_it[vi] <= update_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+
+ 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);
+ }
+ BKE_pbvh_node_mark_redraw(node);
+ }
+ else {
+
+ if (data->mask_expand_keep_prev_mask) {
+ final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
+ }
+
+ if (data->mask_expand_invert_mask) {
+ final_mask = 1.0f - final_mask;
+ }
+
+ if (*vd.mask != final_mask) {
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_update_mask(node);
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ float prevclick_f[2];
+ copy_v2_v2(prevclick_f, op->customdata);
+ int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
+ int len = (int)len_v2v2_int(prevclick, event->mval);
+ len = abs(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int mask_expand_update_it = len / mask_speed;
+ mask_expand_update_it = mask_expand_update_it + 1;
+
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)SCULPT_active_vertex_get(ss)];
+ }
+
+ if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ /* Returning OPERATOR_CANCELLED will leak memory due to not finishing
+ * undo. Better solution could be to make paint_mesh_restore_co work
+ * for this case. */
+ sculpt_mask_expand_cancel(C, op);
+ return OPERATOR_FINISHED;
+ }
+
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == EVT_RETKEY && event->val == KM_PRESS) ||
+ (event->type == EVT_PADENTER && event->val == KM_PRESS)) {
+
+ /* Smooth iterations. */
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
+ const int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ SCULPT_mask_filter_smooth_apply(
+ sd, ob, ss->filter_cache->nodes, ss->filter_cache->totnode, smooth_iterations);
+
+ /* Pivot position. */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float threshold = 0.2f;
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, ss->filter_cache->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (SCULPT_check_vertex_pivot_symmetry(
+ vd.co, ss->filter_cache->mask_expand_initial_co, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ SCULPT_filter_cache_free(ss);
+
+ SCULPT_undo_push_end();
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ /* When pressing Ctrl, expand directly to the max number of iterations. This allows to flood fill
+ * mask and face sets by connectivity directly. */
+ if (event->ctrl) {
+ mask_expand_update_it = ss->filter_cache->mask_update_last_it - 1;
+ }
+
+ if (!ELEM(event->type, MOUSEMOVE, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY)) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
+ ED_region_tag_redraw(region);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
+
+ if (create_face_set) {
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->face_sets[i] = ss->filter_cache->prev_face_set[i];
+ }
+ }
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = mask_expand_update_it,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = mask_expand_update_it;
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+typedef struct MaskExpandFloodFillData {
+ float original_normal[3];
+ float edge_sensitivity;
+ bool use_normals;
+} MaskExpandFloodFillData;
+
+static bool mask_expand_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ MaskExpandFloodFillData *data = userdata;
+
+ 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;
+ if (to_it > ss->filter_cache->mask_update_last_it) {
+ ss->filter_cache->mask_update_last_it = to_it;
+ }
+
+ if (data->use_normals) {
+ 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);
+ }
+ }
+ else {
+ /* PBVH_GRIDS duplicate handling. */
+ ss->filter_cache->mask_update_it[to_v] = ss->filter_cache->mask_update_it[from_v];
+ 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];
+ }
+ }
+
+ return true;
+}
+
+static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ PBVH *pbvh = ob->sculpt->pbvh;
+
+ const bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
+ const bool create_face_set = RNA_boolean_get(op->ptr, "create_face_set");
+
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+
+ SCULPT_vertex_random_access_init(ss);
+
+ op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
+ copy_v2_v2(op->customdata, mouse);
+
+ SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
+
+ int vertex_count = SCULPT_vertex_count_get(ss);
+
+ ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
+
+ SCULPT_undo_push_begin("Mask Expand");
+
+ if (create_face_set) {
+ SCULPT_undo_push_node(ob, ss->filter_cache->nodes[0], SCULPT_UNDO_FACE_SETS);
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+ }
+ else {
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ SCULPT_undo_push_node(ob, ss->filter_cache->nodes[i], SCULPT_UNDO_MASK);
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+ }
+
+ ss->filter_cache->mask_update_it = MEM_callocN(sizeof(int) * vertex_count,
+ "mask update iteration");
+ if (use_normals) {
+ ss->filter_cache->normal_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ ss->filter_cache->edge_factor = MEM_callocN(sizeof(float) * vertex_count,
+ "mask update normal factor");
+ for (int i = 0; i < vertex_count; i++) {
+ ss->filter_cache->edge_factor[i] = 1.0f;
+ }
+ }
+
+ if (create_face_set) {
+ ss->filter_cache->prev_face_set = MEM_callocN(sizeof(float) * ss->totfaces, "prev face mask");
+ for (int i = 0; i < ss->totfaces; i++) {
+ ss->filter_cache->prev_face_set[i] = ss->face_sets[i];
+ }
+ ss->filter_cache->new_face_set = SCULPT_face_set_next_available_get(ss);
+ }
+ 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);
+ }
+ }
+
+ 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;
+
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, SCULPT_active_vertex_co_get(ss));
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
+
+ MaskExpandFloodFillData fdata = {
+ .use_normals = use_normals,
+ .edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity"),
+ };
+ SCULPT_active_vertex_normal_get(ss, fdata.original_normal);
+ SCULPT_floodfill_execute(ss, &flood, mask_expand_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ if (use_normals) {
+ for (int repeat = 0; repeat < 2; repeat++) {
+ for (int i = 0; i < vertex_count; i++) {
+ float avg = 0.0f;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
+ avg += ss->filter_cache->normal_factor[ni.index];
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ ss->filter_cache->normal_factor[i] = avg / ni.size;
+ }
+ }
+
+ MEM_SAFE_FREE(ss->filter_cache->edge_factor);
+ }
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = 0,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"),
+ };
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+
+ const char *status_str = TIP_(
+ "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: "
+ "cancel");
+ ED_workspace_status_text(C, status_str);
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_MASK);
+ WM_event_add_modal_handler(C, op);
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SCULPT_OT_mask_expand(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Mask Expand";
+ ot->idname = "SCULPT_OT_mask_expand";
+ ot->description = "Expands a mask from the initial active vertex under the cursor";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_mask_expand_invoke;
+ ot->modal = sculpt_mask_expand_modal;
+ ot->cancel = sculpt_mask_expand_cancel;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->prop = RNA_def_boolean(ot->srna, "invert", true, "Invert", "Invert the new mask");
+ ot->prop = RNA_def_boolean(
+ ot->srna, "use_cursor", true, "Use Cursor", "Expand the mask to the cursor position");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "update_pivot",
+ true,
+ "Update Pivot Position",
+ "Set the pivot position to the mask border after creating the mask");
+ ot->prop = RNA_def_int(ot->srna, "smooth_iterations", 2, 0, 10, "Smooth iterations", "", 0, 10);
+ ot->prop = RNA_def_int(ot->srna, "mask_speed", 5, 1, 10, "Mask speed", "", 1, 10);
+
+ ot->prop = RNA_def_boolean(ot->srna,
+ "use_normals",
+ true,
+ "Use Normals",
+ "Generate the mask using the normals and curvature of the model");
+ ot->prop = RNA_def_boolean(ot->srna,
+ "keep_previous_mask",
+ false,
+ "Keep Previous Mask",
+ "Generate the new mask on top of the current one");
+ ot->prop = RNA_def_int(ot->srna,
+ "edge_sensitivity",
+ 300,
+ 0,
+ 2000,
+ "Edge Detection Sensitivity",
+ "Sensitivity for expanding the mask across sculpted sharp edges when "
+ "using normals to generate the mask",
+ 0,
+ 2000);
+ ot->prop = RNA_def_boolean(ot->srna,
+ "create_face_set",
+ false,
+ "Expand Face Mask",
+ "Expand a new Face Mask instead of the sculpt mask");
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
index c74a2ba503a..f3327706102 100644
--- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
+++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -79,6 +79,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
/* Apply the brush normal radius to the test before sampling. */
float test_radius = sqrtf(test.radius_squared);
@@ -107,7 +108,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
/* Sample the normal and area of the +X and -X axis individually. */
if (local_co[0] > 0.0f) {
@@ -163,6 +164,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
SculptBrushTest test;
SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
@@ -208,7 +210,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata,
vd.fno,
vd.mask ? *vd.mask : 0.0f,
vd.index,
- tls->thread_id);
+ thread_id);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -301,13 +303,13 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
MultiplaneScrapeSampleData mssd = {{{0}}};
- PBVHParallelSettings sample_settings;
+ TaskParallelSettings sample_settings;
BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce;
sample_settings.userdata_chunk = &mssd;
sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings);
float sampled_plane_normals[2][3];
@@ -392,9 +394,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes,
normalize_v3(plane_no);
plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings);
}
void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr,
diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c
index f1c884f9897..56ba15bef70 100644
--- a/source/blender/editors/sculpt_paint/sculpt_pose.c
+++ b/source/blender/editors/sculpt_paint/sculpt_pose.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
@@ -131,6 +131,32 @@ static void pose_solve_roll_chain(SculptPoseIKChain *ik_chain,
}
}
+static void pose_solve_translate_chain(SculptPoseIKChain *ik_chain, const float delta[3])
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Move the origin and head of each segment by delta. */
+ add_v3_v3v3(segments[i].head, segments[i].initial_head, delta);
+ add_v3_v3v3(segments[i].orig, segments[i].initial_orig, delta);
+
+ /* Reset the segment rotation. */
+ unit_qt(segments[i].rot);
+ }
+}
+
+static void pose_solve_scale_chain(SculptPoseIKChain *ik_chain, const float scale)
+{
+ SculptPoseIKChainSegment *segments = ik_chain->segments;
+ const int tot_segments = ik_chain->tot_segments;
+
+ for (int i = 0; i < tot_segments; i++) {
+ /* Assign the scale to each segment. */
+ segments[i].scale = scale;
+ }
+}
+
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict UNUSED(tls))
@@ -209,12 +235,11 @@ 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.index, ni) {
float vmask_f = data->prev_mask[ni.index];
max = MAX2(vmask_f, max);
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
/* Keep the count of the vertices that where added to the factors in this grow iteration. */
if (max > data->prev_mask[vd.index]) {
@@ -264,7 +289,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
};
data.pose_initial_co = pose_target;
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
PoseGrowFactorTLSData gftd;
gftd.pos_count = 0;
zero_v3(gftd.pos_avg);
@@ -280,7 +305,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd,
zero_v3(gftd.pos_avg);
gftd.pos_count = 0;
memcpy(data.prev_mask, pose_factor, SCULPT_vertex_count_get(ss) * sizeof(float));
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings);
if (gftd.pos_count != 0) {
mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
@@ -352,18 +377,55 @@ typedef struct PoseFloodFillData {
float *pose_factor;
float pose_origin[3];
int tot_co;
+
+ int current_face_set;
+ int next_face_set;
+ int prev_face_set;
+ int next_vertex;
+
+ bool next_face_set_found;
+
+ /* Store the visited face sets to avoid going back when calculating the chain. */
+ GSet *visited_face_sets;
+
+ /* In face sets origin mode, each vertex can only be assigned to one face set. */
+ BLI_bitmap *is_weighted;
+
+ bool is_first_iteration;
+
+ /* In topology mode this stores the furthest point from the stroke origin for cases when a pose
+ * origin based on the brush radius can't be set. */
+ float fallback_floodfill_origin[3];
+
+ /* Fallback origin. If we can't find any face set to continue, use the position of all vertices
+ * that have the current face set. */
+ float fallback_origin[3];
+ int fallback_count;
+
+ /* Face Set FK mode. */
+ int *floodfill_it;
+ float *fk_weights;
+ int initial_face_set;
+ int masked_face_set_it;
+ int masked_face_set;
+ int target_face_set;
} PoseFloodFillData;
-static bool pose_floodfill_cb(
+static bool pose_topology_floodfill_cb(
SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
PoseFloodFillData *data = userdata;
+ const float *co = SCULPT_vertex_co_get(ss, to_v);
if (data->pose_factor) {
data->pose_factor[to_v] = 1.0f;
}
- const float *co = SCULPT_vertex_co_get(ss, to_v);
+ if (len_squared_v3v3(data->pose_initial_co, data->fallback_floodfill_origin) <
+ len_squared_v3v3(data->pose_initial_co, co)) {
+ copy_v3_v3(data->fallback_floodfill_origin, co);
+ }
+
if (sculpt_pose_brush_is_vertex_inside_brush_radius(
co, data->pose_initial_co, data->radius, data->symm)) {
return true;
@@ -378,6 +440,100 @@ static bool pose_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)
+{
+ PoseFloodFillData *data = userdata;
+
+ const int index = to_v;
+ bool visit_next = false;
+
+ const float *co = SCULPT_vertex_co_get(ss, index);
+ const bool symmetry_check = SCULPT_check_vertex_pivot_symmetry(
+ co, data->pose_initial_co, data->symm) &&
+ !is_duplicate;
+
+ /* First iteration. Continue expanding using topology until a vertex is outside the brush radius
+ * to determine the first face set. */
+ if (data->current_face_set == SCULPT_FACE_SET_NONE) {
+
+ data->pose_factor[index] = 1.0f;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
+
+ 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);
+ 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);
+ BLI_gset_add(data->visited_face_sets, POINTER_FROM_INT(data->current_face_set));
+ }
+ return true;
+ }
+
+ /* We already have a current face set, so we can start checking the face sets of the vertices. */
+ /* In the first iteration we need to check all face sets we already visited as the flood fill may
+ * still not be finished in some of them. */
+ bool is_vertex_valid = false;
+ if (data->is_first_iteration) {
+ 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);
+ }
+ }
+ else {
+ is_vertex_valid = SCULPT_vertex_has_face_set(ss, index, data->current_face_set);
+ }
+
+ if (is_vertex_valid) {
+
+ if (!BLI_BITMAP_TEST(data->is_weighted, index)) {
+ data->pose_factor[index] = 1.0f;
+ BLI_BITMAP_ENABLE(data->is_weighted, index);
+ visit_next = true;
+ }
+
+ /* Fallback origin accumulation. */
+ if (symmetry_check) {
+ add_v3_v3(data->fallback_origin, SCULPT_vertex_co_get(ss, index));
+ data->fallback_count++;
+ }
+
+ if (symmetry_check && !SCULPT_vertex_has_unique_face_set(ss, index)) {
+
+ /* We only add coordinates for calculating the origin when it is possible to go from this
+ * vertex to another vertex in a valid face set for the next iteration. */
+ 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);
+
+ /* 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) &&
+ !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_face_set_found = true;
+ }
+ count_as_boundary = true;
+ }
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ /* Origin accumulation. */
+ if (count_as_boundary) {
+ add_v3_v3(data->pose_origin, SCULPT_vertex_co_get(ss, index));
+ data->tot_co++;
+ }
+ }
+ }
+ return visit_next;
+}
+
/* Public functions. */
/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
@@ -408,12 +564,16 @@ void SCULPT_pose_calc_pose_data(Sculpt *sd,
};
zero_v3(fdata.pose_origin);
copy_v3_v3(fdata.pose_initial_co, initial_location);
- SCULPT_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ copy_v3_v3(fdata.fallback_floodfill_origin, initial_location);
+ SCULPT_floodfill_execute(ss, &flood, pose_topology_floodfill_cb, &fdata);
SCULPT_floodfill_free(&flood);
if (fdata.tot_co > 0) {
mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
}
+ else {
+ copy_v3_v3(fdata.pose_origin, fdata.fallback_floodfill_origin);
+ }
/* Offset the pose origin. */
float pose_d[3];
@@ -442,12 +602,11 @@ 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.index, ni) {
avg += data->pose_factor[ni.index];
total++;
}
- sculpt_vertex_neighbors_iter_end(ni);
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
if (total > 0) {
data->pose_factor[vd.index] = avg / total;
@@ -456,12 +615,59 @@ static void pose_brush_init_task_cb_ex(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
}
-SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
- Object *ob,
- SculptSession *ss,
- Brush *br,
- const float initial_location[3],
- const float radius)
+/* Init the IK chain with empty weights. */
+static SculptPoseIKChain *pose_ik_chain_new(const int totsegments, const int totverts)
+{
+ SculptPoseIKChain *ik_chain = MEM_callocN(sizeof(SculptPoseIKChain), "Pose IK Chain");
+ ik_chain->tot_segments = totsegments;
+ ik_chain->segments = MEM_callocN(totsegments * sizeof(SculptPoseIKChainSegment),
+ "Pose IK Chain Segments");
+ for (int i = 0; i < totsegments; i++) {
+ ik_chain->segments[i].weights = MEM_callocN(totverts * sizeof(float), "Pose IK weights");
+ }
+ return ik_chain;
+}
+
+/* Init the origin/head pairs of all the segments from the calculated origins. */
+static void pose_ik_chain_origin_heads_init(SculptPoseIKChain *ik_chain,
+ const float initial_location[3])
+{
+ float origin[3];
+ float head[3];
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
+ if (i == 0) {
+ copy_v3_v3(head, initial_location);
+ copy_v3_v3(origin, ik_chain->segments[i].orig);
+ }
+ else {
+ copy_v3_v3(head, ik_chain->segments[i - 1].orig);
+ copy_v3_v3(origin, ik_chain->segments[i].orig);
+ }
+ copy_v3_v3(ik_chain->segments[i].orig, origin);
+ copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
+ copy_v3_v3(ik_chain->segments[i].initial_head, head);
+ ik_chain->segments[i].len = len_v3v3(head, origin);
+ ik_chain->segments[i].scale = 1.0f;
+ }
+}
+
+static int pose_brush_num_effective_segments(const Brush *brush)
+{
+ /* Scaling multiple segments at the same time is not supported as the IK solver can't handle
+ * changes in the segment's length. It will also required a better weight distribution to avoid
+ * artifacts in the areas affected by multiple segments. */
+ if (brush->pose_deform_type == BRUSH_POSE_DEFORM_SCALE_TRASLATE) {
+ return 1;
+ }
+ return brush->pose_ik_segments;
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_topology(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ Brush *br,
+ const float initial_location[3],
+ const float radius)
{
const float chain_segment_len = radius * (1.0f + br->pose_offset);
@@ -482,14 +688,8 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
pose_factor_grow[nearest_vertex_index] = 1.0f;
- /* Init the IK chain with empty weights. */
- SculptPoseIKChain *ik_chain = MEM_callocN(sizeof(SculptPoseIKChain), "Pose IK Chain");
- ik_chain->tot_segments = br->pose_ik_segments;
- ik_chain->segments = MEM_callocN(ik_chain->tot_segments * sizeof(SculptPoseIKChainSegment),
- "Pose IK Chain Segments");
- for (int i = 0; i < br->pose_ik_segments; i++) {
- ik_chain->segments[i].weights = MEM_callocN(totvert * sizeof(float), "Pose IK weights");
- }
+ const int tot_segments = pose_brush_num_effective_segments(br);
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
/* Calculate the first segment in the chain using the brush radius and the pose origin offset. */
copy_v3_v3(next_chain_segment_target, initial_location);
@@ -534,30 +734,220 @@ SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
}
}
- /* Init the origin/head pairs of all the segments from the calculated origins. */
- float origin[3];
- float head[3];
- for (int i = 0; i < ik_chain->tot_segments; i++) {
- if (i == 0) {
- copy_v3_v3(head, initial_location);
- copy_v3_v3(origin, ik_chain->segments[i].orig);
+ pose_ik_chain_origin_heads_init(ik_chain, initial_location);
+
+ MEM_freeN(pose_factor_grow);
+ MEM_freeN(pose_factor_grow_prev);
+
+ return ik_chain;
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_face_sets(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, const float radius)
+{
+
+ int totvert = SCULPT_vertex_count_get(ss);
+
+ const int tot_segments = pose_brush_num_effective_segments(br);
+
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(tot_segments, totvert);
+
+ GSet *visited_face_sets = BLI_gset_int_new_ex("visited_face_sets", ik_chain->tot_segments);
+
+ BLI_bitmap *is_weighted = BLI_BITMAP_NEW(totvert, "weighted");
+
+ int current_face_set = SCULPT_FACE_SET_NONE;
+ int prev_face_set = SCULPT_FACE_SET_NONE;
+
+ int current_vertex = SCULPT_active_vertex_get(ss);
+
+ for (int s = 0; s < ik_chain->tot_segments; s++) {
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_initial_with_symmetry(sd, ob, ss, &flood, current_vertex, FLT_MAX);
+
+ BLI_gset_add(visited_face_sets, POINTER_FROM_INT(current_face_set));
+
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = ik_chain->segments[s].weights,
+ .tot_co = 0,
+ .fallback_count = 0,
+ .current_face_set = current_face_set,
+ .prev_face_set = prev_face_set,
+ .visited_face_sets = visited_face_sets,
+ .is_weighted = is_weighted,
+ .next_face_set_found = false,
+ .is_first_iteration = s == 0,
+ };
+ zero_v3(fdata.pose_origin);
+ zero_v3(fdata.fallback_origin);
+ copy_v3_v3(fdata.pose_initial_co, SCULPT_vertex_co_get(ss, current_vertex));
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
+ copy_v3_v3(ik_chain->segments[s].orig, fdata.pose_origin);
+ }
+ else if (fdata.fallback_count > 0) {
+ mul_v3_fl(fdata.fallback_origin, 1.0f / (float)fdata.fallback_count);
+ copy_v3_v3(ik_chain->segments[s].orig, fdata.fallback_origin);
}
else {
- copy_v3_v3(head, ik_chain->segments[i - 1].orig);
- copy_v3_v3(origin, ik_chain->segments[i].orig);
+ zero_v3(ik_chain->segments[s].orig);
}
- copy_v3_v3(ik_chain->segments[i].orig, origin);
- copy_v3_v3(ik_chain->segments[i].initial_orig, origin);
- copy_v3_v3(ik_chain->segments[i].initial_head, head);
- ik_chain->segments[i].len = len_v3v3(head, origin);
+
+ prev_face_set = fdata.current_face_set;
+ current_face_set = fdata.next_face_set;
+ current_vertex = fdata.next_vertex;
}
- MEM_freeN(pose_factor_grow);
- MEM_freeN(pose_factor_grow_prev);
+ BLI_gset_free(visited_face_sets, NULL);
+
+ pose_ik_chain_origin_heads_init(ik_chain, SCULPT_active_vertex_co_get(ss));
+
+ MEM_SAFE_FREE(is_weighted);
return ik_chain;
}
+static bool pose_face_sets_fk_find_masked_floodfill_cb(
+ SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
+{
+ PoseFloodFillData *data = userdata;
+
+ if (!is_duplicate) {
+ data->floodfill_it[to_v] = data->floodfill_it[from_v] + 1;
+ }
+ else {
+ data->floodfill_it[to_v] = data->floodfill_it[from_v];
+ }
+
+ const int to_face_set = SCULPT_vertex_face_set_get(ss, to_v);
+ if (SCULPT_vertex_has_unique_face_set(ss, to_v) &&
+ !SCULPT_vertex_has_unique_face_set(ss, from_v) &&
+ SCULPT_vertex_has_face_set(ss, from_v, to_face_set)) {
+
+ if (data->floodfill_it[to_v] > data->masked_face_set_it) {
+ data->masked_face_set = to_face_set;
+ data->masked_face_set_it = data->floodfill_it[to_v];
+ }
+
+ if (data->target_face_set == SCULPT_FACE_SET_NONE) {
+ data->target_face_set = to_face_set;
+ }
+ }
+
+ 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)
+{
+ PoseFloodFillData *data = userdata;
+ data->fk_weights[to_v] = 1.0f;
+ return !SCULPT_vertex_has_face_set(ss, to_v, data->masked_face_set);
+}
+
+static SculptPoseIKChain *pose_ik_chain_init_face_sets_fk(
+ Sculpt *sd, Object *ob, SculptSession *ss, const float radius, const float *initial_location)
+{
+ const int totvert = SCULPT_vertex_count_get(ss);
+
+ SculptPoseIKChain *ik_chain = pose_ik_chain_new(1, totvert);
+
+ const int active_vertex = SCULPT_active_vertex_get(ss);
+ const int active_face_set = SCULPT_active_face_set_get(ss);
+
+ SculptFloodFill flood;
+ SCULPT_floodfill_init(ss, &flood);
+ 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.initial_face_set = active_face_set;
+ fdata.masked_face_set = SCULPT_FACE_SET_NONE;
+ fdata.target_face_set = SCULPT_FACE_SET_NONE;
+ fdata.masked_face_set_it = 0;
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_find_masked_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ 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));
+ origin_count++;
+ }
+ }
+
+ int target_count = 0;
+ float target_acc[3] = {0.0f};
+ if (fdata.target_face_set != fdata.masked_face_set) {
+ 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.target_face_set)) {
+ add_v3_v3(target_acc, SCULPT_vertex_co_get(ss, i));
+ target_count++;
+ }
+ }
+ }
+
+ MEM_freeN(fdata.floodfill_it);
+
+ if (origin_count > 0) {
+ copy_v3_v3(ik_chain->segments[0].orig, origin_acc);
+ mul_v3_fl(ik_chain->segments[0].orig, 1.0f / origin_count);
+ }
+ else {
+ zero_v3(ik_chain->segments[0].orig);
+ }
+
+ if (target_count > 0) {
+ copy_v3_v3(ik_chain->segments[0].head, target_acc);
+ mul_v3_fl(ik_chain->segments[0].head, 1.0f / target_count);
+ sub_v3_v3v3(ik_chain->grab_delta_offset, ik_chain->segments[0].head, initial_location);
+ }
+ else {
+ copy_v3_v3(ik_chain->segments[0].head, initial_location);
+ }
+
+ SCULPT_floodfill_init(ss, &flood);
+ SCULPT_floodfill_add_active(sd, ob, ss, &flood, radius);
+ fdata.fk_weights = ik_chain->segments[0].weights;
+ SCULPT_floodfill_execute(ss, &flood, pose_face_sets_fk_set_weights_floodfill_cb, &fdata);
+ SCULPT_floodfill_free(&flood);
+
+ pose_ik_chain_origin_heads_init(ik_chain, ik_chain->segments[0].head);
+ return ik_chain;
+}
+
+SculptPoseIKChain *SCULPT_pose_ik_chain_init(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ Brush *br,
+ const float initial_location[3],
+ const float radius)
+{
+ switch (br->pose_origin_type) {
+ case BRUSH_POSE_ORIGIN_TOPOLOGY:
+ return pose_ik_chain_init_topology(sd, ob, ss, br, initial_location, radius);
+ break;
+ case BRUSH_POSE_ORIGIN_FACE_SETS:
+ return pose_ik_chain_init_face_sets(sd, ob, ss, br, radius);
+ break;
+ case BRUSH_POSE_ORIGIN_FACE_SETS_FK:
+ return pose_ik_chain_init_face_sets_fk(sd, ob, ss, radius, initial_location);
+ break;
+ }
+ return NULL;
+}
+
void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
{
PBVHNode **nodes;
@@ -581,22 +971,95 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br
for (int ik = 0; ik < ss->cache->pose_ik_chain->tot_segments; ik++) {
data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights;
for (int i = 0; i < br->pose_smooth_iterations; i++) {
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
}
}
MEM_SAFE_FREE(nodes);
}
+static void sculpt_pose_do_translate_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_translate_chain(ik_chain, ss->cache->grab_delta);
+}
+
+static void sculpt_pose_do_scale_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+
+ /* Solve the IK for the first segment to include rotation as part of scale. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+
+ /* Calculate a scale factor based on the grab delta. */
+ float plane[4];
+ float segment_dir[3];
+ sub_v3_v3v3(segment_dir, ik_chain->segments[0].initial_head, ik_chain->segments[0].initial_orig);
+ normalize_v3(segment_dir);
+ plane_from_point_normal_v3(plane, ik_chain->segments[0].initial_head, segment_dir);
+ const float segment_len = ik_chain->segments[0].len;
+ const float scale = segment_len / (segment_len - dist_signed_to_plane_v3(ik_target, plane));
+
+ /* Write the scale into the segments. */
+ pose_solve_scale_chain(ik_chain, scale);
+}
+
+static void sculpt_pose_do_twist_deform(SculptSession *ss, Brush *brush)
+{
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
+ float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength * 0.02f;
+ BKE_curvemapping_initialize(brush->curve);
+ pose_solve_roll_chain(ik_chain, brush, roll);
+}
+
+static void sculpt_pose_do_rotate_deform(SculptSession *ss, Brush *brush)
+{
+ float ik_target[3];
+ SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
+
+ /* Calculate the IK target. */
+ copy_v3_v3(ik_target, ss->cache->true_location);
+ add_v3_v3(ik_target, ss->cache->grab_delta);
+ add_v3_v3(ik_target, ik_chain->grab_delta_offset);
+
+ /* Solve the IK positions. */
+ pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+}
+
+static void sculpt_pose_do_rotate_twist_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_twist_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_rotate_deform(ss, brush);
+ }
+}
+
+static void sculpt_pose_do_scale_translate_deform(SculptSession *ss, Brush *brush)
+{
+ if (ss->cache->invert) {
+ sculpt_pose_do_translate_deform(ss, brush);
+ }
+ else {
+ sculpt_pose_do_scale_deform(ss, brush);
+ }
+}
+
/* Main Brush Function. */
void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
SculptSession *ss = ob->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
- float grab_delta[3];
- float ik_target[3];
const ePaintSymmetryFlags symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
/* The pose brush applies all enabled symmetry axis in a single iteration, so the rest can be
@@ -607,25 +1070,13 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
SculptPoseIKChain *ik_chain = ss->cache->pose_ik_chain;
- /* Solve the positions and rotations of the IK chain. */
- if (ss->cache->invert) {
- /* Roll Mode. */
- /* Calculate the maximum roll. 0.02 radians per pixel works fine. */
- float roll = (ss->cache->initial_mouse[0] - ss->cache->mouse[0]) * ss->cache->bstrength *
- 0.02f;
- BKE_curvemapping_initialize(brush->curve);
- pose_solve_roll_chain(ik_chain, brush, roll);
- }
- else {
- /* IK follow target mode. */
- /* Calculate the IK target. */
-
- copy_v3_v3(grab_delta, ss->cache->grab_delta);
- copy_v3_v3(ik_target, ss->cache->true_location);
- add_v3_v3(ik_target, ss->cache->grab_delta);
-
- /* Solve the IK positions. */
- pose_solve_ik_chain(ik_chain, ik_target, brush->flag2 & BRUSH_POSE_IK_ANCHORED);
+ switch (brush->pose_deform_type) {
+ case BRUSH_POSE_DEFORM_ROTATE_TWIST:
+ sculpt_pose_do_rotate_twist_deform(ss, brush);
+ break;
+ case BRUSH_POSE_DEFORM_SCALE_TRASLATE:
+ sculpt_pose_do_scale_translate_deform(ss, brush);
+ break;
}
/* Flip the segment chain in all symmetry axis and calculate the transform matrices for each
@@ -633,7 +1084,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* This can be optimized by skipping the calculation of matrices where the symmetry is not
* enabled. */
for (int symm_it = 0; symm_it < PAINT_SYMM_AREAS; symm_it++) {
- for (int i = 0; i < brush->pose_ik_segments; i++) {
+ for (int i = 0; i < ik_chain->tot_segments; i++) {
float symm_rot[4];
float symm_orig[3];
float symm_initial_orig[3];
@@ -653,6 +1104,7 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* Create the transform matrix and store it in the segment. */
unit_m4(ik_chain->segments[i].pivot_mat[symm_it]);
quat_to_mat4(ik_chain->segments[i].trans_mat[symm_it], symm_rot);
+ mul_m4_fl(ik_chain->segments[i].trans_mat[symm_it], ik_chain->segments[i].scale);
translate_m4(ik_chain->segments[i].trans_mat[symm_it],
symm_orig[0] - symm_initial_orig[0],
@@ -670,12 +1122,11 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.ob = ob,
.brush = brush,
.nodes = nodes,
- .grab_delta = grab_delta,
};
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+ BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
}
void SCULPT_pose_ik_chain_free(SculptPoseIKChain *ik_chain)
diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c
new file mode 100644
index 00000000000..17451cb40ae
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c
@@ -0,0 +1,608 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+/* For the smooth brush, uses the neighboring vertices around vert to calculate
+ * a smoothed location for vert. Skips corner vertices (used by only one
+ * polygon). */
+void SCULPT_neighbor_average(SculptSession *ss, float avg[3], uint vert)
+{
+ const MeshElemMap *vert_map = &ss->pmap[vert];
+ const MVert *mvert = ss->mvert;
+ float(*deform_co)[3] = ss->deform_cos;
+
+ /* Don't modify corner vertices. */
+ if (vert_map->count > 1) {
+ int total = 0;
+
+ zero_v3(avg);
+
+ for (int i = 0; i < vert_map->count; i++) {
+ const MPoly *p = &ss->mpoly[vert_map->indices[i]];
+ uint f_adj_v[2];
+
+ if (poly_get_adj_loops_from_vert(p, ss->mloop, vert, f_adj_v) != -1) {
+ for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
+ if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
+ add_v3_v3(avg, deform_co ? deform_co[f_adj_v[j]] : mvert[f_adj_v[j]].co);
+
+ total++;
+ }
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, deform_co ? deform_co[vert] : mvert[vert].co);
+}
+
+/* Same logic as neighbor_average(), but for bmesh rather than mesh. */
+void SCULPT_bmesh_neighbor_average(float avg[3], BMVert *v)
+{
+ /* logic for 3 or more is identical. */
+ const int vfcount = BM_vert_face_count_at_most(v, 3);
+
+ /* Don't modify corner vertices. */
+ if (vfcount > 1) {
+ BMIter liter;
+ BMLoop *l;
+ int total = 0;
+
+ zero_v3(avg);
+
+ 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 (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
+ add_v3_v3(avg, v_other->co);
+ total++;
+ }
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ return;
+ }
+ }
+
+ copy_v3_v3(avg, v->co);
+}
+
+/* For bmesh: Average surrounding verts based on an orthogonality measure.
+ * Naturally converges to a quad-like structure. */
+void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], BMVert *v)
+{
+
+ float avg_co[3] = {0.0f, 0.0f, 0.0f};
+ float tot_co = 0.0f;
+
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_boundary(e)) {
+ copy_v3_v3(avg, v->co);
+ return;
+ }
+ BMVert *v_other = (e->v1 == v) ? e->v2 : e->v1;
+ float vec[3];
+ sub_v3_v3v3(vec, v_other->co, v->co);
+ madd_v3_v3fl(vec, v->no, -dot_v3v3(vec, v->no));
+ normalize_v3(vec);
+
+ /* fac is a measure of how orthogonal or parallel the edge is
+ * relative to the direction. */
+ float fac = dot_v3v3(vec, direction);
+ fac = fac * fac - 0.5f;
+ fac *= fac;
+ madd_v3_v3fl(avg_co, v_other->co, fac);
+ tot_co += fac;
+ }
+
+ /* In case vert has no Edge s. */
+ if (tot_co > 0.0f) {
+ mul_v3_v3fl(avg, avg_co, 1.0f / tot_co);
+
+ /* Preserve volume. */
+ float vec[3];
+ sub_v3_v3(avg, v->co);
+ mul_v3_v3fl(vec, v->no, dot_v3v3(avg, v->no));
+ sub_v3_v3(avg, vec);
+ add_v3_v3(avg, v->co);
+ }
+ else {
+ zero_v3(avg);
+ }
+}
+
+/* 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)
+{
+ 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));
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ mul_v3_v3fl(result, avg, 1.0f / (float)total);
+ }
+ else {
+ copy_v3_v3(result, SCULPT_vertex_co_get(ss, index));
+ }
+}
+
+float SCULPT_neighbor_mask_average(SculptSession *ss, int index)
+{
+ 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);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+
+ if (total > 0) {
+ return avg / (float)total;
+ }
+ else {
+ return SCULPT_vertex_mask_get(ss, index);
+ }
+}
+
+static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.vert_indices[vd.i]) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ SCULPT_neighbor_average(ss, avg, vd.vert_indices[vd.i]);
+ 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) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : *vd.mask,
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask;
+ val *= fade * bstrength;
+ *vd.mask += val;
+ CLAMP(*vd.mask, 0.0f, 1.0f);
+ }
+ else {
+ float avg[3], val[3];
+
+ SCULPT_bmesh_neighbor_average(avg, vd.bm_vert);
+ 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) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ Sculpt *sd = data->sd;
+ const Brush *brush = data->brush;
+ const bool smooth_mask = data->smooth_mask;
+ float bstrength = data->strength;
+
+ PBVHVertexIter vd;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade = bstrength * SCULPT_brush_strength_factor(
+ ss,
+ brush,
+ vd.co,
+ sqrtf(test.dist),
+ vd.no,
+ vd.fno,
+ smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f),
+ vd.index,
+ thread_id);
+ if (smooth_mask) {
+ float val = SCULPT_neighbor_mask_average(ss, vd.index) - *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(ss, avg, vd.index);
+ sub_v3_v3v3(val, avg, vd.co);
+ madd_v3_v3v3fl(val, vd.co, val, fade);
+ SCULPT_clip(sd, ss, vd.co, val);
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_smooth(Sculpt *sd,
+ Object *ob,
+ PBVHNode **nodes,
+ const int totnode,
+ float bstrength,
+ const bool smooth_mask)
+{
+ SculptSession *ss = ob->sculpt;
+ Brush *brush = BKE_paint_brush(&sd->paint);
+
+ const int max_iterations = 4;
+ const float fract = 1.0f / max_iterations;
+ PBVHType type = BKE_pbvh_type(ss->pbvh);
+ int iteration, count;
+ float last;
+
+ CLAMP(bstrength, 0.0f, 1.0f);
+
+ count = (int)(bstrength * max_iterations);
+ last = max_iterations * (bstrength - count * fract);
+
+ if (type == PBVH_FACES && !ss->pmap) {
+ BLI_assert(!"sculpt smooth: pmap missing");
+ return;
+ }
+
+ for (iteration = 0; iteration <= count; iteration++) {
+ const float strength = (iteration != count) ? 1.0f : last;
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ .smooth_mask = smooth_mask,
+ .strength = strength,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+
+ switch (type) {
+ case PBVH_GRIDS:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+ break;
+ case PBVH_FACES:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ break;
+ case PBVH_BMESH:
+ BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
+ break;
+ }
+ }
+}
+
+void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, false);
+}
+
+/* HC Smooth Algorithm. */
+/* From: Improved Laplacian Smoothing of Noisy Surface Meshes */
+
+void SCULPT_surface_smooth_laplacian_step(SculptSession *ss,
+ float *disp,
+ const float co[3],
+ float (*laplacian_disp)[3],
+ const int v_index,
+ 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);
+
+ mul_v3_v3fl(weigthed_o, origco, alpha);
+ mul_v3_v3fl(weigthed_q, co, 1.0f - alpha);
+ add_v3_v3v3(d, weigthed_o, weigthed_q);
+ sub_v3_v3v3(laplacian_disp[v_index], laplacian_smooth_co, d);
+
+ sub_v3_v3v3(disp, laplacian_smooth_co, co);
+}
+
+void SCULPT_surface_smooth_displace_step(SculptSession *ss,
+ float *co,
+ float (*laplacian_disp)[3],
+ const int v_index,
+ const float beta,
+ const float fade)
+{
+ float b_avg[3] = {0.0f, 0.0f, 0.0f};
+ float b_current_vertex[3];
+ int total = 0;
+ SculptVertexNeighborIter ni;
+ SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, v_index, ni) {
+ add_v3_v3(b_avg, laplacian_disp[ni.index]);
+ total++;
+ }
+ SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
+ if (total > 0) {
+ mul_v3_v3fl(b_current_vertex, b_avg, (1.0f - beta) / (float)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));
+ sub_v3_v3(co, b_current_vertex);
+ }
+}
+
+static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+ float alpha = brush->surface_smooth_shape_preservation;
+
+ PBVHVertexIter vd;
+ SculptOrigVertData orig_data;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ 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]);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, 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);
+ madd_v3_v3fl(vd.co, disp, clamp_f(fade, 0.0f, 1.0f));
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+}
+
+static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex(
+ void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ const Brush *brush = data->brush;
+ const float bstrength = ss->cache->bstrength;
+ const float beta = brush->surface_smooth_current_vertex;
+
+ PBVHVertexIter vd;
+
+ SculptBrushTest test;
+ SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape(
+ ss, &test, data->brush->falloff_shape);
+ const int thread_id = BLI_task_parallel_thread_id(tls);
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ if (sculpt_brush_test_sq_fn(&test, vd.co)) {
+ const float fade =
+ bstrength *
+ SCULPT_brush_strength_factor(
+ ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id);
+ SCULPT_surface_smooth_displace_step(
+ ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
+{
+ Brush *brush = BKE_paint_brush(&sd->paint);
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 &&
+ ss->cache->radial_symmetry_pass == 0) {
+ BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL);
+ ss->cache->surface_smooth_laplacian_disp = MEM_callocN(
+ SCULPT_vertex_count_get(ss) * 3 * sizeof(float), "HC smooth laplacian b");
+ }
+
+ /* Threaded loop over nodes. */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .brush = brush,
+ .nodes = nodes,
+ };
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ for (int i = 0; i < brush->surface_smooth_iterations; i++) {
+ BLI_task_parallel_range(
+ 0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings);
+ BLI_task_parallel_range(
+ 0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings);
+ }
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c
new file mode 100644
index 00000000000..2eb1191b950
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/sculpt_transform.c
@@ -0,0 +1,381 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2020 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edsculpt
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_context.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_pbvh.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+
+#include "WM_api.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_sculpt.h"
+#include "paint_intern.h"
+#include "sculpt_intern.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "bmesh.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+void ED_sculpt_init_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+
+ copy_v3_v3(ss->init_pivot_pos, ss->pivot_pos);
+ copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot);
+
+ SCULPT_undo_push_begin("Transform");
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ ss->pivot_rot[3] = 1.0f;
+
+ SCULPT_vertex_random_access_init(ss);
+ SCULPT_filter_cache_init(ob, sd);
+}
+
+static void sculpt_transform_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+
+ SculptOrigVertData orig_data;
+ SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[i]);
+
+ PBVHVertexIter vd;
+
+ SCULPT_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
+ {
+ SCULPT_orig_vert_data_update(&orig_data, &vd);
+ float transformed_co[3], orig_co[3], disp[3];
+ float fade = vd.mask ? *vd.mask : 0.0f;
+ copy_v3_v3(orig_co, orig_data.co);
+ char symm_area = SCULPT_get_vertex_symm_area(orig_co);
+
+ copy_v3_v3(transformed_co, orig_co);
+ mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co);
+ sub_v3_v3v3(disp, transformed_co, orig_co);
+ mul_v3_fl(disp, 1.0f - fade);
+
+ add_v3_v3v3(vd.co, orig_co, disp);
+
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+
+ BKE_pbvh_node_mark_update(node);
+}
+
+void ED_sculpt_update_modal_transform(struct bContext *C)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ SCULPT_vertex_random_access_init(ss);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false);
+
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ };
+
+ float final_pivot_pos[3], d_t[3], d_r[4];
+ float t_mat[4][4], r_mat[4][4], s_mat[4][4], pivot_mat[4][4], pivot_imat[4][4],
+ transform_mat[4][4];
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+ for (int i = 0; i < PAINT_SYMM_AREAS; i++) {
+ ePaintSymmetryAreas v_symm = i;
+
+ copy_v3_v3(final_pivot_pos, ss->pivot_pos);
+
+ unit_m4(pivot_mat);
+
+ unit_m4(t_mat);
+ unit_m4(r_mat);
+ unit_m4(s_mat);
+
+ /* Translation matrix. */
+ sub_v3_v3v3(d_t, ss->pivot_pos, ss->init_pivot_pos);
+ SCULPT_flip_v3_by_symm_area(d_t, symm, v_symm, ss->init_pivot_pos);
+ translate_m4(t_mat, d_t[0], d_t[1], d_t[2]);
+
+ /* Rotation matrix. */
+ sub_qt_qtqt(d_r, ss->pivot_rot, ss->init_pivot_rot);
+ normalize_qt(d_r);
+ SCULPT_flip_quat_by_symm_area(d_r, symm, v_symm, ss->init_pivot_pos);
+ quat_to_mat4(r_mat, d_r);
+
+ /* Scale matrix. */
+ size_to_mat4(s_mat, ss->pivot_scale);
+
+ /* Pivot matrix. */
+ SCULPT_flip_v3_by_symm_area(final_pivot_pos, symm, v_symm, ss->init_pivot_pos);
+ translate_m4(pivot_mat, final_pivot_pos[0], final_pivot_pos[1], final_pivot_pos[2]);
+ invert_m4_m4(pivot_imat, pivot_mat);
+
+ /* Final transform matrix. */
+ mul_m4_m4m4(transform_mat, r_mat, t_mat);
+ mul_m4_m4m4(transform_mat, transform_mat, s_mat);
+ mul_m4_m4m4(data.transform_mats[i], transform_mat, pivot_imat);
+ mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
+ }
+
+ TaskParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(
+ &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode);
+ BLI_task_parallel_range(
+ 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings);
+
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
+ SCULPT_flush_stroke_deform(sd, ob, true);
+ }
+
+ SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS);
+}
+
+void ED_sculpt_end_transform(struct bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ 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 cancelling. */
+ const bool use_nested_undo = true;
+ SCULPT_undo_push_end_ex(use_nested_undo);
+ SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+}
+
+typedef enum eSculptPivotPositionModes {
+ SCULPT_PIVOT_POSITION_ORIGIN = 0,
+ SCULPT_PIVOT_POSITION_UNMASKED = 1,
+ SCULPT_PIVOT_POSITION_MASK_BORDER = 2,
+ SCULPT_PIVOT_POSITION_ACTIVE_VERTEX = 3,
+ SCULPT_PIVOT_POSITION_CURSOR_SURFACE = 4,
+} eSculptPivotPositionModes;
+
+static EnumPropertyItem prop_sculpt_pivot_position_types[] = {
+ {SCULPT_PIVOT_POSITION_ORIGIN,
+ "ORIGIN",
+ 0,
+ "Origin",
+ "Sets the pivot to the origin of the sculpt"},
+ {SCULPT_PIVOT_POSITION_UNMASKED,
+ "UNMASKED",
+ 0,
+ "Unmasked",
+ "Sets the pivot position to the average position of the unmasked vertices"},
+ {SCULPT_PIVOT_POSITION_MASK_BORDER,
+ "BORDER",
+ 0,
+ "Mask border",
+ "Sets the pivot position to the center of the border of the mask"},
+ {SCULPT_PIVOT_POSITION_ACTIVE_VERTEX,
+ "ACTIVE",
+ 0,
+ "Active vertex",
+ "Sets the pivot position to the active vertex position"},
+ {SCULPT_PIVOT_POSITION_CURSOR_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Sets the pivot position to the surface under the cursor"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static int sculpt_set_pivot_position_exec(bContext *C, wmOperator *op)
+{
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ ARegion *region = CTX_wm_region(C);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+
+ int mode = RNA_enum_get(op->ptr, "mode");
+
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
+
+ /* Pivot to center. */
+ if (mode == SCULPT_PIVOT_POSITION_ORIGIN) {
+ zero_v3(ss->pivot_pos);
+ }
+ /* Pivot to active vertex. */
+ else if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
+ copy_v3_v3(ss->pivot_pos, SCULPT_active_vertex_co_get(ss));
+ }
+ /* Pivot to raycast surface. */
+ else if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
+ float stroke_location[3];
+ float mouse[2];
+ mouse[0] = RNA_float_get(op->ptr, "mouse_x");
+ mouse[1] = RNA_float_get(op->ptr, "mouse_y");
+ if (SCULPT_stroke_get_location(C, stroke_location, mouse)) {
+ copy_v3_v3(ss->pivot_pos, stroke_location);
+ }
+ }
+ else {
+ PBVHNode **nodes;
+ int totnode;
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+
+ float avg[3];
+ int total = 0;
+ zero_v3(avg);
+
+ /* Pivot to unmasked. */
+ if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < 1.0f) {
+ if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+ /* Pivot to mask border. */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
+
+ for (int n = 0; n < totnode; n++) {
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
+ const float mask = (vd.mask) ? *vd.mask : 0.0f;
+ if (mask < (0.5f + threshold) && mask > (0.5f - threshold)) {
+ if (SCULPT_check_vertex_pivot_symmetry(vd.co, ss->pivot_pos, symm)) {
+ add_v3_v3(avg, vd.co);
+ total++;
+ }
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+ }
+ }
+
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+
+ MEM_SAFE_FREE(nodes);
+ }
+
+ ED_region_tag_redraw(region);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_float_set(op->ptr, "mouse_x", event->mval[0]);
+ RNA_float_set(op->ptr, "mouse_y", event->mval[1]);
+ return sculpt_set_pivot_position_exec(C, op);
+}
+
+void SCULPT_OT_set_pivot_position(wmOperatorType *ot)
+{
+ /* Identifiers. */
+ ot->name = "Set Pivot Position";
+ ot->idname = "SCULPT_OT_set_pivot_position";
+ ot->description = "Sets the sculpt transform pivot position";
+
+ /* API callbacks. */
+ ot->invoke = sculpt_set_pivot_position_invoke;
+ ot->exec = sculpt_set_pivot_position_exec;
+ ot->poll = SCULPT_mode_poll;
+
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ RNA_def_enum(ot->srna,
+ "mode",
+ prop_sculpt_pivot_position_types,
+ SCULPT_PIVOT_POSITION_UNMASKED,
+ "Mode",
+ "");
+
+ RNA_def_float(ot->srna,
+ "mouse_x",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Mouse Position X",
+ "Position of the mouse used for \"Surface\" mode",
+ 0.0f,
+ 10000.0f);
+ RNA_def_float(ot->srna,
+ "mouse_y",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Mouse Position Y",
+ "Position of the mouse used for \"Surface\" mode",
+ 0.0f,
+ 10000.0f);
+}
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index af404c64fb0..d21552efafe 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
@@ -48,12 +48,16 @@
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
+#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_scene.h"
#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "BKE_undo_system.h"
+// XXX: Ideally should be no direct call to such low level things.
+#include "BKE_subdiv_eval.h"
+
#include "DEG_depsgraph.h"
#include "WM_api.h"
@@ -66,6 +70,45 @@
#include "bmesh.h"
#include "sculpt_intern.h"
+/* Implementation of undo system for objects in sculpt mode.
+ *
+ * Each undo step in sculpt mode consists of list of nodes, each node contains:
+ * - Node type
+ * - Data for this type.
+ *
+ * Node type used for undo depends on specific operation and active sculpt mode
+ * ("regular" or dynamic topology).
+ *
+ * Regular sculpt brushes will use COORDS, HIDDEN or MASK nodes. These nodes are
+ * created for every BVH node which is affected by the brush. The undo push for
+ * the node happens BEFORE modifications. This makes the operation undo to work
+ * in the following way: for every node in the undo step swap happens between
+ * node in the undo stack and the corresponding value in the BVH. This is how
+ * redo is possible after undo.
+ *
+ * The COORDS, HIDDEN or MASK type of nodes contains arrays of the corresponding
+ * values.
+ *
+ * Operations like Symmetrize are using GEOMETRY type of nodes which pushes the
+ * entire state of the mesh to the undo stack. This node contains all CustomData
+ * layers.
+ *
+ * The tricky aspect of this undo node type is that it stores mesh before and
+ * after modification. This allows the undo system to both undo and redo the
+ * symmetrize operation within the pre-modified-push of other node type
+ * behavior, but it uses more memory that it seems it should be.
+ *
+ * The dynamic topology undo nodes are handled somewhat separately from all
+ * other ones and the idea there is to store log of operations: which vertices
+ * and faces have been added or removed.
+ *
+ * Begin of dynamic topology sculpting mode have own node type. It contains an
+ * entire copy of mesh since just enabling the dynamic topology mode already
+ * does modifications on it.
+ *
+ * End of dynamic topology and symmetrize in this mode are handled in a special
+ * manner as well. */
+
typedef struct UndoSculpt {
ListBase nodes;
@@ -335,8 +378,11 @@ static bool sculpt_undo_restore_face_sets(bContext *C, SculptUndoNode *unode)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- SculptSession *ss = ob->sculpt;
- memcpy(ss->face_sets, unode->face_sets, ss->totpoly * sizeof(int));
+ 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++) {
+ face_sets[i] = unode->face_sets[i];
+ }
return false;
}
@@ -369,9 +415,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- PBVHParallelSettings settings;
+ TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BKE_pbvh_parallel_range(
+ BLI_task_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
if (nodes) {
@@ -379,7 +425,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
}
}
else {
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
}
}
@@ -389,7 +435,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
SculptSession *ss = ob->sculpt;
Mesh *me = ob->data;
- sculpt_pbvh_clear(ob);
+ SCULPT_pbvh_clear(ob);
/* Create empty BMesh and enable logging. */
ss->bm = BM_mesh_create(&bm_mesh_allocsize_default,
@@ -397,7 +443,7 @@ static void sculpt_undo_bmesh_enable(Object *ob, SculptUndoNode *unode)
.use_toolflags = false,
}));
BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK);
- sculpt_dyntopo_node_layers_add(ss);
+ SCULPT_dyntopo_node_layers_add(ss);
me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY;
/* Restore the BMLog using saved entries. */
@@ -410,7 +456,7 @@ static void sculpt_undo_bmesh_restore_begin(bContext *C,
SculptSession *ss)
{
if (unode->applied) {
- sculpt_dynamic_topology_disable(C, unode);
+ SCULPT_dynamic_topology_disable(C, unode);
unode->applied = false;
}
else {
@@ -438,35 +484,89 @@ static void sculpt_undo_bmesh_restore_end(bContext *C,
}
else {
/* Disable dynamic topology sculpting. */
- sculpt_dynamic_topology_disable(C, NULL);
+ SCULPT_dynamic_topology_disable(C, NULL);
unode->applied = true;
}
}
-static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *ob)
+static void sculpt_undo_geometry_store_data(SculptUndoNodeGeometry *geometry, Object *object)
{
- Mesh *me;
- sculpt_pbvh_clear(ob);
- me = ob->data;
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
- CustomData_free(&me->ldata, me->totloop);
- CustomData_free(&me->pdata, me->totpoly);
- me->totvert = unode->geom_totvert;
- me->totedge = unode->geom_totedge;
- me->totloop = unode->geom_totloop;
- me->totpoly = unode->geom_totpoly;
- me->totface = 0;
+ Mesh *mesh = object->data;
+
+ BLI_assert(!geometry->is_initialized);
+ geometry->is_initialized = true;
+
+ CustomData_copy(&mesh->vdata, &geometry->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
+ CustomData_copy(&mesh->edata, &geometry->edata, CD_MASK_MESH.emask, CD_DUPLICATE, mesh->totedge);
+ CustomData_copy(&mesh->ldata, &geometry->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, mesh->totloop);
+ CustomData_copy(&mesh->pdata, &geometry->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, mesh->totpoly);
+
+ geometry->totvert = mesh->totvert;
+ geometry->totedge = mesh->totedge;
+ geometry->totloop = mesh->totloop;
+ geometry->totpoly = mesh->totpoly;
+}
+
+static void sculpt_undo_geometry_restore_data(SculptUndoNodeGeometry *geometry, Object *object)
+{
+ Mesh *mesh = object->data;
+
+ BLI_assert(geometry->is_initialized);
+
+ CustomData_free(&mesh->vdata, mesh->totvert);
+ CustomData_free(&mesh->edata, mesh->totedge);
+ CustomData_free(&mesh->fdata, mesh->totface);
+ CustomData_free(&mesh->ldata, mesh->totloop);
+ CustomData_free(&mesh->pdata, mesh->totpoly);
+
+ mesh->totvert = geometry->totvert;
+ mesh->totedge = geometry->totedge;
+ mesh->totloop = geometry->totloop;
+ mesh->totpoly = geometry->totpoly;
+ mesh->totface = 0;
+
CustomData_copy(
- &unode->geom_vdata, &me->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, unode->geom_totvert);
+ &geometry->vdata, &mesh->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, geometry->totvert);
CustomData_copy(
- &unode->geom_edata, &me->edata, CD_MASK_MESH.emask, CD_DUPLICATE, unode->geom_totedge);
+ &geometry->edata, &mesh->edata, CD_MASK_MESH.emask, CD_DUPLICATE, geometry->totedge);
CustomData_copy(
- &unode->geom_ldata, &me->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, unode->geom_totloop);
+ &geometry->ldata, &mesh->ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, geometry->totloop);
CustomData_copy(
- &unode->geom_pdata, &me->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, unode->geom_totpoly);
- BKE_mesh_update_customdata_pointers(me, false);
+ &geometry->pdata, &mesh->pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, geometry->totpoly);
+
+ BKE_mesh_update_customdata_pointers(mesh, false);
+}
+
+static void sculpt_undo_geometry_free_data(SculptUndoNodeGeometry *geometry)
+{
+ if (geometry->totvert) {
+ CustomData_free(&geometry->vdata, geometry->totvert);
+ }
+ if (geometry->totedge) {
+ CustomData_free(&geometry->edata, geometry->totedge);
+ }
+ if (geometry->totloop) {
+ CustomData_free(&geometry->ldata, geometry->totloop);
+ }
+ if (geometry->totpoly) {
+ CustomData_free(&geometry->pdata, geometry->totpoly);
+ }
+}
+
+static void sculpt_undo_geometry_restore(SculptUndoNode *unode, Object *object)
+{
+ if (unode->geometry_clear_pbvh) {
+ SCULPT_pbvh_clear(object);
+ }
+
+ if (unode->applied) {
+ sculpt_undo_geometry_restore_data(&unode->geometry_modified, object);
+ unode->applied = false;
+ }
+ else {
+ sculpt_undo_geometry_restore_data(&unode->geometry_original, object);
+ unode->applied = true;
+ }
}
/* Handle all dynamic-topology updates
@@ -527,22 +627,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
if (lb->first) {
unode = lb->first;
- if (unode->type == SCULPT_UNDO_GEOMETRY) {
- if (unode->applied) {
- sculpt_undo_geometry_restore(unode->next, ob);
- unode->next->applied = true;
- unode->applied = false;
- }
- else {
- sculpt_undo_geometry_restore(unode, ob);
- unode->next->applied = false;
- unode->applied = true;
- }
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
- return;
- }
- else if (unode->type == SCULPT_UNDO_FACE_SETS) {
-
+ if (unode->type == SCULPT_UNDO_FACE_SETS) {
sculpt_undo_restore_face_sets(C, unode);
rebuild = true;
@@ -551,14 +636,15 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, need_mask);
SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
+
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
BKE_mesh_flush_hidden_from_verts(ob->data);
}
+ DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
- DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
}
@@ -567,10 +653,18 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
- BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ if (lb->first != NULL) {
+ /* Only do early object update for edits if first node needs this.
+ * Undo steps like geometry does not need object to be updated before they run and will
+ * ensure object is updated after the node is handled. */
+ const SculptUndoNode *first_unode = (const SculptUndoNode *)lb->first;
+ if (first_unode->type != SCULPT_UNDO_GEOMETRY) {
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ }
- if (lb->first && sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
- return;
+ if (sculpt_undo_bmesh_restore(C, lb->first, ob, ss)) {
+ return;
+ }
}
char *undo_modified_grids = NULL;
@@ -619,28 +713,42 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_FACE_SETS:
break;
+ case SCULPT_UNDO_GEOMETRY:
+ sculpt_undo_geometry_restore(unode, ob);
+ BKE_sculpt_update_object_for_edit(depsgraph, ob, false, need_mask);
+ break;
+
case SCULPT_UNDO_DYNTOPO_BEGIN:
case SCULPT_UNDO_DYNTOPO_END:
case SCULPT_UNDO_DYNTOPO_SYMMETRIZE:
BLI_assert(!"Dynamic topology should've already been handled");
break;
- case SCULPT_UNDO_GEOMETRY:
- break;
}
}
if (use_multires_undo) {
- int max_grid;
- unode = lb->first;
- max_grid = unode->maxgrid;
- undo_modified_grids = MEM_callocN(sizeof(char) * max_grid, "undo_grids");
for (unode = lb->first; unode; unode = unode->next) {
+ if (!STREQ(unode->idname, ob->id.name)) {
+ continue;
+ }
+ if (unode->maxgrid == 0) {
+ continue;
+ }
+
+ if (undo_modified_grids == NULL) {
+ undo_modified_grids = MEM_callocN(sizeof(char) * unode->maxgrid, "undo_grids");
+ }
+
for (int i = 0; i < unode->totgrid; i++) {
undo_modified_grids[unode->grids[i]] = 1;
}
}
}
+ if (subdiv_ccg != NULL) {
+ BKE_subdiv_eval_refine_from_mesh(subdiv_ccg->subdiv, ob->data, NULL);
+ }
+
if (update || rebuild) {
bool tag_update = false;
/* We update all nodes still, should be more clever, but also
@@ -737,18 +845,9 @@ static void sculpt_undo_free_list(ListBase *lb)
BM_log_entry_drop(unode->bm_entry);
}
- if (unode->geom_totvert) {
- CustomData_free(&unode->geom_vdata, unode->geom_totvert);
- }
- if (unode->geom_totedge) {
- CustomData_free(&unode->geom_edata, unode->geom_totedge);
- }
- if (unode->geom_totloop) {
- CustomData_free(&unode->geom_ldata, unode->geom_totloop);
- }
- if (unode->geom_totpoly) {
- CustomData_free(&unode->geom_pdata, unode->geom_totpoly);
- }
+ sculpt_undo_geometry_free_data(&unode->geometry_original);
+ sculpt_undo_geometry_free_data(&unode->geometry_modified);
+ sculpt_undo_geometry_free_data(&unode->geometry_bmesh_enter);
if (unode->face_sets) {
MEM_freeN(unode->face_sets);
@@ -794,6 +893,17 @@ SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node)
return BLI_findptr(&usculpt->nodes, node, offsetof(SculptUndoNode, node));
}
+SculptUndoNode *SCULPT_undo_get_first_node()
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+
+ if (usculpt == NULL) {
+ return NULL;
+ }
+
+ return usculpt->nodes.first;
+}
+
static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode)
{
PBVHNode *node = unode->node;
@@ -804,7 +914,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL);
- unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
+ unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden");
for (i = 0; i < totgrid; i++) {
if (grid_hidden[grid_indices[i]]) {
@@ -816,16 +926,43 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode
}
}
+/* Allocate node and initialize its default fields specific for the given undo type.
+ * Will also add the node to the list in the undo step. */
+static SculptUndoNode *sculpt_undo_alloc_node_type(Object *object, SculptUndoType type)
+{
+ SculptUndoNode *unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
+ BLI_strncpy(unode->idname, object->id.name, sizeof(unode->idname));
+ unode->type = type;
+
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+ BLI_addtail(&usculpt->nodes, unode);
+
+ return unode;
+}
+
+/* Will return first existing undo node of the given type.
+ * If such node does not exist will allocate node of this type, register it in the undo step and
+ * return it. */
+static SculptUndoNode *sculpt_undo_find_or_alloc_node_type(Object *object, SculptUndoType type)
+{
+ UndoSculpt *usculpt = sculpt_undo_get_nodes();
+
+ LISTBASE_FOREACH (SculptUndoNode *, unode, &usculpt->nodes) {
+ if (unode->type == type) {
+ return unode;
+ }
+ }
+
+ return sculpt_undo_alloc_node_type(object, type);
+}
+
static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptUndoNode *unode;
SculptSession *ss = ob->sculpt;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
- unode = MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
+ SculptUndoNode *unode = sculpt_undo_alloc_node_type(ob, type);
unode->node = node;
if (node) {
@@ -838,13 +975,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
maxgrid = 0;
}
- /* We will use this while sculpting, is mapalloc slow to access then? */
-
/* General TODO, fix count_alloc. */
switch (type) {
case SCULPT_UNDO_COORDS:
- unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
- unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
+ unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co");
+ unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no");
usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert;
break;
@@ -858,7 +993,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
case SCULPT_UNDO_MASK:
- unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask");
+ unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask");
usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert;
@@ -872,19 +1007,17 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
break;
}
- BLI_addtail(&usculpt->nodes, unode);
-
if (maxgrid) {
/* Multires. */
unode->maxgrid = maxgrid;
unode->totgrid = totgrid;
unode->gridsize = gridsize;
- unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
+ unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids");
}
else {
/* Regular mesh. */
unode->maxvert = ss->totvert;
- unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
+ unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index");
}
if (ss->deform_modifiers_active) {
@@ -950,32 +1083,25 @@ static void sculpt_undo_store_mask(Object *ob, SculptUndoNode *unode)
BKE_pbvh_vertex_iter_end;
}
-static SculptUndoNode *sculpt_undo_geometry_push(Object *ob, SculptUndoType type)
+static SculptUndoNodeGeometry *sculpt_undo_geometry_get(SculptUndoNode *unode)
{
- UndoSculpt *usculpt = sculpt_undo_get_nodes();
- Mesh *me = ob->data;
- bool applied;
-
- SculptUndoNode *unode = usculpt->nodes.first;
- /* Store the original mesh in the first node, modifications in the second. */
- applied = unode != NULL;
+ if (!unode->geometry_original.is_initialized) {
+ return &unode->geometry_original;
+ }
- unode = MEM_callocN(sizeof(*unode), __func__);
+ BLI_assert(!unode->geometry_modified.is_initialized);
- BLI_strncpy(unode->idname, ob->id.name, sizeof(unode->idname));
- unode->type = type;
- unode->applied = applied;
+ return &unode->geometry_modified;
+}
- CustomData_copy(&me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
- CustomData_copy(&me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
- CustomData_copy(&me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
- CustomData_copy(&me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
- unode->geom_totvert = me->totvert;
- unode->geom_totedge = me->totedge;
- unode->geom_totloop = me->totloop;
- unode->geom_totpoly = me->totpoly;
+static SculptUndoNode *sculpt_undo_geometry_push(Object *object, SculptUndoType type)
+{
+ SculptUndoNode *unode = sculpt_undo_find_or_alloc_node_type(object, type);
+ unode->applied = false;
+ unode->geometry_clear_pbvh = true;
- BLI_addtail(&usculpt->nodes, unode);
+ SculptUndoNodeGeometry *geometry = sculpt_undo_geometry_get(unode);
+ sculpt_undo_geometry_store_data(geometry, object);
return unode;
}
@@ -983,8 +1109,6 @@ static SculptUndoNode *sculpt_undo_geometry_push(Object *ob, SculptUndoType type
static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType type)
{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
- SculptSession *ss = ob->sculpt;
-
SculptUndoNode *unode = usculpt->nodes.first;
unode = MEM_callocN(sizeof(*unode), __func__);
@@ -993,8 +1117,14 @@ static SculptUndoNode *sculpt_undo_face_sets_push(Object *ob, SculptUndoType typ
unode->type = type;
unode->applied = true;
- unode->face_sets = MEM_callocN(ss->totpoly * sizeof(int), "sculpt face sets");
- memcpy(unode->face_sets, ss->face_sets, ss->totpoly * sizeof(int));
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ unode->face_sets = MEM_callocN(me->totpoly * sizeof(int), "sculpt face sets");
+
+ int *face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS);
+ for (int i = 0; i < me->totpoly; i++) {
+ unode->face_sets[i] = face_sets[i];
+ }
BLI_addtail(&usculpt->nodes, unode);
@@ -1021,25 +1151,13 @@ static SculptUndoNode *sculpt_undo_bmesh_push(Object *ob, PBVHNode *node, Sculpt
BM_log_before_all_removed(ss->bm, ss->bm_log);
}
else if (type == SCULPT_UNDO_DYNTOPO_BEGIN) {
- Mesh *me = ob->data;
-
/* Store a copy of the mesh's current vertices, loops, and
* polys. A full copy like this is needed because entering
* dynamic-topology immediately does topological edits
* (converting polys to triangles) that the BMLog can't
* fully restore from. */
- CustomData_copy(
- &me->vdata, &unode->geom_vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, me->totvert);
- CustomData_copy(
- &me->edata, &unode->geom_edata, CD_MASK_MESH.emask, CD_DUPLICATE, me->totedge);
- CustomData_copy(
- &me->ldata, &unode->geom_ldata, CD_MASK_MESH.lmask, CD_DUPLICATE, me->totloop);
- CustomData_copy(
- &me->pdata, &unode->geom_pdata, CD_MASK_MESH.pmask, CD_DUPLICATE, me->totpoly);
- unode->geom_totvert = me->totvert;
- unode->geom_totedge = me->totedge;
- unode->geom_totloop = me->totloop;
- unode->geom_totpoly = me->totpoly;
+ SculptUndoNodeGeometry *geometry = &unode->geometry_bmesh_enter;
+ sculpt_undo_geometry_store_data(geometry, ob);
unode->bm_entry = BM_log_entry_add(ss->bm_log);
BM_log_all_added(ss->bm, ss->bm_log);
@@ -1192,6 +1310,11 @@ void SCULPT_undo_push_begin(const char *name)
void SCULPT_undo_push_end(void)
{
+ SCULPT_undo_push_end_ex(false);
+}
+
+void SCULPT_undo_push_end_ex(const bool use_nested_undo)
+{
UndoSculpt *usculpt = sculpt_undo_get_nodes();
SculptUndoNode *unode;
@@ -1201,17 +1324,16 @@ void SCULPT_undo_push_end(void)
MEM_freeN(unode->no);
unode->no = NULL;
}
-
- if (unode->node) {
- BKE_pbvh_node_layer_disp_free(unode->node);
- }
}
/* We could remove this and enforce all callers run in an operator using 'OPTYPE_UNDO'. */
wmWindowManager *wm = G_MAIN->wm.first;
- if (wm->op_undo_depth == 0) {
+ if (wm->op_undo_depth == 0 || use_nested_undo) {
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ if (wm->op_undo_depth == 0) {
+ BKE_undosys_stack_limit_steps_and_memory_defaults(ustack);
+ }
WM_file_tag_modified();
}
}
@@ -1407,3 +1529,96 @@ static UndoSculpt *sculpt_undo_get_nodes(void)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Undo for changes happening on a base mesh for multires sculpting.
+ *
+ * Use this for multires operators which changes base mesh and which are to be
+ * possible. Example of such operators is Apply Base.
+ *
+ * Usage:
+ *
+ * static int operator_exec((bContext *C, wmOperator *op) {
+ *
+ * ED_sculpt_undo_push_mixed_begin(C, op->type->name);
+ * // Modify base mesh.
+ * ED_sculpt_undo_push_mixed_end(C, op->type->name);
+ *
+ * return OPERATOR_FINISHED;
+ * }
+ *
+ * If object is not in sculpt mode or sculpt does not happen on multires then
+ * regular ED_undo_push() is used.
+ * *
+ * \{ */
+
+static bool sculpt_undo_use_multires_mesh(bContext *C)
+{
+ if (BKE_paintmode_get_active_from_context(C) != PAINT_MODE_SCULPT) {
+ return false;
+ }
+
+ Object *object = CTX_data_active_object(C);
+ SculptSession *sculpt_session = object->sculpt;
+
+ return sculpt_session->multires.active;
+}
+
+static void sculpt_undo_push_all_grids(Object *object)
+{
+ SculptSession *ss = object->sculpt;
+
+ /* It is possible that undo push is done from an object state where there is no PBVH. This
+ * happens, for example, when an operation which tagged for geometry update was performed prior
+ * to the current operation without making any stroke in between.
+ *
+ * Skip pushing nodes based on the following logic: on redo SCULPT_UNDO_COORDS will ensure
+ * PBVH for the new base geometry, which will have same coordinates as if we create PBVH here. */
+ if (ss->pbvh == NULL) {
+ return;
+ }
+
+ PBVHNode **nodes;
+ int totnodes;
+
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnodes);
+ for (int i = 0; i < totnodes; i++) {
+ SculptUndoNode *unode = SCULPT_undo_push_node(object, nodes[i], SCULPT_UNDO_COORDS);
+ unode->node = NULL;
+ }
+
+ MEM_SAFE_FREE(nodes);
+}
+
+void ED_sculpt_undo_push_multires_mesh_begin(bContext *C, const char *str)
+{
+ if (!sculpt_undo_use_multires_mesh(C)) {
+ return;
+ }
+
+ Object *object = CTX_data_active_object(C);
+
+ SCULPT_undo_push_begin(str);
+
+ SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
+ geometry_unode->geometry_clear_pbvh = false;
+
+ sculpt_undo_push_all_grids(object);
+}
+
+void ED_sculpt_undo_push_multires_mesh_end(bContext *C, const char *str)
+{
+ if (!sculpt_undo_use_multires_mesh(C)) {
+ ED_undo_push(C, str);
+ return;
+ }
+
+ Object *object = CTX_data_active_object(C);
+
+ SculptUndoNode *geometry_unode = SCULPT_undo_push_node(object, NULL, SCULPT_UNDO_GEOMETRY);
+ geometry_unode->geometry_clear_pbvh = false;
+
+ SCULPT_undo_push_end();
+}
+
+/** \} */
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index f364c174f0f..d6b259c9ac0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -10,7 +10,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
+ * along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) Blender Foundation, 2002-2009
@@ -70,8 +70,8 @@ typedef struct UvAdjacencyElement {
} UvAdjacencyElement;
typedef struct UvEdge {
- unsigned int uv1;
- unsigned int uv2;
+ uint uv1;
+ uint uv2;
/* general use flag
* (Used to check if edge is boundary here, and propagates to adjacency elements) */
char flag;
@@ -315,7 +315,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
Scene *scene = CTX_data_scene(C);
ARegion *region = CTX_wm_region(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- unsigned int tool;
+ uint tool;
UvSculptData *sculptdata = (UvSculptData *)op->customdata;
SpaceImage *sima;
int invert;
@@ -386,7 +386,7 @@ static void uv_sculpt_stroke_apply(bContext *C,
* Smooth Tool
*/
else if (tool == UV_SCULPT_TOOL_RELAX) {
- unsigned int method = toolsettings->uv_relax_method;
+ uint method = toolsettings->uv_relax_method;
if (method == UV_SCULPT_TOOL_RELAX_HC) {
HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
}
@@ -464,7 +464,7 @@ static int uv_element_offset_from_face_get(
return element - map->buf;
}
-static unsigned int uv_edge_hash(const void *key)
+static uint uv_edge_hash(const void *key)
{
const UvEdge *edge = key;
return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
@@ -548,8 +548,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
if (do_island_optimization) {
UvElement *element;
UvNearestHit hit = UV_NEAREST_HIT_INIT;
- Image *ima = CTX_data_edit_image(C);
- uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
+ uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit);
element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
island_index = element->island;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index e6e36309fec..81ac8a16d8a 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -206,7 +206,7 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
static void sound_update_animation_flags(Scene *scene);
-static int sound_update_animation_flags_cb(Sequence *seq, void *user_data)
+static int sound_update_animation_flags_fn(Sequence *seq, void *user_data)
{
struct FCurve *fcu;
Scene *scene = (Scene *)user_data;
@@ -258,7 +258,7 @@ static void sound_update_animation_flags(Scene *scene)
scene->id.tag |= LIB_TAG_DOIT;
SEQ_BEGIN (scene->ed, seq) {
- BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_cb, scene);
+ BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_fn, scene);
}
SEQ_END;
diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c
index 6c2cee4042b..b5a0c4a9e22 100644
--- a/source/blender/editors/space_action/action_data.c
+++ b/source/blender/editors/space_action/action_data.c
@@ -42,7 +42,6 @@
#include "RNA_enum_types.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_key.h"
@@ -100,7 +99,7 @@ AnimData *ED_actedit_animdata_from_context(bContext *C)
/* Create new action */
static bAction *action_create_new(bContext *C, bAction *oldact)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bAction *action;
/* create action - the way to do this depends on whether we've got an
@@ -124,8 +123,8 @@ static bAction *action_create_new(bContext *C, bAction *oldact)
id_us_min(&action->id);
/* set ID-Root type */
- if (sa->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ if (area->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
if (saction->mode == SACTCONT_SHAPEKEY) {
action->idroot = ID_KE;
@@ -165,13 +164,13 @@ static void actedit_change_action(bContext *C, bAction *act)
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
* OR
* The NLA Editor is active (i.e. Animation Data panel -> new action)
- * 2) The associated AnimData block must not be in tweakmode
+ * 2) The associated AnimData block must not be in tweak-mode.
*/
static bool action_new_poll(bContext *C)
{
Scene *scene = CTX_data_scene(C);
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
/* NOTE: unlike for pushdown,
* this operator needs to be run when creating an action from nothing... */
if (ED_operator_action_active(C)) {
@@ -301,7 +300,7 @@ void ACTION_OT_new(wmOperatorType *ot)
/* Criteria:
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
* 2) There must be an action active
- * 3) The associated AnimData block must not be in tweakmode
+ * 3) The associated AnimData block must not be in tweak-mode
*/
static bool action_pushdown_poll(bContext *C)
{
@@ -309,7 +308,7 @@ static bool action_pushdown_poll(bContext *C)
SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
AnimData *adt = ED_actedit_animdata_from_context(C);
- /* Check for AnimData, Actions, and that tweakmode is off */
+ /* Check for AnimData, Actions, and that tweak-mode is off. */
if (adt && saction->action) {
/* NOTE: We check this for the AnimData block in question and not the global flag,
* as the global flag may be left dirty by some of the browsing ops here.
@@ -331,9 +330,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op)
/* Do the deed... */
if (adt) {
- /* Perform the pushdown operation
- * - This will deal with all the AnimData-side usercounts
- */
+ /* Perform the push-down operation
+ * - This will deal with all the AnimData-side user-counts. */
if (action_has_motion(adt->action) == 0) {
/* action may not be suitable... */
BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
@@ -390,7 +388,7 @@ static int action_stash_exec(bContext *C, wmOperator *op)
if (BKE_nla_action_stash(adt)) {
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
+ * the user-count fixes. Hence, we must unset this ref
* first before setting the new action.
*/
saction->action = NULL;
@@ -436,14 +434,14 @@ void ACTION_OT_stash(wmOperatorType *ot)
/* Criteria:
* 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions
- * 2) The associated AnimData block must not be in tweakmode
+ * 2) The associated AnimData block must not be in tweak-mode
*/
static bool action_stash_create_poll(bContext *C)
{
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
- /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+ /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */
/* NOTE: unlike for pushdown,
* this operator needs to be run when creating an action from nothing... */
if (adt) {
@@ -499,7 +497,7 @@ static int action_stash_create_exec(bContext *C, wmOperator *op)
/* The stash operation will remove the user already,
* so the flushing step later shouldn't double up
- * the usercount fixes. Hence, we must unset this ref
+ * the user-count fixes. Hence, we must unset this ref
* first before setting the new action.
*/
saction->action = NULL;
@@ -550,7 +548,7 @@ void ACTION_OT_stash_and_create(wmOperatorType *ot)
void ED_animedit_unlink_action(
bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* If the old action only has a single user (that it's about to lose),
* warn user about it
@@ -609,13 +607,13 @@ void ED_animedit_unlink_action(
BKE_nla_tweakmode_exit(adt);
/* Flush this to the Action Editor (if that's where this change was initiated) */
- if (sa->spacetype == SPACE_ACTION) {
+ if (area->spacetype == SPACE_ACTION) {
actedit_change_action(C, NULL);
}
}
else {
/* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
- if (sa->spacetype == SPACE_ACTION) {
+ if (area->spacetype == SPACE_ACTION) {
/* clear action editor -> action */
actedit_change_action(C, NULL);
}
@@ -729,8 +727,8 @@ static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
static void action_layer_switch_strip(
AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip)
{
- /* Exit tweakmode on old strip
- * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
+ /* Exit tweak-mode on old strip
+ * NOTE: We need to manually clear this stuff ourselves, as tweak-mode exit doesn't do it
*/
BKE_nla_tweakmode_exit(adt);
@@ -762,11 +760,11 @@ static void action_layer_switch_strip(
adt->flag |= ADT_NLA_SOLO_TRACK;
nlt->flag |= NLATRACK_SOLO;
- // TODO: Needs restpose flushing (when we get reference track)
+ // TODO: Needs rest-pose flushing (when we get reference track)
}
}
- /* Enter tweakmode again - hopefully we're now "it" */
+ /* Enter tweak-mode again - hopefully we're now "it" */
BKE_nla_tweakmode_enter(adt);
BLI_assert(adt->actstrip == strip);
}
@@ -779,7 +777,7 @@ static bool action_layer_next_poll(bContext *C)
if (ED_operator_action_active(C)) {
AnimData *adt = ED_actedit_animdata_from_context(C);
if (adt) {
- /* only allow if we're in tweakmode, and there's something above us... */
+ /* only allow if we're in tweak-mode, and there's something above us... */
if (adt->flag & ADT_NLA_EDIT_ON) {
/* We need to check if there are any tracks above the active one
* since the track the action comes from is not stored in AnimData
@@ -841,7 +839,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
}
else {
/* No more actions (strips) - Go back to editing the original active action
- * NOTE: This will mean exiting tweakmode...
+ * NOTE: This will mean exiting tweak-mode...
*/
BKE_nla_tweakmode_exit(adt);
@@ -856,13 +854,12 @@ static int action_layer_next_exec(bContext *C, wmOperator *op)
/* turn on NLA muting (to keep same effect) */
adt->flag |= ADT_NLA_EVAL_OFF;
- // TODO: Needs restpose flushing (when we get reference track)
+ // TODO: Needs rest-pose flushing (when we get reference track)
}
}
/* Update the action that this editor now uses
- * NOTE: The calls above have already handled the usercount/animdata side of things
- */
+ * NOTE: The calls above have already handled the user-count/anim-data side of things. */
actedit_change_action(C, adt->action);
return OPERATOR_FINISHED;
}
@@ -961,8 +958,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op)
}
/* Update the action that this editor now uses
- * NOTE: The calls above have already handled the usercount/animdata side of things
- */
+ * NOTE: The calls above have already handled the user-count/animdata side of things. */
actedit_change_action(C, adt->action);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index 75eeb125609..52287b07b28 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -81,7 +81,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region)
v2d->tot.ymin = -height;
/* need to do a view-sync here, so that the keys area doesn't jump around (it must copy this) */
- UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, ac->area, v2d, V2D_LOCK_COPY);
/* loop through channels, and set up drawing depending on their type */
{ /* first pass: just the standard GL-drawing for backdrop + text */
@@ -141,9 +141,9 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
bDopeSheet *ads = &saction->ads;
AnimData *adt = NULL;
- unsigned char col1[4], col2[4];
- unsigned char col1a[4], col2a[4];
- unsigned char col1b[4], col2b[4];
+ uchar col1[4], col2[4];
+ uchar col1a[4], col2a[4];
+ uchar col1b[4], col2b[4];
const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS);
@@ -212,10 +212,10 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
bActionGroup *agrp = ale->data;
if (show_group_colors && agrp->customCol) {
if (sel) {
- immUniformColor3ubvAlpha((unsigned char *)agrp->cs.select, col1a[3]);
+ immUniformColor3ubvAlpha((uchar *)agrp->cs.select, col1a[3]);
}
else {
- immUniformColor3ubvAlpha((unsigned char *)agrp->cs.solid, col2a[3]);
+ immUniformColor3ubvAlpha((uchar *)agrp->cs.solid, col2a[3]);
}
}
else {
@@ -226,8 +226,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
case ANIMTYPE_FCURVE: {
FCurve *fcu = ale->data;
if (show_group_colors && fcu->grp && fcu->grp->customCol) {
- immUniformColor3ubvAlpha((unsigned char *)fcu->grp->cs.active,
- sel ? col1[3] : col2[3]);
+ immUniformColor3ubvAlpha((uchar *)fcu->grp->cs.active, sel ? col1[3] : col2[3]);
}
else {
immUniformColor4ubv(sel ? col1 : col2);
@@ -243,8 +242,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
immRectf(pos, v2d->cur.xmin, ymin, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymax);
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
- unsigned char *color;
- unsigned char gpl_col[4];
+ uchar *color;
+ uchar gpl_col[4];
if ((show_group_colors) && (ale->type == ANIMTYPE_GPLAYER)) {
bGPDlayer *gpl = (bGPDlayer *)ale->data;
rgb_float_to_uchar(gpl_col, gpl->color);
@@ -266,7 +265,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region
else if (ac->datatype == ANIMCONT_MASK) {
/* TODO --- this is a copy of gpencil */
/* frames less than one get less saturated background */
- unsigned char *color = sel ? col1 : col2;
+ uchar *color = sel ? col1 : col2;
immUniformColor4ubv(color);
immRectf(pos, 0.0f, ymin, v2d->cur.xmin, ymax);
@@ -562,7 +561,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene)
/* Iterate over pointcaches on the active object, and draw each one's range. */
float y_offset = 0.0f;
const float cache_draw_height = 4.0f * UI_DPI_FAC * U.pixelsize;
- for (PTCacheID *pid = pidlist.first; pid; pid = pid->next) {
+ LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) {
if (timeline_cache_is_hidden_by_setting(saction, pid)) {
continue;
}
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 927e51a3e04..b390e4b56d6 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -218,7 +218,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
float tmin, tmax;
/* get range and apply necessary scaling before processing */
- if (calc_fcurve_range(fcu, &tmin, &tmax, onlySel, false)) {
+ if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel, false)) {
if (adt) {
tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
@@ -313,8 +313,8 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot)
/**
* Find the extents of the active channel
*
- * \param[out] min Bottom y-extent of channel
- * \param[out] max Top y-extent of channel
+ * \param[out] min: Bottom y-extent of channel
+ * \param[out] max: Top y-extent of channel
* \return Success of finding a selected channel
*/
static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
@@ -448,7 +448,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
void ACTION_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "ACTION_OT_view_all";
ot->description = "Reset viewable area to show full keyframe range";
@@ -490,7 +490,7 @@ void ACTION_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "ACTION_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = actkeys_view_frame_exec;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 173c2f1b5dc..bbb68f632fb 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -437,7 +437,7 @@ static void box_select_elem(
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
- for (bAnimListElem *ale2 = anim_data.first; ale2; ale2 = ale2->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
box_select_elem(sel_data, ale2, xmin, xmax, true);
}
@@ -675,7 +675,7 @@ static void region_select_elem(RegionSelectData *sel_data, bAnimListElem *ale, b
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac->data, ac->datatype);
- for (bAnimListElem *ale2 = anim_data.first; ale2; ale2 = ale2->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale2, &anim_data) {
region_select_elem(sel_data, ale2, true);
}
@@ -793,8 +793,8 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -805,13 +805,13 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 64c81797bb4..e92ea906237 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -60,7 +60,7 @@
/* ******************** default callbacks for action space ***************** */
-static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *action_new(const ScrArea *area, const Scene *scene)
{
SpaceAction *saction;
ARegion *region;
@@ -113,7 +113,7 @@ static SpaceLink *action_new(const ScrArea *sa, const Scene *scene)
region->regiontype = RGN_TYPE_WINDOW;
region->v2d.tot.xmin = (float)(SFRA - 10);
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
region->v2d.tot.xmax = (float)(EFRA + 10);
region->v2d.tot.ymax = 0.0f;
@@ -144,9 +144,9 @@ static void action_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void action_init(struct wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceAction *saction = sa->spacedata.first;
+ SpaceAction *saction = area->spacedata.first;
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
}
@@ -301,7 +301,7 @@ static void action_header_region_draw(const bContext *C, ARegion *region)
}
static void action_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -355,12 +355,12 @@ static void saction_channel_region_message_subscribe(const struct bContext *UNUS
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -397,7 +397,7 @@ static void saction_channel_region_message_subscribe(const struct bContext *UNUS
}
static void action_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -459,12 +459,12 @@ static void saction_main_region_message_subscribe(const struct bContext *C,
struct WorkSpace *workspace,
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -497,16 +497,16 @@ static void saction_main_region_message_subscribe(const struct bContext *C,
}
/* Now run the general "channels region" one - since channels and main should be in sync */
- saction_channel_region_message_subscribe(C, workspace, scene, screen, sa, region, mbus);
+ saction_channel_region_message_subscribe(C, workspace, scene, screen, area, region, mbus);
}
/* editor level listener */
static void action_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -514,11 +514,11 @@ static void action_listener(wmWindow *UNUSED(win),
/* only handle these events in GPencil mode for performance considerations */
if (saction->mode == SACTCONT_GPENCIL) {
if (wmn->action == NA_EDITED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else if (wmn->action == NA_SELECTED) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
@@ -526,7 +526,7 @@ static void action_listener(wmWindow *UNUSED(win),
/* for NLA tweakmode enter/exit, need complete refresh */
if (wmn->data == ND_NLA_ACTCHANGE) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* autocolor only really needs to change when channels are added/removed,
* or previously hidden stuff appears
@@ -534,14 +534,14 @@ static void action_listener(wmWindow *UNUSED(win),
*/
else if (((wmn->data == ND_KEYFRAME) && ELEM(wmn->action, NA_ADDED, NA_REMOVED)) ||
((wmn->data == ND_ANIMCHAN) && (wmn->action != NA_SELECTED))) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
/* for simple edits to the curve data though (or just plain selections),
* a simple redraw should work
* (see T39851 for an example of how this can go wrong)
*/
else {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_SCENE:
@@ -549,7 +549,7 @@ static void action_listener(wmWindow *UNUSED(win),
case ND_SEQUENCER:
if (wmn->action == NA_SELECTED) {
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case ND_OB_ACTIVE:
@@ -557,13 +557,13 @@ static void action_listener(wmWindow *UNUSED(win),
/* Selection changed, so force refresh to flush
* (needs flag set to do syncing). */
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_RENDER_RESULT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_FRAME_RANGE:
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
Scene *scene = wmn->reference;
region->v2d.tot.xmin = (float)(SFRA - 4);
@@ -575,7 +575,7 @@ static void action_listener(wmWindow *UNUSED(win),
default:
if (saction->mode != SACTCONT_TIMELINE) {
/* Just redrawing the view will do. */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -586,7 +586,7 @@ static void action_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_BONE_ACTIVE:
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_TRANSFORM:
/* moving object shouldn't need to redraw action */
@@ -596,12 +596,12 @@ static void action_listener(wmWindow *UNUSED(win),
case ND_PARTICLE:
/* only needed in timeline mode */
if (saction->mode == SACTCONT_TIMELINE) {
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -609,11 +609,11 @@ static void action_listener(wmWindow *UNUSED(win),
if (saction->mode == SACTCONT_MASK) {
switch (wmn->data) {
case ND_DATA:
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
}
@@ -622,33 +622,33 @@ static void action_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_SELECTED) {
/* selection changed, so force refresh to flush (needs flag set to do syncing) */
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SPACE:
switch (wmn->data) {
case ND_SPACE_DOPESHEET:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_SPACE_TIME:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_SPACE_CHANGED:
saction->runtime.flag |= SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_WINDOW:
if (saction->runtime.flag & SACTION_RUNTIME_FLAG_NEED_CHAN_SYNC) {
/* force redraw/refresh after undo/redo - [#28962] */
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_WM:
switch (wmn->data) {
case ND_FILEREAD:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
@@ -656,12 +656,12 @@ static void action_listener(wmWindow *UNUSED(win),
}
static void action_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -733,7 +733,7 @@ static void action_buttons_area_draw(const bContext *C, ARegion *region)
}
static void action_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -769,9 +769,9 @@ static void action_region_listener(wmWindow *UNUSED(win),
}
}
-static void action_refresh(const bContext *C, ScrArea *sa)
+static void action_refresh(const bContext *C, ScrArea *area)
{
- SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)area->spacedata.first;
/* Update the state of the animchannels in response to changes from the data they represent
* NOTE: the temp flag is used to indicate when this needs to be done,
@@ -789,8 +789,8 @@ static void action_refresh(const bContext *C, ScrArea *sa)
* - Regions (such as header) need to be manually tagged for redraw too
* or else they don't update [#28962]
*/
- ED_area_tag_redraw(sa);
- for (region = sa->regionbase.first; region; region = region->next) {
+ ED_area_tag_redraw(area);
+ for (region = area->regionbase.first; region; region = region->next) {
ED_region_tag_redraw(region);
}
}
@@ -799,7 +799,7 @@ static void action_refresh(const bContext *C, ScrArea *sa)
// XXX re-sizing y-extents of tot should go here?
}
-static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceAction *sact = (SpaceAction *)slink;
@@ -820,15 +820,15 @@ static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, I
* The previous non-timeline mode is stored so switching back to the
* dope-sheet doesn't always reset the sub-mode.
*/
-static int action_space_subtype_get(ScrArea *sa)
+static int action_space_subtype_get(ScrArea *area)
{
- SpaceAction *sact = sa->spacedata.first;
+ SpaceAction *sact = area->spacedata.first;
return sact->mode == SACTCONT_TIMELINE ? SACTCONT_TIMELINE : SACTCONT_DOPESHEET;
}
-static void action_space_subtype_set(ScrArea *sa, int value)
+static void action_space_subtype_set(ScrArea *area, int value)
{
- SpaceAction *sact = sa->spacedata.first;
+ SpaceAction *sact = area->spacedata.first;
if (value == SACTCONT_TIMELINE) {
if (sact->mode != SACTCONT_TIMELINE) {
sact->mode_prev = sact->mode;
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 5b83c082339..acc2281b2da 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -135,6 +135,7 @@ void ED_spacetypes_init(void)
ED_gizmotypes_blank_3d();
ED_gizmotypes_cage_2d();
ED_gizmotypes_cage_3d();
+ ED_gizmotypes_snap_3d();
/* register types for operators and gizmos */
spacetypes = BKE_spacetypes_list();
@@ -268,7 +269,7 @@ void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type)
void ED_spacetype_xxx(void);
/* allocate and init some vars */
-static SpaceLink *xxx_new(const ScrArea *UNUSED(sa), const Scene *UNUSED(scene))
+static SpaceLink *xxx_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
{
return NULL;
}
@@ -279,7 +280,7 @@ static void xxx_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback for usage, should be redoable */
-static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void xxx_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
/* link area to SpaceXXX struct */
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index 587ba5b0b79..7e6088bc3cc 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -1041,7 +1041,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth);
CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md);
return 1;
}
@@ -1051,7 +1051,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody);
CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md);
return 1;
}
@@ -1062,7 +1062,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid);
CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md);
return 1;
}
@@ -1072,7 +1072,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_Collision);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Collision);
CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md);
return 1;
}
@@ -1086,7 +1086,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r
if (ptr && ptr->data) {
Object *ob = ptr->data;
- ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint);
+ ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint);
CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md);
return 1;
}
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index e2affa7bc36..9af623d8065 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -110,7 +110,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
if (BLI_is_dir(path)) {
/* do this first so '//' isnt converted to '//\' on windows */
- BLI_add_slash(path);
+ BLI_path_slash_ensure(path);
if (is_relative) {
BLI_strncpy(path, str, FILE_MAX);
BLI_path_rel(path, BKE_main_blendfile_path(bmain));
@@ -122,7 +122,7 @@ static int file_browse_exec(bContext *C, wmOperator *op)
}
}
else {
- char *const lslash = (char *)BLI_last_slash(str);
+ char *const lslash = (char *)BLI_path_slash_rfind(str);
if (lslash) {
lslash[1] = '\0';
}
@@ -187,7 +187,7 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event)
PointerRNA props_ptr;
if (event->alt) {
- char *lslash = (char *)BLI_last_slash(str);
+ char *lslash = (char *)BLI_path_slash_rfind(str);
if (lslash) {
*lslash = '\0';
}
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index 00818ac77b5..3dc5eca8a8b 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -236,10 +236,10 @@ static void buttons_texture_users_from_context(ListBase *users,
int a;
/* modifiers */
- modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users);
+ BKE_modifiers_foreach_tex_link(ob, buttons_texture_modifier_foreach, users);
/* grease pencil modifiers */
- BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users);
+ BKE_gpencil_modifiers_foreach_tex_link(ob, buttons_texture_modifier_gpencil_foreach, users);
/* particle systems */
if (psys && !limited_mode) {
@@ -373,7 +373,7 @@ static void template_texture_select(bContext *C, void *user_p, void *UNUSED(arg)
/* set user as active */
if (user->node) {
- ED_node_set_active(CTX_data_main(C), user->ntree, user->node);
+ ED_node_set_active(CTX_data_main(C), user->ntree, user->node, NULL);
ct->texture = NULL;
}
else {
@@ -545,7 +545,7 @@ static void template_texture_show(bContext *C, void *data_p, void *prop_p)
}
}
-void uiTemplateTextureShow(uiLayout *layout, bContext *C, PointerRNA *ptr, PropertyRNA *prop)
+void uiTemplateTextureShow(uiLayout *layout, const bContext *C, PointerRNA *ptr, PropertyRNA *prop)
{
/* button to quickly show texture in texture tab */
SpaceProperties *sbuts = CTX_wm_space_properties(C);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 2fd54db667b..c06c107d4a3 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -110,7 +110,7 @@ static void buttons_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void buttons_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -219,7 +219,7 @@ static void buttons_main_region_layout(const bContext *C, ARegion *region)
}
static void buttons_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -274,11 +274,11 @@ static void buttons_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -312,7 +312,7 @@ static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *reg
static void buttons_navigation_bar_region_draw(const bContext *C, ARegion *region)
{
- for (PanelType *pt = region->type->paneltypes.first; pt; pt = pt->next) {
+ LISTBASE_FOREACH (PanelType *, pt, &region->type->paneltypes) {
pt->flag |= PNL_LAYOUT_VERT_BAR;
}
@@ -326,7 +326,7 @@ static void buttons_navigation_bar_region_message_subscribe(const bContext *UNUS
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
@@ -341,96 +341,96 @@ static void buttons_navigation_bar_region_message_subscribe(const bContext *UNUS
/* draw a certain button set only if properties area is currently
* showing that button set, to reduce unnecessary drawing. */
-static void buttons_area_redraw(ScrArea *sa, short buttons)
+static void buttons_area_redraw(ScrArea *area, short buttons)
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
/* if the area's current button set is equal to the one to redraw */
if (sbuts->mainb == buttons) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
/* reused! */
static void buttons_area_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceProperties *sbuts = sa->spacedata.first;
+ SpaceProperties *sbuts = area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_RENDER_OPTIONS:
- buttons_area_redraw(sa, BCONTEXT_RENDER);
- buttons_area_redraw(sa, BCONTEXT_OUTPUT);
- buttons_area_redraw(sa, BCONTEXT_VIEW_LAYER);
+ buttons_area_redraw(area, BCONTEXT_RENDER);
+ buttons_area_redraw(area, BCONTEXT_OUTPUT);
+ buttons_area_redraw(area, BCONTEXT_VIEW_LAYER);
break;
case ND_WORLD:
- buttons_area_redraw(sa, BCONTEXT_WORLD);
+ buttons_area_redraw(area, BCONTEXT_WORLD);
sbuts->preview = 1;
break;
case ND_FRAME:
/* any buttons area can have animated properties so redraw all */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
case ND_OB_ACTIVE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
case ND_KEYINGSET:
- buttons_area_redraw(sa, BCONTEXT_SCENE);
+ buttons_area_redraw(area, BCONTEXT_SCENE);
break;
case ND_RENDER_RESULT:
break;
case ND_MODE:
case ND_LAYER:
default:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_OBJECT:
switch (wmn->data) {
case ND_TRANSFORM:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
- buttons_area_redraw(sa, BCONTEXT_DATA); /* autotexpace flag */
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_DATA); /* autotexpace flag */
break;
case ND_POSE:
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
- buttons_area_redraw(sa, BCONTEXT_BONE);
- buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
- buttons_area_redraw(sa, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_BONE);
+ buttons_area_redraw(area, BCONTEXT_BONE_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_DATA);
break;
case ND_MODIFIER:
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else {
- buttons_area_redraw(sa, BCONTEXT_MODIFIER);
+ buttons_area_redraw(area, BCONTEXT_MODIFIER);
}
- buttons_area_redraw(sa, BCONTEXT_PHYSICS);
+ buttons_area_redraw(area, BCONTEXT_PHYSICS);
break;
case ND_CONSTRAINT:
- buttons_area_redraw(sa, BCONTEXT_CONSTRAINT);
- buttons_area_redraw(sa, BCONTEXT_BONE_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_CONSTRAINT);
+ buttons_area_redraw(area, BCONTEXT_BONE_CONSTRAINT);
break;
case ND_PARTICLE:
if (wmn->action == NA_EDITED) {
- buttons_area_redraw(sa, BCONTEXT_PARTICLE);
+ buttons_area_redraw(area, BCONTEXT_PARTICLE);
}
sbuts->preview = 1;
break;
case ND_DRAW:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
- buttons_area_redraw(sa, BCONTEXT_DATA);
- buttons_area_redraw(sa, BCONTEXT_PHYSICS);
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_PHYSICS);
/* Needed to refresh context path when changing active particle system index. */
- buttons_area_redraw(sa, BCONTEXT_PARTICLE);
+ buttons_area_redraw(area, BCONTEXT_PARTICLE);
break;
case ND_SHADING:
case ND_SHADING_DRAW:
@@ -441,7 +441,7 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
break;
default:
/* Not all object RNA props have a ND_ notifier (yet) */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -450,12 +450,12 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
case ND_SELECT:
case ND_DATA:
case ND_VERTEX_GROUP:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_MATERIAL:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
switch (wmn->data) {
case ND_SHADING:
case ND_SHADING_DRAW:
@@ -468,43 +468,43 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
}
break;
case NC_WORLD:
- buttons_area_redraw(sa, BCONTEXT_WORLD);
+ buttons_area_redraw(area, BCONTEXT_WORLD);
sbuts->preview = 1;
break;
case NC_LAMP:
- buttons_area_redraw(sa, BCONTEXT_DATA);
+ buttons_area_redraw(area, BCONTEXT_DATA);
sbuts->preview = 1;
break;
case NC_GROUP:
- buttons_area_redraw(sa, BCONTEXT_OBJECT);
+ buttons_area_redraw(area, BCONTEXT_OBJECT);
break;
case NC_BRUSH:
- buttons_area_redraw(sa, BCONTEXT_TEXTURE);
- buttons_area_redraw(sa, BCONTEXT_TOOL);
+ buttons_area_redraw(area, BCONTEXT_TEXTURE);
+ buttons_area_redraw(area, BCONTEXT_TOOL);
sbuts->preview = 1;
break;
case NC_TEXTURE:
case NC_IMAGE:
if (wmn->action != NA_PAINTING) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_PROPERTIES) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_ID:
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME:
if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -513,14 +513,14 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_DATA:
if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED, NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
break;
case NC_NODE:
if (wmn->action == NA_SELECTED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* new active node, update texture preview */
if (sbuts->mainb == BCONTEXT_TEXTURE) {
sbuts->preview = 1;
@@ -530,24 +530,24 @@ static void buttons_area_listener(wmWindow *UNUSED(win),
/* Listener for preview render, when doing an global undo. */
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
}
break;
#ifdef WITH_FREESTYLE
case NC_LINESTYLE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
sbuts->preview = 1;
break;
#endif
}
if (wmn->data == ND_KEYS) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
}
-static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceProperties *sbuts = (SpaceProperties *)slink;
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index dc85b3959e1..3b1cc6fcab0 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -872,7 +872,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout,
if (framenr <= clip->len) {
BKE_movieclip_filename_for_frame(clip, user, filepath);
- file = BLI_last_slash(filepath);
+ file = BLI_path_slash_rfind(filepath);
}
else {
file = "-";
diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.c b/source/blender/editors/space_clip/clip_dopesheet_draw.c
index eba0f33d6cc..84ab5e6524b 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_draw.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_draw.c
@@ -68,7 +68,7 @@ static void track_channel_color(MovieTrackingTrack *track, float default_color[3
}
static void draw_keyframe_shape(
- float x, float y, bool sel, float alpha, unsigned int pos_id, unsigned int color_id)
+ float x, float y, bool sel, float alpha, uint pos_id, uint color_id)
{
float color[4] = {0.91f, 0.91f, 0.91f, alpha};
if (sel) {
@@ -79,7 +79,7 @@ static void draw_keyframe_shape(
immVertex2f(pos_id, x, y);
}
-static void clip_draw_dopesheet_background(ARegion *region, MovieClip *clip, unsigned int pos_id)
+static void clip_draw_dopesheet_background(ARegion *region, MovieClip *clip, uint pos_id)
{
View2D *v2d = &region->v2d;
MovieTracking *tracking = &clip->tracking;
@@ -292,7 +292,7 @@ void clip_draw_dopesheet_main(SpaceClip *sc, ARegion *region, Scene *scene)
void clip_draw_dopesheet_channels(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
View2D *v2d = &region->v2d;
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -316,7 +316,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region)
/* need to do a view-sync here, so that the keys area doesn't jump around
* (it must copy this) */
- UI_view2d_sync(NULL, sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, area, v2d, V2D_LOCK_COPY);
/* loop through channels, and set up drawing depending on their type
* first pass: just the standard GL-drawing for backdrop + text
diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c
index cd95a00c62a..c3323491085 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_ops.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c
@@ -204,7 +204,7 @@ static int dopesheet_view_all_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_dopesheet_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "Reset viewable area to show full keyframe range";
ot->idname = "CLIP_OT_dopesheet_view_all";
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 2a6cf4d5a55..fe7ae7096a0 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -66,8 +66,7 @@
/*********************** main area drawing *************************/
-static void draw_keyframe(
- int frame, int cfra, int sfra, float framelen, int width, unsigned int pos)
+static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int width, uint pos)
{
int height = (frame == cfra) ? 22 : 10;
int x = (frame - sfra) * framelen;
@@ -592,7 +591,7 @@ static void draw_marker_outline(SpaceClip *sc,
const float marker_pos[2],
int width,
int height,
- unsigned int position)
+ uint position)
{
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
bool show_search = false;
@@ -895,7 +894,7 @@ static float get_shortest_pattern_side(MovieTrackingMarker *marker)
}
static void draw_marker_slide_square(
- float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], uint pos)
{
float tdx, tdy;
@@ -911,7 +910,7 @@ static void draw_marker_slide_square(
}
static void draw_marker_slide_triangle(
- float x, float y, float dx, float dy, int outline, const float px[2], unsigned int pos)
+ float x, float y, float dx, float dy, int outline, const float px[2], uint pos)
{
float tdx, tdy;
@@ -939,7 +938,7 @@ static void draw_marker_slide_zones(SpaceClip *sc,
int act,
int width,
int height,
- unsigned int pos)
+ uint pos)
{
float dx, dy, patdx, patdy, searchdx, searchdy;
int tiny = sc->flag & SC_SHOW_TINY_MARKER;
@@ -1056,7 +1055,7 @@ static void draw_marker_texts(SpaceClip *sc,
UI_FontThemeColor(fontid, TH_ACT_MARKER);
}
else {
- unsigned char color[4];
+ uchar color[4];
UI_GetThemeColorShade4ubv(TH_DIS_MARKER, 128, color);
BLF_color4ubv(fontid, color);
}
@@ -1191,7 +1190,7 @@ static void draw_plane_marker_image(Scene *scene,
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
if (ibuf) {
- unsigned char *display_buffer;
+ uchar *display_buffer;
void *cache_handle;
if (image->flag & IMA_VIEW_AS_RENDER) {
@@ -1652,7 +1651,7 @@ static void draw_tracking_tracks(SpaceClip *sc,
pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width;
pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy;
- BKE_tracking_distort_v2(tracking, pos, npos);
+ BKE_tracking_distort_v2(tracking, width, height, pos, npos);
if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) {
vec[0] = (marker->pos[0] + track->offset[0]) * width;
@@ -1731,8 +1730,7 @@ static void draw_distortion(SpaceClip *sc,
{
float x, y;
const int n = 10;
- int i, j, a;
- float pos[2], tpos[2], grid[11][11][2];
+ float tpos[2], grid[11][11][2];
MovieTracking *tracking = &clip->tracking;
bGPdata *gpd = NULL;
float aspy = 1.0f / tracking->camera.pixel_aspect;
@@ -1765,7 +1763,7 @@ static void draw_distortion(SpaceClip *sc,
float val[4][2], idx[4][2];
float min[2], max[2];
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
if (a < 2) {
val[a][a % 2] = FLT_MAX;
}
@@ -1774,13 +1772,13 @@ static void draw_distortion(SpaceClip *sc,
}
}
- zero_v2(pos);
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
if (i == 0 || j == 0 || i == n || j == n) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ const float pos[2] = {dx * j, dy * i};
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
- for (a = 0; a < 4; a++) {
+ for (int a = 0; a < 4; a++) {
int ok;
if (a < 2) {
@@ -1797,59 +1795,49 @@ static void draw_distortion(SpaceClip *sc,
}
}
}
-
- pos[0] += dx;
}
-
- pos[0] = 0.0f;
- pos[1] += dy;
}
INIT_MINMAX2(min, max);
- for (a = 0; a < 4; a++) {
- pos[0] = idx[a][0] * dx;
- pos[1] = idx[a][1] * dy;
+ for (int a = 0; a < 4; a++) {
+ const float pos[2] = {idx[a][0] * dx, idx[a][1] * dy};
- BKE_tracking_undistort_v2(tracking, pos, tpos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, tpos);
minmax_v2v2_v2(min, max, tpos);
}
- copy_v2_v2(pos, min);
dx = (max[0] - min[0]) / n;
dy = (max[1] - min[1]) / n;
- for (i = 0; i <= n; i++) {
- for (j = 0; j <= n; j++) {
- BKE_tracking_distort_v2(tracking, pos, grid[i][j]);
+ for (int i = 0; i <= n; i++) {
+ for (int j = 0; j <= n; j++) {
+ const float pos[2] = {min[0] + dx * j, min[1] + dy * i};
+
+ BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]);
grid[i][j][0] /= width;
grid[i][j][1] /= height * aspy;
-
- pos[0] += dx;
}
-
- pos[0] = min[0];
- pos[1] += dy;
}
immUniformColor3f(1.0f, 0.0f, 0.0f);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immVertex2fv(position, grid[i][j]);
}
immEnd();
}
- for (j = 0; j <= n; j++) {
+ for (int j = 0; j <= n; j++) {
immBegin(GPU_PRIM_LINE_STRIP, n + 1);
- for (i = 0; i <= n; i++) {
+ for (int i = 0; i <= n; i++) {
immVertex2fv(position, grid[i][j]);
}
@@ -1883,8 +1871,8 @@ static void draw_distortion(SpaceClip *sc,
while (stroke) {
if (stroke->flag & GP_STROKE_2DSPACE) {
if (stroke->totpoints > 1) {
- for (i = 0; i < stroke->totpoints - 1; i++) {
- float npos[2], dpos[2], len;
+ for (int i = 0; i < stroke->totpoints - 1; i++) {
+ float pos[2], npos[2], dpos[2], len;
int steps;
pos[0] = (stroke->points[i].x + offsx) * width;
@@ -1898,8 +1886,8 @@ static void draw_distortion(SpaceClip *sc,
/* we want to distort only long straight lines */
if (stroke->totpoints == 2) {
- BKE_tracking_undistort_v2(tracking, pos, pos);
- BKE_tracking_undistort_v2(tracking, npos, npos);
+ BKE_tracking_undistort_v2(tracking, width, height, pos, pos);
+ BKE_tracking_undistort_v2(tracking, width, height, npos, npos);
}
sub_v2_v2v2(dpos, npos, pos);
@@ -1907,8 +1895,8 @@ static void draw_distortion(SpaceClip *sc,
immBegin(GPU_PRIM_LINE_STRIP, steps + 1);
- for (j = 0; j <= steps; j++) {
- BKE_tracking_distort_v2(tracking, pos, tpos);
+ for (int j = 0; j <= steps; j++) {
+ BKE_tracking_distort_v2(tracking, width, height, pos, tpos);
immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy));
add_v2_v2(pos, dpos);
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index 6336f1bff3a..5be4b2d5df0 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -37,6 +37,7 @@
#include "DNA_mask_types.h"
#include "BLI_fileops.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_task.h"
@@ -282,7 +283,7 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], flo
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -294,7 +295,7 @@ bool ED_space_clip_color_sample(SpaceClip *sc, ARegion *region, int mval[2], flo
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -310,12 +311,12 @@ void ED_clip_update_frame(const Main *mainp, int cfra)
{
/* image window, compo node users */
for (wmWindowManager *wm = mainp->wm.first; wm; wm = wm->id.next) { /* only 1 wm */
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
bScreen *screen = WM_window_get_active_screen(win);
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_CLIP) {
- SpaceClip *sc = sa->spacedata.first;
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_CLIP) {
+ SpaceClip *sc = area->spacedata.first;
sc->scopes.ok = false;
@@ -545,7 +546,7 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[
r_co[0] *= width;
r_co[1] *= height * aspy;
- BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co);
+ BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co);
r_co[0] /= width;
r_co[1] /= height * aspy;
@@ -579,7 +580,7 @@ void ED_clip_point_stable_pos(
float aspy = 1.0f / tracking->camera.pixel_aspect;
float tmp[2] = {*xr * width, *yr * height * aspy};
- BKE_tracking_distort_v2(tracking, tmp, tmp);
+ BKE_tracking_distort_v2(tracking, width, height, tmp, tmp);
*xr = tmp[0] / width;
*yr = tmp[1] / (height * aspy);
@@ -744,7 +745,7 @@ static bool check_prefetch_break(void)
}
/* read file for specified frame number to the memory */
-static unsigned char *prefetch_read_file_to_memory(
+static uchar *prefetch_read_file_to_memory(
MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size)
{
MovieClipUser user = {0};
@@ -766,7 +767,7 @@ static unsigned char *prefetch_read_file_to_memory(
return NULL;
}
- unsigned char *mem = MEM_mallocN(size, "movieclip prefetch memory file");
+ uchar *mem = MEM_mallocN(size, "movieclip prefetch memory file");
if (mem == NULL) {
close(file);
return NULL;
@@ -822,12 +823,12 @@ static int prefetch_find_uncached_frame(MovieClip *clip,
}
/* get memory buffer for first uncached frame within prefetch frame range */
-static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue,
- MovieClip *clip,
- size_t *r_size,
- int *r_current_frame)
+static uchar *prefetch_thread_next_frame(PrefetchQueue *queue,
+ MovieClip *clip,
+ size_t *r_size,
+ int *r_current_frame)
{
- unsigned char *mem = NULL;
+ uchar *mem = NULL;
BLI_spin_lock(&queue->spin);
if (!*queue->stop && !check_prefetch_break() &&
@@ -884,11 +885,11 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue,
return mem;
}
-static void prefetch_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void prefetch_task_func(TaskPool *__restrict pool, void *task_data)
{
- PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
+ PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_user_data(pool);
MovieClip *clip = (MovieClip *)task_data;
- unsigned char *mem;
+ uchar *mem;
size_t size;
int current_frame;
@@ -941,9 +942,8 @@ static void start_prefetch_threads(MovieClip *clip,
float *progress)
{
PrefetchQueue queue;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
/* initialize queue */
BLI_spin_init(&queue.spin);
@@ -960,9 +960,9 @@ static void start_prefetch_threads(MovieClip *clip,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
for (i = 0; i < tot_thread; i++) {
- BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
BLI_task_pool_free(task_pool);
diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c
index 7f3d3f3d651..277930495bd 100644
--- a/source/blender/editors/space_clip/clip_graph_draw.c
+++ b/source/blender/editors/space_clip/clip_graph_draw.c
@@ -52,7 +52,7 @@ typedef struct TrackMotionCurveUserData {
MovieTrackingTrack *act_track;
bool sel;
float xscale, yscale, hsize;
- unsigned int pos;
+ uint pos;
} TrackMotionCurveUserData;
static void tracking_segment_point_cb(void *userdata,
@@ -159,7 +159,7 @@ static void tracking_segment_knot_cb(void *userdata,
}
}
-static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, unsigned int pos)
+static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, uint pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
@@ -215,36 +215,51 @@ static void draw_tracks_motion_and_error_curves(View2D *v2d, SpaceClip *sc, unsi
}
}
-static void draw_frame_curves(SpaceClip *sc, unsigned int pos)
+static void draw_frame_curves(SpaceClip *sc, uint pos)
{
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking);
- int i, lines = 0, prevfra = 0;
+
+ int previous_frame;
+ float previous_error;
+ bool have_previous_point = false;
+
+ /* Indicates whether immBegin() was called. */
+ bool is_lines_segment_open = false;
immUniformColor3f(0.0f, 0.0f, 1.0f);
- for (i = 0; i < reconstruction->camnr; i++) {
+ for (int i = 0; i < reconstruction->camnr; i++) {
MovieReconstructedCamera *camera = &reconstruction->cameras[i];
- int framenr;
- if (lines && camera->framenr != prevfra + 1) {
- immEnd();
- lines = 0;
- }
+ const int current_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr);
+ const float current_error = camera->error;
- if (!lines) {
- immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr);
- lines = 1;
+ if (have_previous_point && current_frame != previous_frame + 1) {
+ if (is_lines_segment_open) {
+ immEnd();
+ is_lines_segment_open = false;
+ }
+ have_previous_point = false;
}
- framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr);
- immVertex2f(pos, framenr, camera->error);
+ if (have_previous_point) {
+ if (!is_lines_segment_open) {
+ immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr);
+ is_lines_segment_open = true;
+
+ immVertex2f(pos, previous_frame, previous_error);
+ }
+ immVertex2f(pos, current_frame, current_error);
+ }
- prevfra = camera->framenr;
+ previous_frame = current_frame;
+ previous_error = current_error;
+ have_previous_point = true;
}
- if (lines) {
+ if (is_lines_segment_open) {
immEnd();
}
}
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index e974480a233..589831b1c45 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -671,7 +671,7 @@ static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_graph_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "View all curves in editor";
ot->idname = "CLIP_OT_graph_view_all";
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 4dc8d367f2b..27493bb5ccd 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -112,7 +112,7 @@ void CLIP_OT_cursor_set(struct wmOperatorType *ot);
void CLIP_OT_lock_selection_toggle(struct wmOperatorType *ot);
/* clip_toolbar.c */
-struct ARegion *ED_clip_has_properties_region(struct ScrArea *sa);
+struct ARegion *ED_clip_has_properties_region(struct ScrArea *area);
/* clip_utils.c */
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 4e5c6513695..984aa0a63ad 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -286,7 +286,7 @@ static int open_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
BLI_strncpy(path, clip->name, sizeof(path));
BLI_path_abs(path, CTX_data_main(C)->name);
- BLI_parent_dir(path);
+ BLI_path_parent_dir(path);
}
else {
BLI_strncpy(path, U.textudir, sizeof(path));
@@ -784,7 +784,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom In";
+ ot->name = "Zoom In";
ot->idname = "CLIP_OT_view_zoom_in";
ot->description = "Zoom in the view";
@@ -841,7 +841,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom Out";
+ ot->name = "Zoom Out";
ot->idname = "CLIP_OT_view_zoom_out";
ot->description = "Zoom out the view";
@@ -975,7 +975,7 @@ void CLIP_OT_view_all(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "CLIP_OT_view_all";
ot->description = "View whole image with markers";
@@ -1313,12 +1313,12 @@ typedef struct ProxyThread {
int *build_undistort_sizes, build_undistort_count;
} ProxyThread;
-static unsigned char *proxy_thread_next_frame(ProxyQueue *queue,
- MovieClip *clip,
- size_t *r_size,
- int *r_cfra)
+static uchar *proxy_thread_next_frame(ProxyQueue *queue,
+ MovieClip *clip,
+ size_t *r_size,
+ int *r_cfra)
{
- unsigned char *mem = NULL;
+ uchar *mem = NULL;
BLI_spin_lock(&queue->spin);
if (!*queue->stop && queue->cfra <= queue->efra) {
@@ -1367,11 +1367,11 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue,
return mem;
}
-static void proxy_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid))
+static void proxy_task_func(TaskPool *__restrict pool, void *task_data)
{
ProxyThread *data = (ProxyThread *)task_data;
- ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
- unsigned char *mem;
+ ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_user_data(pool);
+ uchar *mem;
size_t size;
int cfra;
@@ -1413,11 +1413,10 @@ static void do_sequence_proxy(void *pjv,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
TaskPool *task_pool;
int sfra = SFRA, efra = EFRA;
ProxyThread *handles;
- int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int i, tot_thread = BLI_task_scheduler_num_threads();
int width, height;
ProxyQueue queue;
@@ -1434,7 +1433,7 @@ static void do_sequence_proxy(void *pjv,
queue.do_update = do_update;
queue.progress = progress;
- task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW);
handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
@@ -1451,7 +1450,7 @@ static void do_sequence_proxy(void *pjv,
handle->distortion = BKE_tracking_distortion_new(&clip->tracking, width, height);
}
- BLI_task_pool_push(task_pool, proxy_task_func, handle, false, TASK_PRIORITY_LOW);
+ BLI_task_pool_push(task_pool, proxy_task_func, handle, false, NULL);
}
BLI_task_pool_work_and_wait(task_pool);
@@ -1533,7 +1532,7 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
wmJob *wm_job;
ProxyJob *pj;
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -1570,7 +1569,7 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_clip/clip_toolbar.c b/source/blender/editors/space_clip/clip_toolbar.c
index 1e3911863fc..b02f3fe16f6 100644
--- a/source/blender/editors/space_clip/clip_toolbar.c
+++ b/source/blender/editors/space_clip/clip_toolbar.c
@@ -53,17 +53,17 @@
/************************** properties ******************************/
-ARegion *ED_clip_has_properties_region(ScrArea *sa)
+ARegion *ED_clip_has_properties_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ region = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
/* is error! */
if (region == NULL) {
@@ -72,7 +72,7 @@ ARegion *ED_clip_has_properties_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip properties region");
- BLI_insertlinkafter(&sa->regionbase, region, arnew);
+ BLI_insertlinkafter(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_UI;
arnew->alignment = RGN_ALIGN_RIGHT;
diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c
index 4a0df454a78..03f791ad70d 100644
--- a/source/blender/editors/space_clip/clip_utils.c
+++ b/source/blender/editors/space_clip/clip_utils.c
@@ -166,7 +166,8 @@ static float calculate_reprojection_error_at_marker(MovieClip *clip,
reprojected_position[1] = (reprojected_position[1] / (reprojected_position[3] * 2.0f) + 0.5f) *
clip_height * aspy;
- BKE_tracking_distort_v2(tracking, reprojected_position, reprojected_position);
+ BKE_tracking_distort_v2(
+ tracking, clip_width, clip_height, reprojected_position, reprojected_position);
marker_position[0] = (marker->pos[0] + track->offset[0]) * clip_width;
marker_position[1] = (marker->pos[1] + track->offset[1]) * clip_height * aspy;
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index dad361db7e3..0dccd45578e 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -71,7 +71,7 @@
#include "clip_intern.h" /* own include */
static void init_preview_region(const Scene *scene,
- const ScrArea *sa,
+ const ScrArea *area,
const SpaceClip *sc,
ARegion *region)
{
@@ -81,8 +81,8 @@ static void init_preview_region(const Scene *scene,
if (sc->view == SC_VIEW_DOPESHEET) {
region->v2d.tot.xmin = -10.0f;
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
- region->v2d.tot.xmax = (float)(sa->winx);
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
+ region->v2d.tot.xmax = (float)(area->winx);
region->v2d.tot.ymax = 0.0f;
region->v2d.cur = region->v2d.tot;
@@ -133,32 +133,32 @@ static void init_preview_region(const Scene *scene,
static void reinit_preview_region(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
if (sc->view == SC_VIEW_DOPESHEET) {
if ((region->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) == 0) {
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
}
}
else {
if (region->v2d.flag & V2D_VIEWSYNC_AREA_VERTICAL) {
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
}
}
}
-static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
+static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
/* is error! */
if (region == NULL) {
@@ -167,23 +167,23 @@ static ARegion *ED_clip_has_preview_region(const bContext *C, ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip preview region");
- BLI_insertlinkbefore(&sa->regionbase, region, arnew);
- init_preview_region(CTX_data_scene(C), sa, CTX_wm_space_clip(C), arnew);
+ BLI_insertlinkbefore(&area->regionbase, region, arnew);
+ init_preview_region(CTX_data_scene(C), area, CTX_wm_space_clip(C), arnew);
return arnew;
}
-static ARegion *ED_clip_has_channels_region(ScrArea *sa)
+static ARegion *ED_clip_has_channels_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS);
+ region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW);
/* is error! */
if (region == NULL) {
@@ -192,7 +192,7 @@ static ARegion *ED_clip_has_channels_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "clip channels region");
- BLI_insertlinkbefore(&sa->regionbase, region, arnew);
+ BLI_insertlinkbefore(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_CHANNELS;
arnew->alignment = RGN_ALIGN_LEFT;
@@ -202,9 +202,9 @@ static ARegion *ED_clip_has_channels_region(ScrArea *sa)
return arnew;
}
-static void clip_scopes_tag_refresh(ScrArea *sa)
+static void clip_scopes_tag_refresh(ScrArea *area)
{
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
ARegion *region;
if (sc->mode != SC_MODE_TRACKING) {
@@ -212,7 +212,7 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
}
/* only while properties are visible */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_UI && region->flag & RGN_FLAG_HIDDEN) {
return;
}
@@ -221,24 +221,24 @@ static void clip_scopes_tag_refresh(ScrArea *sa)
sc->scopes.ok = false;
}
-static void clip_scopes_check_gpencil_change(ScrArea *sa)
+static void clip_scopes_check_gpencil_change(ScrArea *area)
{
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- clip_scopes_tag_refresh(sa);
+ clip_scopes_tag_refresh(area);
}
}
-static void clip_area_sync_frame_from_scene(ScrArea *sa, Scene *scene)
+static void clip_area_sync_frame_from_scene(ScrArea *area, Scene *scene)
{
- SpaceClip *space_clip = (SpaceClip *)sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)area->spacedata.first;
BKE_movieclip_user_set_frame(&space_clip->user, scene->r.cfra);
}
/* ******************** default callbacks for clip space ***************** */
-static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *clip_new(const ScrArea *area, const Scene *scene)
{
ARegion *region;
SpaceClip *sc;
@@ -287,7 +287,7 @@ static SpaceLink *clip_new(const ScrArea *sa, const Scene *scene)
region = MEM_callocN(sizeof(ARegion), "preview for clip");
BLI_addtail(&sc->regionbase, region);
- init_preview_region(scene, sa, sc, region);
+ init_preview_region(scene, area, sc, region);
/* main region */
region = MEM_callocN(sizeof(ARegion), "main region for clip");
@@ -326,18 +326,18 @@ static SpaceLink *clip_duplicate(SpaceLink *sl)
return (SpaceLink *)scn;
}
-static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *scene)
+static void clip_listener(wmWindow *UNUSED(win), ScrArea *area, wmNotifier *wmn, Scene *scene)
{
/* context changes */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
- clip_scopes_tag_refresh(sa);
+ clip_scopes_tag_refresh(area);
ATTR_FALLTHROUGH;
case ND_FRAME_RANGE:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -345,8 +345,8 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
switch (wmn->data) {
case ND_DISPLAY:
case ND_SELECT:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
switch (wmn->action) {
@@ -356,8 +356,8 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
/* fall-through */
case NA_SELECTED:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -366,56 +366,56 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S
case ND_SELECT:
case ND_DATA:
case ND_DRAW:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
switch (wmn->action) {
case NA_SELECTED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_EDITED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_GEOM:
switch (wmn->data) {
case ND_SELECT:
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_SCREEN:
switch (wmn->data) {
case ND_ANIMPLAY:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_LAYOUTSET:
- clip_area_sync_frame_from_scene(sa, scene);
+ clip_area_sync_frame_from_scene(area, scene);
break;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_CLIP) {
- clip_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
case NC_GPENCIL:
if (wmn->action == NA_EDITED) {
- clip_scopes_check_gpencil_change(sa);
- ED_area_tag_redraw(sa);
+ clip_scopes_check_gpencil_change(area);
+ ED_area_tag_redraw(area);
}
else if (wmn->data & ND_GPENCIL_EDITMODE) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_WM:
switch (wmn->data) {
case ND_FILEREAD:
case ND_UNDO:
- clip_area_sync_frame_from_scene(sa, scene);
+ clip_area_sync_frame_from_scene(area, scene);
break;
}
break;
@@ -592,17 +592,17 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
return false;
}
-static void clip_refresh(const bContext *C, ScrArea *sa)
+static void clip_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window = CTX_wm_window(C);
Scene *scene = CTX_data_scene(C);
- SpaceClip *sc = (SpaceClip *)sa->spacedata.first;
- ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- ARegion *ar_tools = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS);
- ARegion *ar_preview = ED_clip_has_preview_region(C, sa);
- ARegion *ar_properties = ED_clip_has_properties_region(sa);
- ARegion *ar_channels = ED_clip_has_channels_region(sa);
+ SpaceClip *sc = (SpaceClip *)area->spacedata.first;
+ ARegion *region_main = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ ARegion *region_tools = BKE_area_find_region_type(area, RGN_TYPE_TOOLS);
+ ARegion *region_preview = ED_clip_has_preview_region(C, area);
+ ARegion *region_properties = ED_clip_has_properties_region(area);
+ ARegion *region_channels = ED_clip_has_channels_region(area);
bool main_visible = false, preview_visible = false, tools_visible = false;
bool properties_visible = false, channels_visible = false;
bool view_changed = false;
@@ -622,7 +622,7 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
properties_visible = false;
channels_visible = false;
- reinit_preview_region(C, ar_preview);
+ reinit_preview_region(C, region_preview);
break;
case SC_VIEW_DOPESHEET:
main_visible = false;
@@ -631,135 +631,135 @@ static void clip_refresh(const bContext *C, ScrArea *sa)
properties_visible = false;
channels_visible = true;
- reinit_preview_region(C, ar_preview);
+ reinit_preview_region(C, region_preview);
break;
}
if (main_visible) {
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_main && (region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
else {
- if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag |= RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
+ if (region_main && !(region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag |= RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_main->handlers);
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (properties_visible) {
- if (ar_properties && (ar_properties->flag & RGN_FLAG_HIDDEN)) {
- ar_properties->flag &= ~RGN_FLAG_HIDDEN;
- ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_properties && (region_properties->flag & RGN_FLAG_HIDDEN)) {
+ region_properties->flag &= ~RGN_FLAG_HIDDEN;
+ region_properties->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_properties && ar_properties->alignment != RGN_ALIGN_RIGHT) {
- ar_properties->alignment = RGN_ALIGN_RIGHT;
+ if (region_properties && region_properties->alignment != RGN_ALIGN_RIGHT) {
+ region_properties->alignment = RGN_ALIGN_RIGHT;
view_changed = true;
}
}
else {
- if (ar_properties && !(ar_properties->flag & RGN_FLAG_HIDDEN)) {
- ar_properties->flag |= RGN_FLAG_HIDDEN;
- ar_properties->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_properties->handlers);
+ if (region_properties && !(region_properties->flag & RGN_FLAG_HIDDEN)) {
+ region_properties->flag |= RGN_FLAG_HIDDEN;
+ region_properties->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_properties->handlers);
view_changed = true;
}
- if (ar_properties && ar_properties->alignment != RGN_ALIGN_NONE) {
- ar_properties->alignment = RGN_ALIGN_NONE;
+ if (region_properties && region_properties->alignment != RGN_ALIGN_NONE) {
+ region_properties->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (tools_visible) {
- if (ar_tools && (ar_tools->flag & RGN_FLAG_HIDDEN)) {
- ar_tools->flag &= ~RGN_FLAG_HIDDEN;
- ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_tools && (region_tools->flag & RGN_FLAG_HIDDEN)) {
+ region_tools->flag &= ~RGN_FLAG_HIDDEN;
+ region_tools->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_tools && ar_tools->alignment != RGN_ALIGN_LEFT) {
- ar_tools->alignment = RGN_ALIGN_LEFT;
+ if (region_tools && region_tools->alignment != RGN_ALIGN_LEFT) {
+ region_tools->alignment = RGN_ALIGN_LEFT;
view_changed = true;
}
}
else {
- if (ar_tools && !(ar_tools->flag & RGN_FLAG_HIDDEN)) {
- ar_tools->flag |= RGN_FLAG_HIDDEN;
- ar_tools->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_tools->handlers);
+ if (region_tools && !(region_tools->flag & RGN_FLAG_HIDDEN)) {
+ region_tools->flag |= RGN_FLAG_HIDDEN;
+ region_tools->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_tools->handlers);
view_changed = true;
}
- if (ar_tools && ar_tools->alignment != RGN_ALIGN_NONE) {
- ar_tools->alignment = RGN_ALIGN_NONE;
+ if (region_tools && region_tools->alignment != RGN_ALIGN_NONE) {
+ region_tools->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (preview_visible) {
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
+ if (region_preview && (region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
else {
- if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag |= RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
+ if (region_preview && !(region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag |= RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_preview->handlers);
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (channels_visible) {
- if (ar_channels && (ar_channels->flag & RGN_FLAG_HIDDEN)) {
- ar_channels->flag &= ~RGN_FLAG_HIDDEN;
- ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_channels && (region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag &= ~RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_channels && ar_channels->alignment != RGN_ALIGN_LEFT) {
- ar_channels->alignment = RGN_ALIGN_LEFT;
+ if (region_channels && region_channels->alignment != RGN_ALIGN_LEFT) {
+ region_channels->alignment = RGN_ALIGN_LEFT;
view_changed = true;
}
}
else {
- if (ar_channels && !(ar_channels->flag & RGN_FLAG_HIDDEN)) {
- ar_channels->flag |= RGN_FLAG_HIDDEN;
- ar_channels->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_channels->handlers);
+ if (region_channels && !(region_channels->flag & RGN_FLAG_HIDDEN)) {
+ region_channels->flag |= RGN_FLAG_HIDDEN;
+ region_channels->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_channels->handlers);
view_changed = true;
}
- if (ar_channels && ar_channels->alignment != RGN_ALIGN_NONE) {
- ar_channels->alignment = RGN_ALIGN_NONE;
+ if (region_channels && region_channels->alignment != RGN_ALIGN_NONE) {
+ region_channels->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
}
if (view_changed) {
- ED_area_initialize(wm, window, sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(wm, window, area);
+ ED_area_tag_redraw(area);
}
BKE_movieclip_user_set_frame(&sc->user, scene->r.cfra);
@@ -899,9 +899,9 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
if (sc->mode == SC_MODE_MASKEDIT) {
Mask *mask = CTX_data_edit_mask(C);
if (mask && clip) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int mask_width, mask_height;
- ED_mask_get_size(sa, &mask_width, &mask_height);
+ ED_mask_get_size(area, &mask_width, &mask_height);
ED_mask_draw_region(CTX_data_expect_evaluated_depsgraph(C),
mask,
region,
@@ -954,7 +954,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region)
}
static void clip_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1098,7 +1098,7 @@ static void clip_preview_region_draw(const bContext *C, ARegion *region)
}
static void clip_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -1144,7 +1144,7 @@ static void clip_channels_region_draw(const bContext *C, ARegion *region)
}
static void clip_channels_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -1165,7 +1165,7 @@ static void clip_header_region_draw(const bContext *C, ARegion *region)
}
static void clip_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1208,7 +1208,7 @@ static void clip_tools_region_draw(const bContext *C, ARegion *region)
/****************** tool properties region ******************/
static void clip_props_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1261,7 +1261,7 @@ static void clip_properties_region_draw(const bContext *C, ARegion *region)
}
static void clip_properties_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1283,7 +1283,7 @@ static void clip_properties_region_listener(wmWindow *UNUSED(win),
/********************* registration ********************/
-static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceClip *sclip = (SpaceClip *)slink;
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 67c453825f7..81cc858c69f 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -387,7 +387,8 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
DEG_id_tag_update(&clip->id, ID_RECALC_SELECT);
- return OPERATOR_FINISHED;
+ /* Pass-through + finished to allow tweak to transform. */
+ return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
}
static bool select_poll(bContext *C)
@@ -597,8 +598,8 @@ void CLIP_OT_select_box(wmOperatorType *ot)
/********************** lasso select operator *********************/
static int do_lasso_select_marker(bContext *C,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
bool select)
{
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -615,7 +616,7 @@ static int do_lasso_select_marker(bContext *C,
int framenr = ED_space_clip_get_clip_frame_number(sc);
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
track = tracksbase->first;
@@ -630,7 +631,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
}
@@ -658,7 +660,8 @@ static int do_lasso_select_marker(bContext *C,
ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co);
if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) {
if (select) {
plane_track->flag |= SELECT;
}
@@ -684,10 +687,10 @@ static int do_lasso_select_marker(bContext *C,
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const bool select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
@@ -695,9 +698,9 @@ static int clip_lasso_select_exec(bContext *C, wmOperator *op)
ED_clip_select_all(sc, SEL_DESELECT, NULL);
}
- do_lasso_select_marker(C, mcords, mcords_tot, select);
+ do_lasso_select_marker(C, mcoords, mcoords_len, select);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c
index 6c56e8dfb79..805e9608fec 100644
--- a/source/blender/editors/space_console/console_draw.c
+++ b/source/blender/editors/space_console/console_draw.c
@@ -91,7 +91,6 @@ void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy)
static int console_textview_begin(TextViewContext *tvc)
{
SpaceConsole *sc = (SpaceConsole *)tvc->arg1;
- tvc->lheight = sc->lheight * UI_DPI_FAC;
tvc->sel_start = sc->sel_start;
tvc->sel_end = sc->sel_end;
@@ -143,10 +142,7 @@ static void console_cursor_wrap_offset(
return;
}
-static void console_textview_draw_cursor(TextViewContext *tvc,
- int cwidth,
- int columns,
- int descender)
+static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns)
{
int pen[2];
{
@@ -157,10 +153,10 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
console_cursor_wrap_offset(sc->prompt, columns, &offl, &offc, NULL);
console_cursor_wrap_offset(cl->line, columns, &offl, &offc, cl->line + cl->cursor);
pen[0] = cwidth * offc;
- pen[1] = -2 - (tvc->lheight + descender) * offl;
+ pen[1] = -tvc->lheight * offl;
console_cursor_wrap_offset(cl->line + cl->cursor, columns, &offl, &offc, NULL);
- pen[1] += (tvc->lheight + descender) * offl;
+ pen[1] += tvc->lheight * offl;
pen[0] += tvc->draw_rect.xmin;
pen[1] += tvc->draw_rect.ymin;
@@ -172,8 +168,7 @@ static void console_textview_draw_cursor(TextViewContext *tvc,
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(TH_CONSOLE_CURSOR);
- immRectf(
- pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight + descender);
+ immRectf(pos, pen[0] - U.pixelsize, pen[1], pen[0] + U.pixelsize, pen[1] + tvc->lheight);
immUnbindProgram();
}
@@ -229,7 +224,7 @@ static int console_textview_main__internal(SpaceConsole *sc,
/* view */
tvc.sel_start = sc->sel_start;
tvc.sel_end = sc->sel_end;
- tvc.lheight = sc->lheight * 1.2f * UI_DPI_FAC;
+ tvc.lheight = sc->lheight * UI_DPI_FAC;
tvc.scroll_ymin = v2d->cur.ymin;
tvc.scroll_ymax = v2d->cur.ymax;
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 58d6fb425b0..981e056fa63 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -353,10 +353,10 @@ static int console_move_exec(bContext *C, wmOperator *op)
}
if (done) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
console_scroll_bottom(region);
}
@@ -860,7 +860,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
{
SpaceConsole *sc = CTX_wm_space_console(C);
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ConsoleLine *ci = console_history_verify(C);
/* own this text in the new line, don't free */
char *str = RNA_string_get_alloc(op->ptr, "text", NULL, 0);
@@ -885,7 +885,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
console_select_offset(sc, ci->len - prev_len);
console_line_cursor_set(ci, cursor);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* when calling render modally this can be NULL when calling:
* bpy.ops.render.render('INVOKE_DEFAULT') */
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 4214d43fe5f..3f1e4f8292f 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -98,7 +98,7 @@ static void console_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void console_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void console_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -140,7 +140,7 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *region)
}
/* same as 'text_cursor' */
-static void console_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *region)
+static void console_cursor(wmWindow *win, ScrArea *UNUSED(area), ARegion *region)
{
int wmcursor = WM_CURSOR_TEXT_EDIT;
const wmEvent *event = win->eventstate;
@@ -228,19 +228,19 @@ static void console_header_region_draw(const bContext *C, ARegion *region)
}
static void console_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- // SpaceInfo *sinfo = sa->spacedata.first;
+ // SpaceInfo *sinfo = area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SPACE: {
if (wmn->data == ND_SPACE_CONSOLE) {
if (wmn->action == NA_EDITED) {
- if ((wmn->reference && sa) && (wmn->reference == sa->spacedata.first)) {
+ if ((wmn->reference && area) && (wmn->reference == area->spacedata.first)) {
/* we've modified the geometry (font size), re-calculate rect */
console_textview_update_rect(wmn->reference, region);
ED_region_tag_redraw(region);
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 5f5aced292d..8d14664c0fa 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -220,7 +220,8 @@ static void file_draw_preview(uiBlock *block,
const bool is_icon,
const int typeflags,
const bool drag,
- const bool dimmed)
+ const bool dimmed,
+ const bool is_link)
{
uiBut *but;
float fx, fy;
@@ -312,37 +313,57 @@ static void file_draw_preview(uiBlock *block,
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
- if (icon && !(typeflags & FILE_TYPE_FTFONT)) {
- /* size of center icon is scaled to fit container and UI scale */
+ if (icon && is_icon) {
+ /* Small icon in the middle of large image, scaled to fit container and UI scale */
float icon_x, icon_y;
-
- if (is_icon) {
- const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
- float icon_opacity = 0.3f;
- uchar icon_color[4] = {0, 0, 0, 255};
- float bgcolor[4];
- UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
- if (rgb_to_grayscale(bgcolor) < 0.5f) {
- icon_color[0] = 255;
- icon_color[1] = 255;
- icon_color[2] = 255;
- }
- icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
- icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
- UI_icon_draw_ex(
- icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ const float icon_size = 16.0f / icon_aspect * U.dpi_fac;
+ float icon_opacity = 0.3f;
+ uchar icon_color[4] = {0, 0, 0, 255};
+ float bgcolor[4];
+ UI_GetThemeColor4fv(TH_ICON_FOLDER, bgcolor);
+ if (rgb_to_grayscale(bgcolor) < 0.5f) {
+ icon_color[0] = 255;
+ icon_color[1] = 255;
+ icon_color[2] = 255;
}
- else {
+ icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f);
+ icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.75f));
+ UI_icon_draw_ex(
+ icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false);
+ }
+
+ if (is_link) {
+ /* Arrow icon to indicate it is a shortcut, link, or alias. */
+ float icon_x, icon_y;
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ const int arrow = ICON_LOOP_FORWARDS;
+ if (!is_icon) {
+ /* Arrow at very bottom-left if preview style. */
const uchar dark[4] = {0, 0, 0, 255};
const uchar light[4] = {255, 255, 255, 255};
-
- /* Smaller, fainter icon for preview image thumbnail. */
- icon_x = xco + (2.0f * UI_DPI_FAC);
- icon_y = yco + (2.0f * UI_DPI_FAC);
-
- UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
- UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, arrow, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
+ else {
+ /* Link to folder or non-previewed file. */
+ uchar icon_color[4];
+ UI_GetThemeColor4ubv(TH_BACK, icon_color);
+ icon_x = xco + ((typeflags & FILE_TYPE_DIR) ? 0.14f : 0.23f) * scaledx;
+ icon_y = yco + ((typeflags & FILE_TYPE_DIR) ? 0.24f : 0.14f) * scaledy;
+ UI_icon_draw_ex(
+ icon_x, icon_y, arrow, icon_aspect / U.dpi_fac * 1.8, 0.3f, 0.0f, icon_color, false);
+ }
+ }
+ else if (icon && !is_icon && !(typeflags & FILE_TYPE_FTFONT)) {
+ /* Smaller, fainter icon at bottom-left for preview image thumbnail, but not for fonts. */
+ float icon_x, icon_y;
+ const uchar dark[4] = {0, 0, 0, 255};
+ const uchar light[4] = {255, 255, 255, 255};
+ icon_x = xco + (2.0f * UI_DPI_FAC);
+ icon_y = yco + (2.0f * UI_DPI_FAC);
+ UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false);
+ UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false);
}
/* Contrasting outline around some preview types. */
@@ -448,7 +469,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
const int step = (layout->tile_w + 2 * layout->tile_border_x);
- unsigned int vertex_len = 0;
+ uint vertex_len = 0;
int sx = (int)v2d->tot.xmin;
while (sx < v2d->cur.xmax) {
sx += step;
@@ -457,7 +478,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d)
if (vertex_len > 0) {
int v1[2], v2[2];
- unsigned char col_hi[3], col_lo[3];
+ uchar col_hi[3], col_lo[3];
UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
@@ -685,7 +706,7 @@ void file_draw_list(const bContext *C, ARegion *region)
bool is_icon;
eFontStyle_Align align;
bool do_drag;
- unsigned char text_col[4];
+ uchar text_col[4];
const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY);
const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f);
@@ -753,7 +774,7 @@ void file_draw_list(const bContext *C, ARegion *region)
UI_GetThemeColor4ubv(TH_TEXT, text_col);
for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) {
- unsigned int file_selflag;
+ uint file_selflag;
char path[FILE_MAX_LIBEXTRA];
int padx = 0.1f * UI_UNIT_X;
int icon_ofs = 0;
@@ -788,6 +809,7 @@ void file_draw_list(const bContext *C, ARegion *region)
/* don't drag parent or refresh items */
do_drag = !(FILENAME_IS_CURRPAR(file->relpath));
const bool is_hidden = (file->attributes & FILE_ATTR_HIDDEN);
+ const bool is_link = (file->attributes & FILE_ATTR_ANY_LINK);
if (FILE_IMGDISPLAY == params->display) {
const int icon = filelist_geticon(files, i, false);
@@ -809,7 +831,8 @@ void file_draw_list(const bContext *C, ARegion *region)
is_icon,
file->typeflag,
do_drag,
- is_hidden);
+ is_hidden,
+ is_link);
}
else {
file_draw_icon(block,
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 5258892d55d..41d32fda088 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -103,7 +103,7 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile,
return sel;
}
-static void file_deselect_all(SpaceFile *sfile, unsigned int flag)
+static void file_deselect_all(SpaceFile *sfile, uint flag)
{
FileSelection sel;
sel.first = 0;
@@ -211,7 +211,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
else {
if (is_parent_dir) {
/* avoids /../../ */
- BLI_parent_dir(params->dir);
+ BLI_path_parent_dir(params->dir);
if (params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
@@ -220,9 +220,9 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
}
}
else {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
strcat(params->dir, file->relpath);
- BLI_add_slash(params->dir);
+ BLI_path_slash_ensure(params->dir);
}
ED_file_change_dir(C);
@@ -851,7 +851,7 @@ void FILE_OT_select_walk(wmOperatorType *ot)
static int file_select_all_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelection sel;
const int numfiles = filelist_files_ensure(sfile->files);
@@ -900,7 +900,7 @@ static int file_select_all_exec(bContext *C, wmOperator *op)
file_draw_check(C);
WM_event_add_mousemove(CTX_wm_window(C));
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -940,7 +940,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, entry);
BLI_strncpy(params->dir, entry, sizeof(params->dir));
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
ED_file_change_dir(C);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
@@ -975,7 +975,7 @@ void FILE_OT_select_bookmark(wmOperatorType *ot)
static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FileSelectParams *params = ED_fileselect_get_params(sfile);
@@ -992,8 +992,8 @@ static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
fsmenu_write_file(fsmenu, name);
}
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1017,7 +1017,7 @@ void FILE_OT_bookmark_add(wmOperatorType *ot)
static int bookmark_delete_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
@@ -1041,8 +1041,8 @@ static int bookmark_delete_exec(bContext *C, wmOperator *op)
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
@@ -1075,7 +1075,7 @@ void FILE_OT_bookmark_delete(wmOperatorType *ot)
static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
int index;
@@ -1102,8 +1102,8 @@ static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -1138,7 +1138,7 @@ enum {
static int bookmark_move_exec(bContext *C, wmOperator *op)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
struct FSMenu *fsmenu = ED_fsmenu_get();
struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
@@ -1187,7 +1187,7 @@ static int bookmark_move_exec(bContext *C, wmOperator *op)
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, fname);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1228,7 +1228,7 @@ void FILE_OT_bookmark_move(wmOperatorType *ot)
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
char name[FILE_MAX];
struct FSMenu *fsmenu = ED_fsmenu_get();
@@ -1240,7 +1240,7 @@ static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(fsmenu, name);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -1469,9 +1469,12 @@ void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, ch
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
FileDirEntry *file = filelist_file(sfile->files, i);
- RNA_property_collection_add(op->ptr, prop, &itemptr);
- RNA_string_set(&itemptr, "name", file->relpath);
- num_files++;
+ /* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
+ if (!file->redirection_path) {
+ RNA_property_collection_add(op->ptr, prop, &itemptr);
+ RNA_string_set(&itemptr, "name", file->relpath);
+ num_files++;
+ }
}
}
/* make sure the file specified in the filename button is added even if no
@@ -1617,9 +1620,23 @@ static int file_exec(bContext *C, wmOperator *exec_op)
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- const struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
+ struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
char filepath[FILE_MAX];
+ if (file && file->redirection_path) {
+ /* redirection_path is an absolute path that takes precedence
+ * over using sfile->params->dir + sfile->params->file. */
+ BLI_split_dirfile(file->redirection_path,
+ sfile->params->dir,
+ sfile->params->file,
+ sizeof(sfile->params->dir),
+ sizeof(sfile->params->file));
+ /* Update relpath with redirected filename as well so that the alternative
+ * combination of sfile->params->dir + relpath remains valid as well. */
+ MEM_freeN(file->relpath);
+ file->relpath = BLI_strdup(sfile->params->file);
+ }
+
/* directory change */
if (file && (file->typeflag & FILE_TYPE_DIR)) {
if (!file->relpath) {
@@ -1627,15 +1644,12 @@ static int file_exec(bContext *C, wmOperator *exec_op)
}
if (FILENAME_IS_PARENT(file->relpath)) {
- BLI_parent_dir(sfile->params->dir);
+ BLI_path_parent_dir(sfile->params->dir);
}
else {
- BLI_cleanup_path(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir);
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
- BLI_add_slash(sfile->params->dir);
- }
- if (file->redirection_path) {
- STRNCPY(sfile->params->dir, file->redirection_path);
+ BLI_path_slash_ensure(sfile->params->dir);
}
ED_file_change_dir(C);
}
@@ -1754,8 +1768,8 @@ static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
- if (BLI_parent_dir(sfile->params->dir)) {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ if (BLI_path_parent_dir(sfile->params->dir)) {
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
ED_file_change_dir(C);
if (sfile->params->recursion_level > 1) {
/* Disable 'dirtree' recursion when going up in tree. */
@@ -1867,9 +1881,9 @@ void FILE_OT_next(struct wmOperatorType *ot)
/* only meant for timer usage */
static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = CTX_wm_space_file(C);
- ARegion *region, *ar_ctx = CTX_wm_region(C);
+ ARegion *region, *region_ctx = CTX_wm_region(C);
const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
int i;
@@ -1911,7 +1925,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
}
/* we need the correct area for scrolling */
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
sfile->smoothscroll_timer = NULL;
@@ -2033,7 +2047,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w
ED_region_tag_redraw(region);
/* and restore context */
- CTX_wm_region_set(C, ar_ctx);
+ CTX_wm_region_set(C, region_ctx);
return OPERATOR_FINISHED;
}
@@ -2274,7 +2288,7 @@ static void file_expand_directory(bContext *C)
sfile->params->dir[3] = '\0';
}
else if (BLI_path_is_unc(sfile->params->dir)) {
- BLI_cleanup_unc(sfile->params->dir, FILE_MAX_LIBEXTRA);
+ BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA);
}
#endif
}
@@ -2291,7 +2305,7 @@ static bool can_create_dir(const char *dir)
if (BLI_path_is_unc(dir)) {
char parent[PATH_MAX];
BLI_strncpy(parent, dir, PATH_MAX);
- BLI_parent_dir(parent);
+ BLI_path_parent_dir(parent);
return BLI_is_dir(parent);
}
return true;
@@ -2338,7 +2352,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
}
}
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
@@ -2423,7 +2437,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
/* if directory, open it and empty filename field */
if (filelist_is_dir(sfile->files, filepath)) {
- BLI_cleanup_dir(BKE_main_blendfile_path(bmain), filepath);
+ BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
ED_file_change_dir(C);
@@ -2487,16 +2501,16 @@ static bool file_filenum_poll(bContext *C)
}
/**
- * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
+ * Looks for a string of digits within name (using BLI_path_sequence_decode) and adjusts it by add.
*/
static void filenum_newname(char *name, size_t name_size, int add)
{
char head[FILE_MAXFILE], tail[FILE_MAXFILE];
char name_temp[FILE_MAXFILE];
int pic;
- unsigned short digits;
+ ushort digits;
- pic = BLI_stringdec(name, head, tail, &digits);
+ pic = BLI_path_sequence_decode(name, head, tail, &digits);
/* are we going from 100 -> 99 or from 10 -> 9 */
if (add < 0 && digits > 0) {
@@ -2514,19 +2528,19 @@ static void filenum_newname(char *name, size_t name_size, int add)
if (pic < 0) {
pic = 0;
}
- BLI_stringenc(name_temp, head, tail, digits, pic);
+ BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
BLI_strncpy(name, name_temp, name_size);
}
static int file_filenum_exec(bContext *C, wmOperator *op)
{
SpaceFile *sfile = CTX_wm_space_file(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int inc = RNA_int_get(op->ptr, "increment");
if (sfile->params && (inc != 0)) {
filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
file_draw_check(C);
// WM_event_add_notifier(C, NC_WINDOW, NULL);
}
@@ -2576,12 +2590,12 @@ static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool requ
static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
file_rename_state_activate(sfile, sfile->params->active_file, true);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -2589,12 +2603,12 @@ static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
if (sfile->params) {
file_rename_state_activate(sfile, sfile->params->highlight_file, false);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
return OPERATOR_FINISHED;
@@ -2708,8 +2722,8 @@ void FILE_OT_delete(struct wmOperatorType *ot)
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_UI);
SpaceFile *sf = CTX_wm_space_file(C);
UI_textbutton_activate_rna(C, region, sf->params, "filter_search");
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 9ba098fcf45..ff9454cd922 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -57,20 +57,20 @@ static bool file_panel_operator_poll(const bContext *C, PanelType *UNUSED(pt))
return (sfile && sfile->op);
}
-static void file_panel_operator_header(const bContext *C, Panel *pa)
+static void file_panel_operator_header(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
- BLI_strncpy(pa->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(pa->drawname));
+ BLI_strncpy(panel->drawname, WM_operatortype_name(op->type, op->ptr), sizeof(panel->drawname));
}
-static void file_panel_operator(const bContext *C, Panel *pa)
+static void file_panel_operator(const bContext *C, Panel *panel)
{
SpaceFile *sfile = CTX_wm_space_file(C);
wmOperator *op = sfile->op;
- UI_block_func_set(uiLayoutGetBlock(pa->layout), file_draw_check_cb, NULL, NULL);
+ UI_block_func_set(uiLayoutGetBlock(panel->layout), file_draw_check_cb, NULL, NULL);
/* Hack: temporary hide.*/
const char *hide[] = {"filepath", "files", "directory", "filename"};
@@ -82,7 +82,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
}
uiTemplateOperatorPropertyButs(
- C, pa->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
+ C, panel->layout, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_EMPTY);
/* Hack: temporary hide.*/
for (int i = 0; i < ARRAY_SIZE(hide); i++) {
@@ -92,7 +92,7 @@ static void file_panel_operator(const bContext *C, Panel *pa)
}
}
- UI_block_func_set(uiLayoutGetBlock(pa->layout), NULL, NULL, NULL);
+ UI_block_func_set(uiLayoutGetBlock(panel->layout), NULL, NULL, NULL);
}
void file_tool_props_region_panels_register(ARegionType *art)
@@ -128,12 +128,12 @@ static void file_panel_execution_execute_button(uiLayout *layout, const char *ti
uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
}
-static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
+static void file_panel_execution_buttons_draw(const bContext *C, Panel *panel)
{
bScreen *screen = CTX_wm_screen(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_params(sfile);
- uiBlock *block = uiLayoutGetBlock(pa->layout);
+ uiBlock *block = uiLayoutGetBlock(panel->layout);
uiBut *but;
uiLayout *row;
PointerRNA params_rna_ptr, *but_extra_rna_ptr;
@@ -148,7 +148,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &params_rna_ptr);
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
uiLayoutSetScaleY(row, 1.3f);
/* callbacks for operator check functions */
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index dec38501d38..d8d7ef01a2e 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -264,7 +264,7 @@ enum {
typedef struct FileListEntryPreview {
char path[FILE_MAX];
- unsigned int flags;
+ uint flags;
int index;
ImBuf *img;
} FileListEntryPreview;
@@ -635,7 +635,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi
/* filename might actually be a piece of path, in which case we have to check all its parts. */
bool hidden = false;
- char *sep = (char *)BLI_last_slash(filename);
+ char *sep = (char *)BLI_path_slash_rfind(filename);
if (!hidden && sep) {
char tmp_filename[FILE_MAX_LIBEXTRA];
@@ -654,7 +654,7 @@ static bool is_hidden_dot_filename(const char *filename, FileListInternEntry *fi
break;
}
*sep = '\0';
- sep = (char *)BLI_last_slash(tmp_filename);
+ sep = (char *)BLI_path_slash_rfind(tmp_filename);
}
}
return hidden;
@@ -1015,6 +1015,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
/* If this path is in System list or path cache then use that icon. */
struct FSMenu *fsmenu = ED_fsmenu_get();
FSMenuCategory categories[] = {
+ FS_CATEGORY_SYSTEM,
FS_CATEGORY_SYSTEM_BOOKMARKS,
FS_CATEGORY_OTHER,
};
@@ -1022,10 +1023,16 @@ static int filelist_geticon_ex(FileDirEntry *file,
for (int i = 0; i < ARRAY_SIZE(categories); i++) {
FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, categories[i]);
char fullpath[FILE_MAX_LIBEXTRA];
- BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
- BLI_add_slash(fullpath);
+ char *target = fullpath;
+ if (file->redirection_path) {
+ target = file->redirection_path;
+ }
+ else {
+ BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath);
+ BLI_path_slash_ensure(fullpath);
+ }
for (; tfsm; tfsm = tfsm->next) {
- if (STREQ(tfsm->path, fullpath)) {
+ if (STREQ(tfsm->path, target)) {
/* Never want a little folder inside a large one. */
return (tfsm->icon == ICON_FILE_FOLDER) ? ICON_NONE : tfsm->icon;
}
@@ -1033,10 +1040,7 @@ static int filelist_geticon_ex(FileDirEntry *file,
}
}
- if (file->attributes & FILE_ATTR_ANY_LINK) {
- return ICON_LOOP_FORWARDS;
- }
- else if (file->attributes & FILE_ATTR_OFFLINE) {
+ if (file->attributes & FILE_ATTR_OFFLINE) {
return ICON_ERROR;
}
else if (file->attributes & FILE_ATTR_TEMPORARY) {
@@ -1112,7 +1116,7 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
static void parent_dir_until_exists_or_default_root(char *dir)
{
- if (!BLI_parent_dir_until_exists(dir)) {
+ if (!BLI_path_parent_dir_until_exists(dir)) {
#ifdef WIN32
get_default_root(dir);
#else
@@ -1264,11 +1268,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern)
MEM_SAFE_FREE(filelist_intern->filtered);
}
-static void filelist_cache_preview_runf(TaskPool *__restrict pool,
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata)
{
- FileListEntryCache *cache = BLI_task_pool_userdata(pool);
+ FileListEntryCache *cache = BLI_task_pool_user_data(pool);
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1306,9 +1308,7 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool,
// printf("%s: End (%d)...\n", __func__, threadid);
}
-static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
- void *taskdata,
- int UNUSED(threadid))
+static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata)
{
FileListEntryPreviewTaskData *preview_taskdata = taskdata;
FileListEntryPreview *preview = preview_taskdata->preview;
@@ -1327,9 +1327,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool),
static void filelist_cache_preview_ensure_running(FileListEntryCache *cache)
{
if (!cache->previews_pool) {
- TaskScheduler *scheduler = BLI_task_scheduler_get();
-
- cache->previews_pool = BLI_task_pool_create_background(scheduler, cache);
+ cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW);
cache->previews_done = BLI_thread_queue_init();
IMB_thumb_locks_acquire();
@@ -1381,8 +1379,15 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
(entry->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT |
FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP | FILE_TYPE_BLENDERLIB))) {
FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__);
- BLI_join_dirfile(
- preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+
+ if (entry->redirection_path) {
+ BLI_strncpy(preview->path, entry->redirection_path, FILE_MAXDIR);
+ }
+ else {
+ BLI_join_dirfile(
+ preview->path, sizeof(preview->path), filelist->filelist.root, entry->relpath);
+ }
+
preview->index = index;
preview->flags = entry->typeflag;
preview->img = NULL;
@@ -1393,12 +1398,11 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry
FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata),
__func__);
preview_taskdata->preview = preview;
- BLI_task_pool_push_ex(cache->previews_pool,
- filelist_cache_preview_runf,
- preview_taskdata,
- true,
- filelist_cache_preview_freef,
- TASK_PRIORITY_LOW);
+ BLI_task_pool_push(cache->previews_pool,
+ filelist_cache_preview_runf,
+ preview_taskdata,
+ true,
+ filelist_cache_preview_freef);
}
}
@@ -1624,7 +1628,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
{
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
- BLI_cleanup_dir(BKE_main_blendfile_path_from_global(), r_dir);
+ BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir);
const bool is_valid_path = filelist->checkdirf(filelist, r_dir, true);
BLI_assert(is_valid_path);
UNUSED_VARS_NDEBUG(is_valid_path);
@@ -2277,13 +2281,6 @@ int ED_path_extension_type(const char *path)
return 0;
}
-static int file_extension_type(const char *dir, const char *relpath)
-{
- char path[FILE_MAX];
- BLI_join_dirfile(path, sizeof(path), dir, relpath);
- return ED_path_extension_type(path);
-}
-
int ED_file_extension_icon(const char *path)
{
const int type = ED_path_extension_type(path);
@@ -2325,16 +2322,16 @@ int filelist_empty(struct FileList *filelist)
return (filelist->filelist.nbr_entries == 0);
}
-unsigned int filelist_entry_select_set(const FileList *filelist,
- const FileDirEntry *entry,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+uint filelist_entry_select_set(const FileList *filelist,
+ const FileDirEntry *entry,
+ FileSelType select,
+ uint flag,
+ FileCheckType check)
{
/* Default NULL pointer if not found is fine here! */
void **es_p = BLI_ghash_lookup_p(filelist->selection_state, entry->uuid);
- unsigned int entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
- const unsigned int org_entry_flag = entry_flag;
+ uint entry_flag = es_p ? POINTER_AS_UINT(*es_p) : 0;
+ const uint org_entry_flag = entry_flag;
BLI_assert(entry);
BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
@@ -2373,11 +2370,8 @@ unsigned int filelist_entry_select_set(const FileList *filelist,
return entry_flag;
}
-void filelist_entry_select_index_set(FileList *filelist,
- const int index,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+void filelist_entry_select_index_set(
+ FileList *filelist, const int index, FileSelType select, uint flag, FileCheckType check)
{
FileDirEntry *entry = filelist_file(filelist, index);
@@ -2386,11 +2380,8 @@ void filelist_entry_select_index_set(FileList *filelist,
}
}
-void filelist_entries_select_index_range_set(FileList *filelist,
- FileSelection *sel,
- FileSelType select,
- unsigned int flag,
- FileCheckType check)
+void filelist_entries_select_index_range_set(
+ FileList *filelist, FileSelection *sel, FileSelType select, uint flag, FileCheckType check)
{
/* select all valid files between first and last indicated */
if ((sel->first >= 0) && (sel->first < filelist->filelist.nbr_entries_filtered) &&
@@ -2402,9 +2393,7 @@ void filelist_entries_select_index_range_set(FileList *filelist,
}
}
-unsigned int filelist_entry_select_get(FileList *filelist,
- FileDirEntry *entry,
- FileCheckType check)
+uint filelist_entry_select_get(FileList *filelist, FileDirEntry *entry, FileCheckType check)
{
BLI_assert(entry);
BLI_assert(ELEM(check, CHECK_DIRS, CHECK_FILES, CHECK_ALL));
@@ -2418,9 +2407,7 @@ unsigned int filelist_entry_select_get(FileList *filelist,
return 0;
}
-unsigned int filelist_entry_select_index_get(FileList *filelist,
- const int index,
- FileCheckType check)
+uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCheckType check)
{
FileDirEntry *entry = filelist_file(filelist, index);
@@ -2436,7 +2423,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist,
*/
void filelist_entry_parent_select_set(FileList *filelist,
FileSelType select,
- unsigned int flag,
+ uint flag,
FileCheckType check)
{
if ((filelist->filter_data.flags & FLF_HIDE_PARENT) == 0) {
@@ -2458,7 +2445,7 @@ static int groupname_to_code(const char *group)
BLI_assert(group);
BLI_strncpy(buf, group, sizeof(buf));
- lslash = (char *)BLI_last_slash(buf);
+ lslash = (char *)BLI_path_slash_rfind(buf);
if (lslash) {
lslash[0] = '\0';
}
@@ -2492,7 +2479,8 @@ static int filelist_readjob_list_dir(const char *root,
{
struct direntry *files;
int nbr_files, nbr_entries = 0;
- char path[FILE_MAX];
+ /* Full path of the item. */
+ char full_path[FILE_MAX];
nbr_files = BLI_filelist_dir_contents(root, &files);
if (files) {
@@ -2508,38 +2496,53 @@ static int filelist_readjob_list_dir(const char *root,
entry->relpath = MEM_dupallocN(files[i].relname);
entry->st = files[i].s;
- BLI_join_dirfile(path, sizeof(path), root, entry->relpath);
+ BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath);
+ char *target = full_path;
- /* Set file type. */
+ /* Set initial file type and attributes. */
+ entry->attributes = BLI_file_attributes(full_path);
if (S_ISDIR(files[i].s.st_mode)) {
entry->typeflag = FILE_TYPE_DIR;
}
- else if (do_lib && BLO_has_bfile_extension(entry->relpath)) {
- /* If we are considering .blend files as libs, promote them to directory status. */
- entry->typeflag = FILE_TYPE_BLENDER;
- /* prevent current file being used as acceptable dir */
- if (BLI_path_cmp(main_name, path) != 0) {
- entry->typeflag |= FILE_TYPE_DIR;
- }
- }
- /* Otherwise, do not check extensions for directories! */
- else if (!(entry->typeflag & FILE_TYPE_DIR)) {
- entry->typeflag = file_extension_type(root, entry->relpath);
- if (filter_glob[0] && BLI_path_extension_check_glob(entry->relpath, filter_glob)) {
- entry->typeflag |= FILE_TYPE_OPERATOR;
- }
- }
- /* Set file attributes. */
- entry->attributes = BLI_file_attributes(path);
+ /* Is this a file that points to another file? */
if (entry->attributes & FILE_ATTR_ALIAS) {
entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__);
- if (BLI_file_alias_target(entry->redirection_path, path)) {
+ if (BLI_file_alias_target(entry->redirection_path, full_path)) {
if (BLI_is_dir(entry->redirection_path)) {
entry->typeflag = FILE_TYPE_DIR;
+ BLI_path_slash_ensure(entry->redirection_path);
}
- else
+ else {
entry->typeflag = ED_path_extension_type(entry->redirection_path);
+ }
+ target = entry->redirection_path;
+#ifdef WIN32
+ /* On Windows don't show ".lnk" extension for valid shortcuts. */
+ BLI_path_extension_replace(entry->relpath, FILE_MAXDIR, "");
+#endif
+ }
+ else {
+ MEM_freeN(entry->redirection_path);
+ entry->redirection_path = NULL;
+ entry->attributes |= FILE_ATTR_HIDDEN;
+ }
+ }
+
+ if (!(entry->typeflag & FILE_TYPE_DIR)) {
+ if (do_lib && BLO_has_bfile_extension(target)) {
+ /* If we are considering .blend files as libs, promote them to directory status. */
+ entry->typeflag = FILE_TYPE_BLENDER;
+ /* prevent current file being used as acceptable dir */
+ if (BLI_path_cmp(main_name, target) != 0) {
+ entry->typeflag |= FILE_TYPE_DIR;
+ }
+ }
+ else {
+ entry->typeflag = ED_path_extension_type(target);
+ if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) {
+ entry->typeflag |= FILE_TYPE_OPERATOR;
+ }
}
}
@@ -2627,7 +2630,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const
/* Kept for reference here, in case we want to add back that feature later.
* We do not need it currently. */
/* Code ***NOT*** updated for job stuff! */
-static void filelist_readjob_main_rec(Main *bmain, FileList *filelist)
+static void filelist_readjob_main_recursive(Main *bmain, FileList *filelist)
{
ID *id;
FileDirEntry *files, *firstlib = NULL;
@@ -2826,7 +2829,7 @@ static void filelist_readjob_do(const bool do_lib,
BLI_strncpy(dir, filelist->filelist.root, sizeof(dir));
BLI_strncpy(filter_glob, filelist->filter_data.filter_glob, sizeof(filter_glob));
- BLI_cleanup_dir(main_name, dir);
+ BLI_path_normalize_dir(main_name, dir);
td_dir->dir = BLI_strdup(dir);
while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) {
@@ -2852,7 +2855,7 @@ static void filelist_readjob_do(const bool do_lib,
* Note that in the end, this means we 'cache' valid relative subdir once here,
* this is actually better. */
BLI_strncpy(rel_subdir, subdir, sizeof(rel_subdir));
- BLI_cleanup_dir(root, rel_subdir);
+ BLI_path_normalize_dir(root, rel_subdir);
BLI_path_rel(rel_subdir, root);
if (do_lib) {
@@ -2894,7 +2897,7 @@ static void filelist_readjob_do(const bool do_lib,
else {
/* We have a directory we want to list, add it to todo list! */
BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath);
- BLI_cleanup_dir(main_name, dir);
+ BLI_path_normalize_dir(main_name, dir);
td_dir = BLI_stack_push_r(todo_dirs);
td_dir->level = recursion_level + 1;
td_dir->dir = BLI_strdup(dir);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 67c0fae3565..3b62941af83 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -47,6 +47,7 @@
#include "BLI_blenlib.h"
#include "BLI_fnmatch.h"
+#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "BLO_readfile.h"
@@ -156,7 +157,7 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
if (params->dir[0]) {
- BLI_cleanup_dir(blendfile_path, params->dir);
+ BLI_path_normalize_dir(blendfile_path, params->dir);
BLI_path_abs(params->dir, blendfile_path);
}
@@ -758,11 +759,11 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
layout->attribute_column_header_h = 0;
layout->offset_top = 0;
if (layout->flow_columns > 0) {
- layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero
+ layout->rows = divide_ceil_u(numfiles, layout->flow_columns);
}
else {
layout->flow_columns = 1;
- layout->rows = numfiles + 1; // XXX dirty, modulo is zero
+ layout->rows = numfiles;
}
layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) +
layout->tile_border_y * 2 - layout->offset_top;
@@ -807,11 +808,11 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *region)
file_attribute_columns_init(params, layout);
if (layout->rows > 0) {
- layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = divide_ceil_u(numfiles, layout->rows);
}
else {
layout->rows = 1;
- layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero
+ layout->flow_columns = numfiles;
}
layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) +
layout->tile_border_x * 2;
@@ -924,7 +925,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
match = UI_autocomplete_end(autocpl, str);
if (match == AUTOCOMPLETE_FULL_MATCH) {
- BLI_add_slash(str);
+ BLI_path_slash_ensure(str);
}
}
}
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 66157296064..b03df01a02b 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -418,7 +418,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu,
else {
/* if we're bookmarking this, file should come
* before the last separator, only automatically added
- * current dir go after the last sep. */
+ * current dir go after the last separator. */
if (flag & FS_INSERT_SAVE) {
break;
}
@@ -848,6 +848,10 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(volEnum);
+ /* kLSSharedFileListFavoriteItems is deprecated, but available till macOS 10.15.
+ * Will have to find a new method to sync the Finder Favorites with File Browser. */
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* Finally get user favorite places */
if (read_bookmarks) {
UInt32 seed;
@@ -891,6 +895,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
CFRelease(pathesArray);
CFRelease(list);
}
+# pragma GCC diagnostic pop
}
# else
/* unix */
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 0ac838f9d0c..319d74f5fad 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,16 +55,16 @@
#include "filelist.h"
#include "fsmenu.h"
-static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+static ARegion *file_execute_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
- if ((region = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ if ((region = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE)) != NULL) {
return region;
}
region = MEM_callocN(sizeof(ARegion), "execute region for file");
- BLI_insertlinkafter(&sa->regionbase, ar_prev, region);
+ BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_EXECUTE;
region->alignment = RGN_ALIGN_BOTTOM;
region->flag = RGN_FLAG_DYNAMIC_SIZE;
@@ -72,17 +72,17 @@ static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
return region;
}
-static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+static ARegion *file_tool_props_region_ensure(ScrArea *area, ARegion *region_prev)
{
ARegion *region;
- if ((region = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ if ((region = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS)) != NULL) {
return region;
}
/* add subdiv level; after execute region */
region = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, ar_prev, region);
+ BLI_insertlinkafter(&area->regionbase, region_prev, region);
region->regiontype = RGN_TYPE_TOOL_PROPS;
region->alignment = RGN_ALIGN_RIGHT;
@@ -173,18 +173,18 @@ static void file_free(SpaceLink *sl)
}
/* spacetype; init callback, area size changes, screen set, etc */
-static void file_init(wmWindowManager *UNUSED(wm), ScrArea *sa)
+static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area)
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
if (sfile->layout) {
sfile->layout->dirty = true;
}
}
-static void file_exit(wmWindowManager *wm, ScrArea *sa)
+static void file_exit(wmWindowManager *wm, ScrArea *area)
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
if (sfile->previews_timer) {
WM_event_remove_timer_notifier(wm, NULL, sfile->previews_timer);
@@ -228,44 +228,44 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
static void file_ensure_valid_region_state(bContext *C,
wmWindowManager *wm,
wmWindow *win,
- ScrArea *sa,
+ ScrArea *area,
SpaceFile *sfile,
FileSelectParams *params)
{
- ARegion *ar_ui = BKE_area_find_region_type(sa, RGN_TYPE_UI);
- ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS);
- ARegion *ar_execute = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
+ ARegion *region_ui = BKE_area_find_region_type(area, RGN_TYPE_UI);
+ ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_TOOL_PROPS);
+ ARegion *region_execute = BKE_area_find_region_type(area, RGN_TYPE_EXECUTE);
bool needs_init = false; /* To avoid multiple ED_area_initialize() calls. */
/* If there's an file-operation, ensure we have the option and execute region */
- if (sfile->op && (ar_props == NULL)) {
- ar_execute = file_execute_region_ensure(sa, ar_ui);
- ar_props = file_tool_props_region_ensure(sa, ar_execute);
+ if (sfile->op && (region_props == NULL)) {
+ region_execute = file_execute_region_ensure(area, region_ui);
+ region_props = file_tool_props_region_ensure(area, region_execute);
if (params->flag & FILE_HIDE_TOOL_PROPS) {
- ar_props->flag |= RGN_FLAG_HIDDEN;
+ region_props->flag |= RGN_FLAG_HIDDEN;
}
else {
- ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ region_props->flag &= ~RGN_FLAG_HIDDEN;
}
needs_init = true;
}
/* If there's _no_ file-operation, ensure we _don't_ have the option and execute region */
- else if ((sfile->op == NULL) && (ar_props != NULL)) {
- BLI_assert(ar_execute != NULL);
+ else if ((sfile->op == NULL) && (region_props != NULL)) {
+ BLI_assert(region_execute != NULL);
- ED_region_remove(C, sa, ar_props);
- ED_region_remove(C, sa, ar_execute);
+ ED_region_remove(C, area, region_props);
+ ED_region_remove(C, area, region_execute);
needs_init = true;
}
if (needs_init) {
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
}
-static void file_refresh(const bContext *C, ScrArea *sa)
+static void file_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
@@ -333,34 +333,34 @@ static void file_refresh(const bContext *C, ScrArea *sa)
sfile->layout->dirty = true;
}
- /* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa) {
- file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
+ /* Might be called with NULL area, see file_main_region_draw() below. */
+ if (area) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, area, sfile, params);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
static void file_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceFile *sfile = (SpaceFile *)sa->spacedata.first;
+ SpaceFile *sfile = (SpaceFile *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_SPACE:
switch (wmn->data) {
case ND_SPACE_FILE_LIST:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_SPACE_FILE_PARAMS:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_SPACE_FILE_PREVIEW:
if (sfile->files && filelist_cache_previews_update(sfile->files)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
}
@@ -384,7 +384,7 @@ static void file_main_region_init(wmWindowManager *wm, ARegion *region)
}
static void file_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -408,18 +408,18 @@ static void file_main_region_message_subscribe(const struct bContext *UNUSED(C),
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceFile *sfile = sa->spacedata.first;
+ SpaceFile *sfile = area->spacedata.first;
FileSelectParams *params = ED_fileselect_get_params(sfile);
/* This is a bit odd that a region owns the subscriber for an area,
* keep for now since all subscribers for WM are regions.
* May be worth re-visiting later. */
wmMsgSubscribeValue msg_sub_value_area_tag_refresh = {
.owner = region,
- .user_data = sa,
+ .user_data = area,
.notify = ED_area_do_msg_notify_tag_refresh,
};
@@ -575,7 +575,7 @@ static void file_tools_region_draw(const bContext *C, ARegion *region)
}
static void file_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -643,7 +643,7 @@ static void file_execution_region_draw(const bContext *C, ARegion *region)
}
static void file_ui_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index c2aa74a695e..179d73a38ba 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -38,10 +38,11 @@
#include "BLT_translation.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
@@ -111,9 +112,9 @@ static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt))
/* -------------- */
-static void graph_panel_cursor_header(const bContext *C, Panel *pa)
+static void graph_panel_cursor_header(const bContext *C, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
SpaceGraph *sipo = CTX_wm_space_graph(C);
Scene *scene = CTX_data_scene(C);
PointerRNA spaceptr, sceneptr;
@@ -121,25 +122,25 @@ static void graph_panel_cursor_header(const bContext *C, Panel *pa)
/* get RNA pointers for use when creating the UI elements */
RNA_id_pointer_create(&scene->id, &sceneptr);
- RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
/* 2D-Cursor */
- col = uiLayoutColumn(pa->layout, false);
+ col = uiLayoutColumn(panel->layout, false);
uiItemR(col, &spaceptr, "show_cursor", 0, "", ICON_NONE);
}
-static void graph_panel_cursor(const bContext *C, Panel *pa)
+static void graph_panel_cursor(const bContext *C, Panel *panel)
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
SpaceGraph *sipo = CTX_wm_space_graph(C);
Scene *scene = CTX_data_scene(C);
PointerRNA spaceptr, sceneptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col, *sub;
/* get RNA pointers for use when creating the UI elements */
RNA_id_pointer_create(&scene->id, &sceneptr);
- RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
@@ -164,12 +165,12 @@ static void graph_panel_cursor(const bContext *C, Panel *pa)
/* ******************* active F-Curve ************** */
-static void graph_panel_properties(const bContext *C, Panel *pa)
+static void graph_panel_properties(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
PointerRNA fcu_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
char name[256];
int icon = 0;
@@ -294,7 +295,7 @@ static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bez
bezt->h2 = HD_ALIGN;
}
else {
- BKE_nurb_bezt_handle_test(bezt, SELECT, true);
+ BKE_nurb_bezt_handle_test(bezt, SELECT, true, false);
}
/* now call standard updates */
@@ -345,13 +346,13 @@ static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr
bezt->f3 = f3;
}
-static void graph_panel_key_properties(const bContext *C, Panel *pa)
+static void graph_panel_key_properties(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
BezTriple *bezt, *prevbezt;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
const ARegion *region = CTX_wm_region(C);
/* Just a width big enough so buttons use entire layout width (will be clamped by it then). */
const int but_max_width = region->winx;
@@ -422,8 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
col = uiLayoutColumn(layout, true);
/* keyframe itself */
{
-
- uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -434,16 +434,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 1,
+ 0,
0,
0,
-1,
-1,
NULL);
- UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
- UI_but_unit_type_set(but, unit);
- uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -454,21 +452,42 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
UI_UNIT_Y,
&bezt_ptr,
"co",
- 0,
+ 1,
0,
0,
-1,
-1,
NULL);
UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
+ UI_but_unit_type_set(but, unit);
+
+ UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt);
}
/* previous handle - only if previous was Bezier interpolation */
if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) {
col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE);
+ but = uiDefButR(block,
+ UI_BTYPE_MENU,
+ B_REDR,
+ NULL,
+ 0,
+ 0,
+ but_max_width,
+ UI_UNIT_Y,
+ &bezt_ptr,
+ "handle_left_type",
+ 0,
+ 0,
+ 0,
+ -1,
+ -1,
+ "Type of left handle");
+ UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -487,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -506,8 +525,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
+ }
+
+ /* next handle - only if current is Bezier interpolation */
+ if (bezt->ipo == BEZT_IPO_BEZ) {
+ /* NOTE: special update callbacks are needed on the coords here due to T39911 */
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
+ col = uiLayoutColumn(layout, true);
+ uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_MENU,
B_REDR,
@@ -517,22 +542,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
but_max_width,
UI_UNIT_Y,
&bezt_ptr,
- "handle_left_type",
+ "handle_right_type",
0,
0,
0,
-1,
-1,
- "Type of left handle");
+ "Type of right handle");
UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
- }
- /* next handle - only if current is Bezier interpolation */
- if (bezt->ipo == BEZT_IPO_BEZ) {
- /* NOTE: special update callbacks are needed on the coords here due to T39911 */
-
- col = uiLayoutColumn(layout, true);
- uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -551,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
- uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE);
+ uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE);
but = uiDefButR(block,
UI_BTYPE_NUM,
B_REDR,
@@ -570,25 +589,6 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
NULL);
UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt);
UI_but_unit_type_set(but, unit);
-
- uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE);
- but = uiDefButR(block,
- UI_BTYPE_MENU,
- B_REDR,
- NULL,
- 0,
- 0,
- but_max_width,
- UI_UNIT_Y,
- &bezt_ptr,
- "handle_right_type",
- 0,
- 0,
- 0,
- -1,
- -1,
- "Type of right handle");
- UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt);
}
}
else {
@@ -1227,7 +1227,7 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
/* Panel to show property driven by the driver (in Drivers Editor) - duplicates Active FCurve,
* but useful for clarity. */
-static void graph_panel_driven_property(const bContext *C, Panel *pa)
+static void graph_panel_driven_property(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1236,14 +1236,14 @@ static void graph_panel_driven_property(const bContext *C, Panel *pa)
return;
}
- graph_draw_driven_property_panel(pa->layout, ale->id, fcu);
+ graph_draw_driven_property_panel(panel->layout, ale->id, fcu);
MEM_freeN(ale);
}
/* driver settings for active F-Curve
* (only for 'Drivers' mode in Graph Editor, i.e. the full "Drivers Editor") */
-static void graph_panel_drivers(const bContext *C, Panel *pa)
+static void graph_panel_drivers(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1253,7 +1253,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
return;
}
- graph_draw_driver_settings_panel(pa->layout, ale->id, fcu, false);
+ graph_draw_driver_settings_panel(panel->layout, ale->id, fcu, false);
/* cleanup */
MEM_freeN(ale);
@@ -1269,9 +1269,9 @@ static bool graph_panel_drivers_popover_poll(const bContext *C, PanelType *UNUSE
}
/* popover panel for driver editing anywhere in ui */
-static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
+static void graph_panel_drivers_popover(const bContext *C, Panel *panel)
{
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
PointerRNA ptr = {NULL};
PropertyRNA *prop = NULL;
@@ -1284,7 +1284,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
FCurve *fcu;
bool driven, special;
- fcu = rna_get_fcurve_context_ui(
+ fcu = BKE_fcurve_find_by_rna_context_ui(
(bContext *)C, &ptr, prop, index, NULL, NULL, &driven, &special);
/* Hack: Force all buttons in this panel to be able to know the driver button
@@ -1303,7 +1303,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
/* Driven Property Settings */
uiItemL(layout, IFACE_("Driven Property:"), ICON_NONE);
- graph_draw_driven_property_panel(pa->layout, id, fcu);
+ graph_draw_driven_property_panel(panel->layout, id, fcu);
/* TODO: All vs Single */
uiItemS(layout);
@@ -1311,7 +1311,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *pa)
/* Drivers Settings */
uiItemL(layout, IFACE_("Driver Settings:"), ICON_NONE);
- graph_draw_driver_settings_panel(pa->layout, id, fcu, true);
+ graph_draw_driver_settings_panel(panel->layout, id, fcu, true);
}
}
@@ -1334,7 +1334,7 @@ static void do_graph_region_modifier_buttons(bContext *C, void *UNUSED(arg), int
}
}
-static void graph_panel_modifiers(const bContext *C, Panel *pa)
+static void graph_panel_modifiers(const bContext *C, Panel *panel)
{
bAnimListElem *ale;
FCurve *fcu;
@@ -1347,12 +1347,12 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
return;
}
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_graph_region_modifier_buttons, NULL);
/* 'add modifier' button at top of panel */
{
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
/* this is an operator button which calls a 'add modifier' operator...
* a menu might be nicer but would be tricky as we need some custom filtering
@@ -1369,7 +1369,7 @@ static void graph_panel_modifiers(const bContext *C, Panel *pa)
active = !(fcu->flag & FCURVE_MOD_OFF);
/* draw each modifier */
for (fcm = fcu->modifiers.first; fcm; fcm = fcm->next) {
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
uiLayoutSetActive(col, active);
ANIM_uiTemplate_fmodifier_draw(col, ale->fcurve_owner_id, &fcu->modifiers, fcm);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index eac87caf777..f2071d292ca 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -343,6 +343,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
uint color = GPU_vertformat_attr_add(
format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(true);
+ }
+ GPU_blend(true);
immBeginAtMost(GPU_PRIM_LINES, 4 * 2 * fcu->totvert);
@@ -419,6 +423,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu)
immEnd();
immUnbindProgram();
+ GPU_blend(false);
+ if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) {
+ GPU_line_smooth(false);
+ }
}
/* Samples ---------------- */
@@ -1151,7 +1159,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
* we must obey this.
*/
if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) {
- if (!fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) {
+ if (!BKE_fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) {
/* only draw controls if this is the active modifier */
if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
switch (fcm->type) {
@@ -1181,9 +1189,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor
if (do_handles) {
/* only draw handles/vertices on keyframes */
- GPU_blend(true);
draw_fcurve_handles(sipo, fcu);
- GPU_blend(false);
}
draw_fcurve_vertices(region, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY));
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 8c64fb5bb40..03151da8d4d 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -126,7 +126,8 @@ void get_graph_keyframe_extents(bAnimContext *ac,
float unitFac, offset;
/* get range */
- if (calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
+ if (BKE_fcurve_calc_bounds(
+ fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles)) {
short mapping_flag = ANIM_get_normalization_flags(ac);
/* apply NLA scaling */
@@ -328,7 +329,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op)
void GRAPH_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "GRAPH_OT_view_all";
ot->description = "Reset viewable area to show full keyframe range";
@@ -385,7 +386,7 @@ void GRAPH_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "GRAPH_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = graphkeys_view_frame_exec;
@@ -409,7 +410,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
int filter;
/* free existing ghost curves */
- free_fcurves(&sipo->runtime.ghost_curves);
+ BKE_fcurves_free(&sipo->runtime.ghost_curves);
/* sanity check */
if (start >= end) {
@@ -425,7 +426,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
/* loop through filtered data and add keys between selected keyframes on every frame */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
- FCurve *gcu = MEM_callocN(sizeof(FCurve), "Ghost FCurve");
+ FCurve *gcu = BKE_fcurve_create();
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver = fcu->driver;
FPoint *fpt;
@@ -536,7 +537,7 @@ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
/* free ghost curves */
- free_fcurves(&sipo->runtime.ghost_curves);
+ BKE_fcurves_free(&sipo->runtime.ghost_curves);
/* update this editor only */
ED_area_tag_redraw(CTX_wm_area(C));
@@ -806,7 +807,7 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
/* when there are F-Modifiers on the curve, only allow adding
* keyframes if these will be visible after doing so...
*/
- if (fcurve_is_keyframable(fcu)) {
+ if (BKE_fcurve_is_keyframable(fcu)) {
ListBase anim_data;
ToolSettings *ts = ac.scene->toolsettings;
@@ -1336,7 +1337,7 @@ static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float erro
typedef struct tDecimateGraphOp {
bAnimContext ac;
Scene *scene;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
/** A 0-1 value for determining how much we should decimate. */
@@ -1409,7 +1410,7 @@ static void decimate_exit(bContext *C, wmOperator *op)
return;
}
- ScrArea *sa = dgo->sa;
+ ScrArea *area = dgo->area;
LinkData *link;
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
@@ -1423,7 +1424,7 @@ static void decimate_exit(bContext *C, wmOperator *op)
/* Return to normal cursor and header status. */
WM_cursor_modal_restore(win);
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
/* cleanup */
op->customdata = NULL;
@@ -1450,7 +1451,7 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
}
- ED_area_status_text(dgo->sa, status_str);
+ ED_area_status_text(dgo->area, status_str);
}
/* Calculate percentage based on position of mouse (we only use x-axis for now.
@@ -1482,7 +1483,7 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio");
dgo->scene = CTX_data_scene(C);
- dgo->sa = CTX_wm_area(C);
+ dgo->area = CTX_wm_area(C);
dgo->region = CTX_wm_region(C);
/* initialise percentage so that it will have the correct value before the first mouse move. */
@@ -2647,7 +2648,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
for (f = 0; f < 3; f++) {
FCurve *fcu = euf->fcurves[f];
BezTriple *bezt, *prev;
- unsigned int i;
+ uint i;
/* skip if not enough vets to do a decent analysis of... */
if (fcu->totvert <= 2) {
@@ -3569,7 +3570,7 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
bAnimListElem *ale;
int filter;
bool ok = false;
- unsigned int deleted = 0;
+ uint deleted = 0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -3623,10 +3624,10 @@ static int graph_driver_delete_invalid_exec(bContext *C, wmOperator *op)
static bool graph_driver_delete_invalid_poll(bContext *C)
{
bAnimContext ac;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* firstly, check if in Graph Editor */
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index a2e9ba86dec..ae435b5624a 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -760,8 +760,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
data_lasso.rectf_view = &rect_fl;
- data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
- if (data_lasso.mcords == NULL) {
+ data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len);
+ if (data_lasso.mcoords == NULL) {
return OPERATOR_CANCELLED;
}
@@ -782,13 +782,13 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
}
/* get settings from operator */
- BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
+ BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len);
BLI_rctf_rcti_copy(&rect_fl, &rect);
/* apply box_select action */
box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso);
- MEM_freeN((void *)data_lasso.mcords);
+ MEM_freeN((void *)data_lasso.mcoords);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 0af94904ba6..03ed8870d67 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -54,40 +54,40 @@
/* Set up UI configuration for Drivers Editor */
/* NOTE: Currently called from windowmanager
* (new drivers editor window) and RNA (mode switching) */
-void ED_drivers_editor_init(bContext *C, ScrArea *sa)
+void ED_drivers_editor_init(bContext *C, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* Set mode */
sipo->mode = SIPO_MODE_DRIVERS;
/* Show Properties Region (or else the settings can't be edited) */
- ARegion *ar_props = BKE_area_find_region_type(sa, RGN_TYPE_UI);
- if (ar_props) {
- UI_panel_category_active_set(ar_props, "Drivers");
+ ARegion *region_props = BKE_area_find_region_type(area, RGN_TYPE_UI);
+ if (region_props) {
+ UI_panel_category_active_set(region_props, "Drivers");
- ar_props->flag &= ~RGN_FLAG_HIDDEN;
+ region_props->flag &= ~RGN_FLAG_HIDDEN;
/* XXX: Adjust width of this too? */
- ED_region_visibility_change_update(C, sa, ar_props);
+ ED_region_visibility_change_update(C, area, region_props);
}
else {
- printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, sa);
+ printf("%s: Couldn't find properties region for Drivers Editor - %p\n", __func__, area);
}
/* Adjust framing in graph region */
/* TODO: Have a way of not resetting this every time?
* (e.g. So that switching back and forth between editors doesn't keep jumping?)
*/
- ARegion *ar_main = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar_main) {
+ ARegion *region_main = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
+ if (region_main) {
/* XXX: Ideally we recenter based on the range instead... */
- ar_main->v2d.tot.xmin = -2.0f;
- ar_main->v2d.tot.ymin = -2.0f;
- ar_main->v2d.tot.xmax = 2.0f;
- ar_main->v2d.tot.ymax = 2.0f;
+ region_main->v2d.tot.xmin = -2.0f;
+ region_main->v2d.tot.ymin = -2.0f;
+ region_main->v2d.tot.xmax = 2.0f;
+ region_main->v2d.tot.ymax = 2.0f;
- ar_main->v2d.cur = ar_main->v2d.tot;
+ region_main->v2d.cur = region_main->v2d.tot;
}
}
@@ -135,14 +135,14 @@ bool graphop_visible_keyframes_poll(bContext *C)
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -171,7 +171,7 @@ bool graphop_visible_keyframes_poll(bContext *C)
if (fcu->bezt == NULL) {
continue;
}
- if (fcurve_are_keyframes_usable(fcu)) {
+ if (BKE_fcurve_are_keyframes_usable(fcu)) {
found = 1;
break;
}
@@ -188,14 +188,14 @@ bool graphop_editable_keyframes_poll(bContext *C)
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -225,7 +225,7 @@ bool graphop_editable_keyframes_poll(bContext *C)
if (fcu->bezt == NULL) {
continue;
}
- if (fcurve_is_keyframable(fcu)) {
+ if (BKE_fcurve_is_keyframable(fcu)) {
found = 1;
break;
}
@@ -241,12 +241,12 @@ bool graphop_active_fcurve_poll(bContext *C)
{
bAnimContext ac;
bAnimListElem *ale;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool has_fcurve = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
@@ -293,13 +293,13 @@ bool graphop_selected_fcurve_poll(bContext *C)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
size_t items;
int filter;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
- if ((sa == NULL) || (sa->spacetype != SPACE_GRAPH)) {
+ if ((area == NULL) || (area->spacetype != SPACE_GRAPH)) {
return 0;
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 05edfccd6a8..b9c7c529620 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -64,7 +64,7 @@
/* ******************** default callbacks for ipo space ***************** */
-static SpaceLink *graph_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *graph_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
SpaceGraph *sipo;
@@ -145,14 +145,14 @@ static void graph_free(SpaceLink *sl)
}
if (si->runtime.ghost_curves.first) {
- free_fcurves(&si->runtime.ghost_curves);
+ BKE_fcurves_free(&si->runtime.ghost_curves);
}
}
/* spacetype; init callback */
-static void graph_init(struct wmWindowManager *wm, ScrArea *sa)
+static void graph_init(struct wmWindowManager *wm, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (sipo->ads == NULL) {
@@ -165,7 +165,7 @@ static void graph_init(struct wmWindowManager *wm, ScrArea *sa)
* as this is run on each region resize; setting this here will cause selection
* state to be lost on area/region resizing. [#35744]
*/
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
static SpaceLink *graph_duplicate(SpaceLink *sl)
@@ -413,7 +413,7 @@ static void graph_buttons_region_draw(const bContext *C, ARegion *region)
}
static void graph_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -483,12 +483,12 @@ static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceGraphEditor, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -556,11 +556,11 @@ static void graph_region_message_subscribe(const struct bContext *UNUSED(C),
/* editor level listener */
static void graph_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -568,10 +568,10 @@ static void graph_listener(wmWindow *UNUSED(win),
/* for selection changes of animation data, we can just redraw...
* otherwise autocolor might need to be done again */
if (ELEM(wmn->data, ND_KEYFRAME, ND_ANIMCHAN) && (wmn->action == NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
else {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SCENE:
@@ -580,11 +580,11 @@ static void graph_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_OB_SELECT:
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -594,13 +594,13 @@ static void graph_listener(wmWindow *UNUSED(win),
* (needs flag set to do syncing). */
case ND_BONE_ACTIVE:
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_TRANSFORM:
break; /*do nothing*/
default: /* just redrawing the view will do */
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -608,26 +608,26 @@ static void graph_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_SELECTED) {
/* selection changed, so force refresh to flush (needs flag set to do syncing) */
sipo->runtime.flag |= SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_GRAPH) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_WINDOW:
if (sipo->runtime.flag &
(SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC | SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR)) {
/* force redraw/refresh after undo/redo - prevents "black curve" problem */
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
// XXX: restore the case below if not enough updates occur...
// default:
// if (wmn->data == ND_KEYS)
- // ED_area_tag_redraw(sa);
+ // ED_area_tag_redraw(area);
}
}
@@ -754,9 +754,9 @@ static void graph_refresh_fcurve_colors(const bContext *C)
ANIM_animdata_freelist(&anim_data);
}
-static void graph_refresh(const bContext *C, ScrArea *sa)
+static void graph_refresh(const bContext *C, ScrArea *area)
{
- SpaceGraph *sipo = (SpaceGraph *)sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)area->spacedata.first;
/* updates to data needed depends on Graph Editor mode... */
switch (sipo->mode) {
@@ -780,7 +780,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
if (sipo->runtime.flag & SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC) {
ANIM_sync_animchannels_to_data(C);
sipo->runtime.flag &= ~SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/* We could check 'SIPO_RUNTIME_FLAG_NEED_CHAN_SYNC_COLOR', but color is recalculated anyway. */
@@ -789,7 +789,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
#if 0 /* Done below. */
graph_refresh_fcurve_colors(C);
#endif
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
sipo->runtime.flag &= ~(SIPO_RUNTIME_FLAG_TWEAK_HANDLES_LEFT |
@@ -799,7 +799,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
graph_refresh_fcurve_colors(C);
}
-static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceGraph *sgraph = (SpaceGraph *)slink;
@@ -813,15 +813,15 @@ static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
-static int graph_space_subtype_get(ScrArea *sa)
+static int graph_space_subtype_get(ScrArea *area)
{
- SpaceGraph *sgraph = sa->spacedata.first;
+ SpaceGraph *sgraph = area->spacedata.first;
return sgraph->mode;
}
-static void graph_space_subtype_set(ScrArea *sa, int value)
+static void graph_space_subtype_set(ScrArea *area, int value)
{
- SpaceGraph *sgraph = sa->spacedata.first;
+ SpaceGraph *sgraph = area->spacedata.first;
sgraph->mode = value;
}
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 873091bd68d..6f3ef44fe94 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -656,8 +656,8 @@ static void uiblock_layer_pass_buttons(
/* pass */
rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass) : NULL);
- if (rpass && RE_passes_have_name(rl)) {
- display_name = rpass->name;
+ if (rl && RE_passes_have_name(rl)) {
+ display_name = rpass ? rpass->name : "";
rnd_pt = ui_imageuser_data_copy(&rnd_pt_local);
but = uiDefMenuBut(block,
ui_imageuser_pass_menu,
@@ -1276,7 +1276,7 @@ void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *i
}
else if (ima->source == IMA_SRC_SEQUENCE && ibuf) {
/* Image sequence frame number + filename */
- const char *filename = BLI_last_slash(ibuf->name);
+ const char *filename = BLI_path_slash_rfind(ibuf->name);
filename = (filename == NULL) ? ibuf->name : filename + 1;
BLI_snprintf(str, MAX_IMAGE_INFO_LEN, TIP_("Frame %d: %s"), framenr, filename);
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 85f7f744abc..9040ca5e79c 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -476,7 +476,7 @@ static void sima_draw_zbuf_pixels(
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, x1, y1, rectx, recty, GL_RED, GL_INT, GL_NEAREST, recti, zoomx, zoomy, NULL);
@@ -524,7 +524,7 @@ static void sima_draw_zbuffloat_pixels(Scene *scene,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
immDrawPixelsTex(
&state, x1, y1, rectx, recty, GL_RED, GL_FLOAT, GL_NEAREST, rectf, zoomx, zoomy, NULL);
@@ -575,6 +575,9 @@ static void draw_image_buffer(const bContext *C,
float zoomx,
float zoomy)
{
+ /* Image are still drawn in display space. */
+ glDisable(GL_FRAMEBUFFER_SRGB);
+
int x, y;
int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf);
@@ -634,7 +637,7 @@ static void draw_image_buffer(const bContext *C,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
display_buffer = IMB_display_buffer_acquire(
@@ -666,6 +669,8 @@ static void draw_image_buffer(const bContext *C,
GPU_blend(false);
}
}
+
+ glEnable(GL_FRAMEBUFFER_SRGB);
}
static void draw_image_buffer_repeated(const bContext *C,
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 7f911113b7c..c9f2ec38354 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -264,7 +264,10 @@ void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy)
}
}
-void ED_space_image_get_zoom(SpaceImage *sima, ARegion *region, float *r_zoomx, float *r_zoomy)
+void ED_space_image_get_zoom(SpaceImage *sima,
+ const ARegion *region,
+ float *r_zoomx,
+ float *r_zoomy)
{
int width, height;
@@ -314,7 +317,7 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float *
}
/* takes event->mval */
-void ED_image_mouse_pos(SpaceImage *sima, ARegion *region, const int mval[2], float co[2])
+void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2])
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -341,7 +344,7 @@ void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
}
void ED_image_point_pos(
- SpaceImage *sima, ARegion *region, float x, float y, float *r_x, float *r_y)
+ SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y)
{
int sx, sy, width, height;
float zoomx, zoomy;
@@ -356,7 +359,7 @@ void ED_image_point_pos(
}
void ED_image_point_pos__reverse(SpaceImage *sima,
- ARegion *region,
+ const ARegion *region,
const float co[2],
float r_co[2])
{
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 7bd1b8e8291..8cb85ce9800 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -58,6 +58,7 @@
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_image_save.h"
+#include "BKE_layer.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
@@ -91,6 +92,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_util.h"
+#include "ED_util_imbuf.h"
#include "ED_uvedit.h"
#include "UI_interface.h"
@@ -277,28 +279,6 @@ static bool space_image_main_area_not_uv_brush_poll(bContext *C)
return 0;
}
-static bool image_sample_poll(bContext *C)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- if (sima == NULL) {
- return false;
- }
-
- Object *obedit = CTX_data_edit_object(C);
- if (obedit) {
- /* Disable when UV editing so it doesn't swallow all click events
- * (use for setting cursor). */
- if (ED_space_image_show_uvedit(sima, obedit)) {
- return false;
- }
- }
- else if (sima->mode != SI_MODE_VIEW) {
- return false;
- }
-
- return true;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -846,7 +826,7 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "IMAGE_OT_view_all";
ot->description = "View the entire image";
@@ -905,7 +885,6 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene;
ViewLayer *view_layer;
Object *obedit;
- Image *ima;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -914,12 +893,15 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
view_layer = CTX_data_view_layer(C);
obedit = CTX_data_edit_object(C);
- ima = ED_space_image(sima);
-
/* get bounds */
float min[2], max[2];
if (ED_space_image_show_uvedit(sima, obedit)) {
- if (!ED_uvedit_minmax(scene, ima, obedit, min, max)) {
+ 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);
+ bool success = ED_uvedit_minmax_multi(scene, objects, objects_len, min, max);
+ MEM_freeN(objects);
+ if (!success) {
return OPERATOR_CANCELLED;
}
}
@@ -1001,7 +983,7 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom In";
+ ot->name = "Zoom In";
ot->idname = "IMAGE_OT_view_zoom_in";
ot->description = "Zoom in the image (centered around 2D cursor)";
@@ -1060,7 +1042,7 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "View Zoom Out";
+ ot->name = "Zoom Out";
ot->idname = "IMAGE_OT_view_zoom_out";
ot->description = "Zoom out the image (centered around 2D cursor)";
@@ -1275,7 +1257,7 @@ static Image *image_open_single(Main *bmain,
if ((range->length > 1) && (ima->source == IMA_SRC_FILE)) {
if (range->udim_tiles.first && range->offset == 1001) {
ima->source = IMA_SRC_TILED;
- for (LinkData *node = range->udim_tiles.first; node; node = node->next) {
+ LISTBASE_FOREACH (LinkData *, node, &range->udim_tiles) {
BKE_image_add_tile(ima, POINTER_AS_INT(node->data), NULL);
}
}
@@ -1291,7 +1273,7 @@ static Image *image_open_single(Main *bmain,
static int image_open_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
ImageUser *iuser = NULL;
@@ -1309,7 +1291,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
}
ListBase ranges = ED_image_filesel_detect_sequences(bmain, op, use_udim);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
Image *ima_range = image_open_single(
bmain, op, range, BKE_main_blendfile_path(bmain), is_relative_path, use_multiview);
@@ -1345,8 +1327,8 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iod->iuser) {
iuser = iod->iuser;
}
- else if (sa && sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ else if (area && area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
ED_space_image_set(bmain, sima, obedit, ima, false);
iuser = &sima->iuser;
}
@@ -1359,7 +1341,7 @@ static int image_open_exec(bContext *C, wmOperator *op)
if (iuser == NULL) {
Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data;
if (cam) {
- for (CameraBGImage *bgpic = cam->bg_images.first; bgpic; bgpic = bgpic->next) {
+ LISTBASE_FOREACH (CameraBGImage *, bgpic, &cam->bg_images) {
if (bgpic->ima == ima) {
iuser = &bgpic->iuser;
break;
@@ -1794,7 +1776,8 @@ static int image_save_options_init(Main *bmain,
}
/* append UDIM numbering if not present */
- if (ima->source == IMA_SRC_TILED && (BLI_stringdec(ima->name, NULL, NULL, NULL) != 1001)) {
+ if (ima->source == IMA_SRC_TILED &&
+ (BLI_path_sequence_decode(ima->name, NULL, NULL, NULL) != 1001)) {
int len = strlen(opts->filepath);
STR_CONCAT(opts->filepath, len, ".1001");
}
@@ -3098,85 +3081,6 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
/** \name Sample Image Operator
* \{ */
-typedef struct ImageSampleInfo {
- ARegionType *art;
- void *draw_handle;
- int x, y;
- int channels;
-
- int width, height;
- int sample_size;
-
- unsigned char col[4];
- float colf[4];
- float linearcol[4];
- int z;
- float zf;
-
- unsigned char *colp;
- const float *colfp;
- int *zp;
- float *zfp;
-
- bool draw;
- bool color_manage;
- int use_default_view;
-} ImageSampleInfo;
-
-static void image_sample_draw(const bContext *C, ARegion *region, void *arg_info)
-{
- ImageSampleInfo *info = arg_info;
- if (!info->draw) {
- return;
- }
-
- Scene *scene = CTX_data_scene(C);
- ED_image_draw_info(scene,
- region,
- info->color_manage,
- info->use_default_view,
- info->channels,
- info->x,
- info->y,
- info->colp,
- info->colfp,
- info->linearcol,
- info->zp,
- info->zfp);
-
- if (info->sample_size > 1) {
- const wmWindow *win = CTX_wm_window(C);
- const wmEvent *event = win->eventstate;
-
- SpaceImage *sima = CTX_wm_space_image(C);
- GPUVertFormat *format = immVertexFormat();
- 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);
- immUniformColor3fv(color);
-
- /* TODO(campbell): lock to pixels. */
- rctf sample_rect_fl;
- BLI_rctf_init_pt_radius(
- &sample_rect_fl,
- (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
- (float)(info->sample_size / 2.0f) * sima->zoom);
-
- glEnable(GL_COLOR_LOGIC_OP);
- glLogicOp(GL_XOR);
- GPU_line_width(1.0f);
- imm_draw_box_wire_2d(pos,
- (float)sample_rect_fl.xmin,
- (float)sample_rect_fl.ymin,
- (float)sample_rect_fl.xmax,
- (float)sample_rect_fl.ymax);
- glDisable(GL_COLOR_LOGIC_OP);
-
- immUnbindProgram();
- }
-}
-
/* Returns color in linear space, matching ED_space_node_color_sample(). */
bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2], float r_col[3])
{
@@ -3198,7 +3102,7 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -3210,7 +3114,7 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -3221,279 +3125,6 @@ bool ED_space_image_color_sample(SpaceImage *sima, ARegion *region, int mval[2],
return ret;
}
-/* -------------------------------------------------------------------- */
-/** \name Image Pixel Sample
- * \{ */
-
-static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
- const int coord[2],
- uchar r_col[4],
- float r_col_linear[4])
-{
- const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
- copy_v4_v4_uchar(r_col, cp);
- rgba_uchar_to_float(r_col_linear, r_col);
- IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
-}
-
-static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
-{
- const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
- copy_v4_v4(r_col, cp);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Image Pixel Region Sample
- * \{ */
-
-static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
- const rcti *rect,
- uchar r_col[4],
- float r_col_linear[4])
-{
- uint col_accum_ub[4] = {0, 0, 0, 0};
- zero_v4(r_col_linear);
- int col_tot = 0;
- int coord[2];
- for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
- for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
- float col_temp_fl[4];
- uchar col_temp_ub[4];
- image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
- add_v4_v4(r_col_linear, col_temp_fl);
- col_accum_ub[0] += (uint)col_temp_ub[0];
- col_accum_ub[1] += (uint)col_temp_ub[1];
- col_accum_ub[2] += (uint)col_temp_ub[2];
- col_accum_ub[3] += (uint)col_temp_ub[3];
- col_tot += 1;
- }
- }
- mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
-
- r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
- r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
- r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
- r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
-}
-
-static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
-{
- zero_v4(r_col);
- int col_tot = 0;
- int coord[2];
- for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
- for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
- float col_temp_fl[4];
- image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
- add_v4_v4(r_col, col_temp_fl);
- col_tot += 1;
- }
- }
- mul_v4_fl(r_col, 1.0 / (float)col_tot);
-}
-
-/** \} */
-
-static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *region = CTX_wm_region(C);
- Image *image = ED_space_image(sima);
-
- float uv[2];
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
- int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
-
- void *lock;
- ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
- ImageSampleInfo *info = op->customdata;
- Scene *scene = CTX_data_scene(C);
- CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
-
- if (ibuf == NULL) {
- ED_space_image_release_buffer(sima, ibuf, lock);
- info->draw = false;
- return;
- }
-
- if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
- int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
-
- CLAMP(x, 0, ibuf->x - 1);
- CLAMP(y, 0, ibuf->y - 1);
-
- info->width = ibuf->x;
- info->height = ibuf->y;
- info->x = x;
- info->y = y;
-
- info->draw = true;
- info->channels = ibuf->channels;
-
- info->colp = NULL;
- info->colfp = NULL;
- info->zp = NULL;
- info->zfp = NULL;
-
- info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
-
- rcti sample_rect;
- sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
- sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
- sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
- sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
-
- if (ibuf->rect) {
- image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
- rgba_uchar_to_float(info->colf, info->col);
-
- info->colp = info->col;
- info->colfp = info->colf;
- info->color_manage = true;
- }
- if (ibuf->rect_float) {
- image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
-
- if (ibuf->channels == 4) {
- /* pass */
- }
- else if (ibuf->channels == 3) {
- info->colf[3] = 1.0f;
- }
- else {
- info->colf[1] = info->colf[0];
- info->colf[2] = info->colf[0];
- info->colf[3] = 1.0f;
- }
- info->colfp = info->colf;
-
- copy_v4_v4(info->linearcol, info->colf);
-
- info->color_manage = true;
- }
-
- if (ibuf->zbuf) {
- /* TODO, blend depth (not urgent). */
- info->z = ibuf->zbuf[y * ibuf->x + x];
- info->zp = &info->z;
- if (ibuf->zbuf == (int *)ibuf->rect) {
- info->colp = NULL;
- }
- }
- if (ibuf->zbuf_float) {
- /* TODO, blend depth (not urgent). */
- info->zf = ibuf->zbuf_float[y * ibuf->x + x];
- info->zfp = &info->zf;
- if (ibuf->zbuf_float == ibuf->rect_float) {
- info->colfp = NULL;
- }
- }
-
- if (curve_mapping && ibuf->channels == 4) {
- /* we reuse this callback for set curves point operators */
- if (RNA_struct_find_property(op->ptr, "point")) {
- int point = RNA_enum_get(op->ptr, "point");
-
- if (point == 1) {
- BKE_curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
- }
- else if (point == 0) {
- BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
- }
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- }
- }
-
- // XXX node curve integration ..
-#if 0
- {
- ScrArea *sa, *cur = curarea;
-
- node_curvemap_sample(fp); /* sends global to node editor */
- for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_NODE) {
- areawinset(sa->win);
- scrarea_do_windraw(sa);
- }
- }
- node_curvemap_sample(NULL); /* clears global in node editor */
- curarea = cur;
- }
-#endif
- }
- else {
- info->draw = 0;
- }
-
- ED_space_image_release_buffer(sima, ibuf, lock);
- ED_area_tag_redraw(CTX_wm_area(C));
-}
-
-static void image_sample_exit(bContext *C, wmOperator *op)
-{
- ImageSampleInfo *info = op->customdata;
-
- ED_region_draw_cb_exit(info->art, info->draw_handle);
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(info);
-}
-
-static int image_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *region = CTX_wm_region(C);
- ImageSampleInfo *info;
-
- if (region->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
- return OPERATOR_PASS_THROUGH;
- }
- }
-
- if (!ED_space_image_has_buffer(sima)) {
- return OPERATOR_CANCELLED;
- }
-
- info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
-
- info->art = region->type;
- info->draw_handle = ED_region_draw_cb_activate(
- region->type, image_sample_draw, info, REGION_DRAW_POST_PIXEL);
- info->sample_size = RNA_int_get(op->ptr, "size");
- op->customdata = info;
-
- image_sample_apply(C, op, event);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int image_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- case RIGHTMOUSE: // XXX hardcoded
- if (event->val == KM_RELEASE) {
- image_sample_exit(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- case MOUSEMOVE:
- image_sample_apply(C, op, event);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void image_sample_cancel(bContext *C, wmOperator *op)
-{
- image_sample_exit(C, op);
-}
-
void IMAGE_OT_sample(wmOperatorType *ot)
{
/* identifiers */
@@ -3502,10 +3133,10 @@ void IMAGE_OT_sample(wmOperatorType *ot)
ot->description = "Use mouse to sample a color in current image";
/* api callbacks */
- ot->invoke = image_sample_invoke;
- ot->modal = image_sample_modal;
- ot->cancel = image_sample_cancel;
- ot->poll = image_sample_poll;
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
+ ot->poll = ED_imbuf_sample_poll;
/* flags */
ot->flag = OPTYPE_BLOCKING;
@@ -3631,9 +3262,9 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* api callbacks */
- ot->invoke = image_sample_invoke;
- ot->modal = image_sample_modal;
- ot->cancel = image_sample_cancel;
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
ot->poll = space_image_main_area_not_uv_brush_poll;
/* properties */
diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c
index cc6fe38866d..0817bdda88d 100644
--- a/source/blender/editors/space_image/image_sequence.c
+++ b/source/blender/editors/space_image/image_sequence.c
@@ -64,22 +64,27 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
char dir[FILE_MAXDIR];
const bool do_frame_range = RNA_boolean_get(op->ptr, "use_sequence_detection");
ImageFrameRange *range = NULL;
+ int range_first_frame = 0;
RNA_string_get(op->ptr, "directory", dir);
RNA_BEGIN (op->ptr, itemptr, "files") {
char base_head[FILE_MAX], base_tail[FILE_MAX];
char head[FILE_MAX], tail[FILE_MAX];
- unsigned short digits;
+ ushort digits;
char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
/* use the first file in the list as base filename */
- frame->framenr = BLI_stringdec(filename, head, tail, &digits);
+ frame->framenr = BLI_path_sequence_decode(filename, head, tail, &digits);
/* still in the same sequence */
if (do_frame_range && (range != NULL) && (STREQLEN(base_head, head, FILE_MAX)) &&
(STREQLEN(base_tail, tail, FILE_MAX))) {
- /* pass */
+ /* Set filepath to first frame in the range. */
+ if (frame->framenr < range_first_frame) {
+ BLI_join_dirfile(range->filepath, sizeof(range->filepath), dir, filename);
+ range_first_frame = frame->framenr;
+ }
}
else {
/* start a new frame range */
@@ -89,6 +94,8 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
BLI_strncpy(base_head, head, sizeof(base_head));
BLI_strncpy(base_tail, tail, sizeof(base_tail));
+
+ range_first_frame = frame->framenr;
}
BLI_addtail(&range->frames, frame);
@@ -125,9 +132,9 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
char filename[FILE_MAX], dirname[FILE_MAXDIR];
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
- unsigned short digits;
+ ushort digits;
char base_head[FILE_MAX], base_tail[FILE_MAX];
- int id = BLI_stringdec(filename, base_head, base_tail, &digits);
+ int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits);
if (id < 1001 || id >= IMA_UDIM_MAX) {
return 0;
@@ -144,7 +151,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
continue;
}
char head[FILE_MAX], tail[FILE_MAX];
- id = BLI_stringdec(dir[i].relname, head, tail, &digits);
+ id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits);
if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) ||
!(STREQLEN(base_tail, tail, FILE_MAX))) {
@@ -166,7 +173,7 @@ static int image_get_udim(char *filepath, ListBase *udim_tiles)
if (is_udim && has_primary) {
char primary_filename[FILE_MAX];
- BLI_stringenc(primary_filename, base_head, base_tail, digits, 1001);
+ BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, 1001);
BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename);
return max_udim - 1000;
}
@@ -226,7 +233,7 @@ ListBase ED_image_filesel_detect_sequences(Main *bmain, wmOperator *op, const bo
const bool was_relative = BLI_path_is_rel(filepath);
image_sequence_get_frame_ranges(op, &ranges);
- for (ImageFrameRange *range = ranges.first; range; range = range->next) {
+ LISTBASE_FOREACH (ImageFrameRange *, range, &ranges) {
image_detect_frame_range(range, detect_udim);
BLI_freelistN(&range->frames);
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 1394c05d7bc..e0c44c3a0ba 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -145,7 +145,7 @@ static void ptile_free_list(ListBase *paint_tiles)
static void ptile_invalidate_list(ListBase *paint_tiles)
{
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
ptile->valid = false;
}
}
@@ -159,7 +159,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
ushort **r_mask,
bool validate)
{
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ 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) {
@@ -225,9 +225,9 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
"PaintTile.mask");
}
- ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
- square_i(ED_IMAGE_UNDO_TILE_SIZE),
- "PaintTile.rect");
+ ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ square_i(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
ptile->use_float = has_float;
ptile->valid = true;
@@ -267,7 +267,7 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
{
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ LISTBASE_FOREACH (PaintTile *, ptile, paint_tiles) {
Image *image = ptile->image;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, &ptile->iuser, NULL);
const bool has_float = (ibuf->rect_float != NULL);
@@ -542,7 +542,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
{
ImBuf *tmpibuf = imbuf_alloc_temp_tile();
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
/* Tiles only added to second set of tiles. */
Image *image = uh->image_ref.ptr;
@@ -552,7 +552,7 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init)
continue;
}
bool changed = false;
- for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ LISTBASE_FOREACH (UndoImageBuf *, ubuf_iter, &uh->buffers) {
UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
ubuf_ensure_compat_ibuf(ubuf, ibuf);
@@ -611,7 +611,7 @@ static UndoImageBuf *uhandle_lookup_ubuf(UndoImageHandle *uh,
const Image *UNUSED(image),
const char *ibuf_name)
{
- for (UndoImageBuf *ubuf = uh->buffers.first; ubuf; ubuf = ubuf->next) {
+ LISTBASE_FOREACH (UndoImageBuf *, ubuf, &uh->buffers) {
if (STREQ(ubuf->ibuf_name, ibuf_name)) {
return ubuf;
}
@@ -643,7 +643,7 @@ static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
const Image *image,
int tile_number)
{
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
if (STREQ(image->id.name + 2, uh->image_ref.name + 2) && uh->iuser.tile == tile_number) {
return uh;
}
@@ -653,7 +653,7 @@ static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles,
static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image, int tile_number)
{
- for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, undo_handles) {
if (image == uh->image_ref.ptr && uh->iuser.tile == tile_number) {
return uh;
}
@@ -667,7 +667,7 @@ static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image, ImageU
UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
uh->image_ref.ptr = image;
uh->iuser = *iuser;
- BLI_assert(uh->iuser.scene == NULL);
+ uh->iuser.scene = NULL;
uh->iuser.ok = 1;
BLI_addtail(undo_handles, uh);
return uh;
@@ -714,7 +714,7 @@ static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
int tile_number,
const UndoImageBuf *ubuf)
{
- /* Use name lookup because because the pointer is cleared for previous steps. */
+ /* 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) {
UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
@@ -733,9 +733,9 @@ static bool image_undosys_poll(bContext *C)
{
Object *obact = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- if (sa && (sa->spacetype == SPACE_IMAGE)) {
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area && (area->spacetype == SPACE_IMAGE)) {
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
return true;
}
@@ -799,8 +799,8 @@ static bool image_undosys_step_encode(struct bContext *C,
}
BLI_listbase_clear(&us->paint_tiles);
- for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
- for (UndoImageBuf *ubuf_pre = uh->buffers.first; ubuf_pre; ubuf_pre = ubuf_pre->next) {
+ 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);
@@ -958,7 +958,7 @@ static void image_undosys_step_decode(
}
if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ ED_object_mode_set_ex(C, OB_MODE_TEXTURE_PAINT, false, NULL);
}
/* Refresh texture slots. */
@@ -979,7 +979,7 @@ static void image_undosys_foreach_ID_ref(UndoStep *us_p,
void *user_data)
{
ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ LISTBASE_FOREACH (UndoImageHandle *, uh, &us->handles) {
foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
}
}
@@ -1083,6 +1083,7 @@ void ED_image_undo_push_end(void)
{
UndoStack *ustack = ED_undo_stack_get();
BKE_undosys_step_push(ustack, NULL, NULL);
+ 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 14cc6a9e151..51da5270f6e 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -83,13 +83,13 @@
/**************************** common state *****************************/
-static void image_scopes_tag_refresh(ScrArea *sa)
+static void image_scopes_tag_refresh(ScrArea *area)
{
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
ARegion *region;
/* only while histogram is visible */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_TOOL_PROPS && region->flag & RGN_FLAG_HIDDEN) {
return;
}
@@ -127,6 +127,7 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
simage->zoom = 1.0f;
simage->lock = true;
simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS;
+ simage->uv_opacity = 1.0f;
BKE_imageuser_default(&simage->iuser);
simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS;
@@ -256,10 +257,10 @@ static void image_keymap(struct wmKeyConfig *keyconf)
* \note take care not to get into feedback loop here,
* calling composite job causes viewer to refresh.
*/
-static void image_refresh(const bContext *C, ScrArea *sa)
+static void image_refresh(const bContext *C, ScrArea *area)
{
Scene *scene = CTX_data_scene(C);
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
Image *ima;
ima = ED_space_image(sima);
@@ -276,53 +277,53 @@ static void image_refresh(const bContext *C, ScrArea *sa)
}
}
-static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
+static void image_listener(wmWindow *win, ScrArea *area, wmNotifier *wmn, Scene *UNUSED(scene))
{
- SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)area->spacedata.first;
/* context changes */
switch (wmn->category) {
case NC_WINDOW:
/* notifier comes from editing color space */
- image_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
case ND_MODE:
if (wmn->subtype == NS_EDITMODE_MESH) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_RENDER_RESULT:
case ND_RENDER_OPTIONS:
case ND_COMPO_RESULT:
if (ED_space_image_show_render(sima)) {
- image_scopes_tag_refresh(sa);
+ image_scopes_tag_refresh(area);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
break;
case NC_IMAGE:
if (wmn->reference == sima->image || !wmn->reference) {
if (wmn->action != NA_PAINTING) {
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_IMAGE) {
- image_scopes_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
break;
case NC_MASK: {
@@ -332,23 +333,23 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
if (sima->mode == SI_MODE_MASK) {
switch (wmn->data) {
case ND_SELECT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_DATA:
case ND_DRAW:
/* causes node-recalc */
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
break;
}
switch (wmn->action) {
case NA_SELECTED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_EDITED:
/* causes node-recalc */
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
break;
}
}
@@ -358,9 +359,9 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
switch (wmn->data) {
case ND_DATA:
case ND_SELECT:
- image_scopes_tag_refresh(sa);
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ image_scopes_tag_refresh(area);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
break;
}
break;
@@ -373,8 +374,8 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
Object *ob = OBACT(view_layer);
if (ob && (ob == wmn->reference) && (ob->mode & OB_MODE_EDIT)) {
if (sima->lock && (sima->flag & SI_DRAWSHADOW)) {
- ED_area_tag_refresh(sa);
- ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(area);
+ ED_area_tag_redraw(area);
}
}
break;
@@ -385,14 +386,14 @@ static void image_listener(wmWindow *win, ScrArea *sa, wmNotifier *wmn, Scene *U
}
case NC_ID: {
if (wmn->action == NA_RENAME) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_redraw(sa);
- ED_area_tag_refresh(sa);
+ ED_area_tag_redraw(area);
+ ED_area_tag_refresh(area);
}
break;
}
@@ -611,13 +612,13 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
GPU_clear(GPU_COLOR_BIT);
GPU_framebuffer_bind(fbl->overlay_fb);
- glDisable(GL_FRAMEBUFFER_SRGB);
/* XXX not supported yet, disabling for now */
scene->r.scemode &= ~R_COMP_CROP;
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
+ srgb_to_linearrgb_v3_v3(col, col);
GPU_clear_color(col[0], col[1], col[2], 1.0f);
GPU_clear(GPU_COLOR_BIT);
GPU_depth_test(false);
@@ -714,7 +715,7 @@ static void image_main_region_draw(const bContext *C, ARegion *region)
}
static void image_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -742,7 +743,7 @@ static void image_main_region_listener(wmWindow *UNUSED(win),
break;
case NC_MATERIAL:
if (wmn->data == ND_SHADING_LINKS) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (sima->iuser.scene && (sima->iuser.scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE)) {
ED_region_tag_redraw(region);
@@ -831,7 +832,7 @@ static void image_buttons_region_draw(const bContext *C, ARegion *region)
}
static void image_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -894,7 +895,7 @@ static void image_tools_region_draw(const bContext *C, ARegion *region)
}
static void image_tools_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -942,8 +943,8 @@ static void image_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regio
static void image_header_region_draw(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceImage *sima = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceImage *sima = area->spacedata.first;
image_user_refresh_scene(C, sima);
@@ -951,7 +952,7 @@ static void image_header_region_draw(const bContext *C, ARegion *region)
}
static void image_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -982,7 +983,7 @@ static void image_header_region_listener(wmWindow *UNUSED(win),
}
}
-static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceImage *simg = (SpaceImage *)slink;
@@ -1012,15 +1013,15 @@ static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
* The previous non-uv-edit mode is stored so switching back to the
* image doesn't always reset the sub-mode.
*/
-static int image_space_subtype_get(ScrArea *sa)
+static int image_space_subtype_get(ScrArea *area)
{
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
return sima->mode == SI_MODE_UV ? SI_MODE_UV : SI_MODE_VIEW;
}
-static void image_space_subtype_set(ScrArea *sa, int value)
+static void image_space_subtype_set(ScrArea *area, int value)
{
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
if (value == SI_MODE_UV) {
if (sima->mode != SI_MODE_UV) {
sima->mode_prev = sima->mode;
diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c
index 2a3f6d6e365..3685e5de852 100644
--- a/source/blender/editors/space_info/info_draw.c
+++ b/source/blender/editors/space_info/info_draw.c
@@ -141,7 +141,6 @@ static int report_textview_begin(TextViewContext *tvc)
{
const ReportList *reports = tvc->arg2;
- tvc->lheight = 14 * UI_DPI_FAC;
tvc->sel_start = 0;
tvc->sel_end = 0;
diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c
index 7499c057950..adc6391a0f6 100644
--- a/source/blender/editors/space_info/info_report.c
+++ b/source/blender/editors/space_info/info_report.c
@@ -250,7 +250,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
const int select = (sel_op != SEL_OP_SUB);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- for (Report *report = reports->list.first; report; report = report->next) {
+ LISTBASE_FOREACH (Report *, report, &reports->list) {
if ((report->type & report_mask) == 0) {
continue;
}
@@ -264,7 +264,7 @@ static int box_select_exec(bContext *C, wmOperator *op)
/* get the first report if none found */
if (report_min == NULL) {
// printf("find_min\n");
- for (Report *report = reports->list.first; report; report = report->next) {
+ LISTBASE_FOREACH (Report *, report, &reports->list) {
if (report->type & report_mask) {
report_min = report;
break;
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 78bc0961cb3..e1937dffb37 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -33,6 +33,8 @@
#include "DNA_scene_types.h"
#include "DNA_windowmanager_types.h"
+#include "BLF_api.h"
+
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -40,7 +42,6 @@
#include "BLT_translation.h"
-#include "BKE_anim.h"
#include "BKE_blender_version.h"
#include "BKE_curve.h"
#include "BKE_displist.h"
@@ -60,9 +61,10 @@
#include "ED_armature.h"
#include "ED_info.h"
+#include "UI_resources.h"
+
#include "GPU_extensions.h"
-#define MAX_INFO_LEN 512
#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
@@ -74,8 +76,6 @@ typedef struct SceneStats {
uint64_t totlamp, totlampsel;
uint64_t tottri;
uint64_t totgplayer, totgpframe, totgpstroke, totgppoint;
-
- char infostr[MAX_INFO_LEN];
} SceneStats;
typedef struct SceneStatsFmt {
@@ -369,10 +369,16 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
if (obedit) {
/* Edit Mode */
- FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) {
- stats_object_edit(ob_iter, &stats);
+ FOREACH_OBJECT_BEGIN (view_layer, ob_iter) {
+ if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) {
+ if (ob_iter->mode == OB_MODE_EDIT) {
+ stats_object_edit(ob_iter, &stats);
+ stats.totobjsel++;
+ }
+ stats.totobj++;
+ }
}
- FOREACH_OBJECT_IN_MODE_END;
+ FOREACH_OBJECT_END;
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
/* Pose Mode */
@@ -399,26 +405,92 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer)
*(view_layer->stats) = stats;
}
-static void stats_string(ViewLayer *view_layer)
+static const char *footer_string(ViewLayer *view_layer)
{
#define MAX_INFO_MEM_LEN 64
- SceneStats *stats = view_layer->stats;
- SceneStatsFmt stats_fmt;
- LayerCollection *layer_collection = view_layer->active_collection;
- Object *ob = OBACT(view_layer);
- Object *obedit = OBEDIT_FROM_OBACT(ob);
- eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
- uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
char gpumemstr[MAX_INFO_MEM_LEN] = "";
char formatted_mem[15];
- char *s;
size_t ofs = 0;
- mem_in_use = MEM_get_memory_in_use();
- mmap_in_use = MEM_get_mapped_memory_in_use();
+ uintptr_t mem_in_use = MEM_get_memory_in_use();
+
+ /* get memory statistics */
+ BLI_str_format_byte_unit(formatted_mem, mem_in_use, false);
+ ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem);
+
+ if (GPU_mem_stats_supported()) {
+ int gpu_free_mem, gpu_tot_memory;
+
+ GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
+
+ BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
+ ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
+
+ if (gpu_tot_memory) {
+ BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
+ BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
+ }
+ }
+
+ BLI_snprintf(view_layer->footer_str,
+ sizeof(view_layer->footer_str),
+ "%s%s | %s",
+ memstr,
+ gpumemstr,
+ BKE_blender_version_string());
+
+ return view_layer->footer_str;
+
+#undef MAX_INFO_MEM_LEN
+}
+
+void ED_info_stats_clear(ViewLayer *view_layer)
+{
+ if (view_layer->stats) {
+ MEM_freeN(view_layer->stats);
+ view_layer->stats = NULL;
+ }
+}
+
+const char *ED_info_footer_string(ViewLayer *view_layer)
+{
+ return footer_string(view_layer);
+}
+
+static void stats_row(int col1,
+ const char *key,
+ int col2,
+ const char *value1,
+ const char *value2,
+ int *y,
+ int height)
+{
+ *y -= height;
+ BLF_draw_default(col1, *y, 0.0f, key, 128);
+ char values[128];
+ BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2);
+ BLF_draw_default(col2, *y, 0.0f, values, sizeof(values));
+}
+
+void ED_info_draw_stats(
+ Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height)
+{
+ /* Create stats if they don't already exist. */
+ if (!view_layer->stats) {
+ /* Do not not access dependency graph if interface is marked as locked. */
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm->is_interface_locked) {
+ return;
+ }
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
+ stats_update(depsgraph, view_layer);
+ }
+
+ SceneStats *stats = view_layer->stats;
+ SceneStatsFmt stats_fmt;
- /* Generate formatted numbers */
+ /* Generate formatted numbers. */
#define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id)
SCENE_STATS_FMT_INT(totvert);
@@ -448,151 +520,94 @@ static void stats_string(ViewLayer *view_layer)
#undef SCENE_STATS_FMT_INT
- /* get memory statistics */
- BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false);
- ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem);
-
- if (mmap_in_use) {
- BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false);
- BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem);
+ Object *ob = OBACT(view_layer);
+ Object *obedit = OBEDIT_FROM_OBACT(ob);
+ eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT;
+ const int font_id = BLF_default();
+
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
+ BLF_enable(font_id, BLF_SHADOW);
+ BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
+ BLF_shadow_offset(font_id, 1, -1);
+
+ /* Translated labels for each stat row. */
+ enum {
+ OBJ,
+ VERTS,
+ EDGES,
+ FACES,
+ TRIS,
+ BONES,
+ LAYERS,
+ FRAMES,
+ STROKES,
+ POINTS,
+ MAX_LABELS_COUNT
+ };
+ char labels[MAX_LABELS_COUNT][64];
+
+ STRNCPY(labels[OBJ], IFACE_("Objects"));
+ STRNCPY(labels[VERTS], IFACE_("Vertices"));
+ STRNCPY(labels[EDGES], IFACE_("Edges"));
+ STRNCPY(labels[FACES], IFACE_("Faces"));
+ STRNCPY(labels[TRIS], IFACE_("Triangles"));
+ STRNCPY(labels[BONES], IFACE_("Bones"));
+ STRNCPY(labels[LAYERS], IFACE_("Layers"));
+ STRNCPY(labels[FRAMES], IFACE_("Frames"));
+ STRNCPY(labels[STROKES], IFACE_("Strokes"));
+ STRNCPY(labels[POINTS], IFACE_("Points"));
+
+ int longest_label = 0;
+ int i;
+ for (i = 0; i < MAX_LABELS_COUNT; ++i) {
+ longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i])));
}
- if (GPU_mem_stats_supported()) {
- int gpu_free_mem, gpu_tot_memory;
-
- GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem);
-
- BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false);
- ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem);
+ int col1 = x;
+ int col2 = x + longest_label + (0.5f * U.widget_unit);
- if (gpu_tot_memory) {
- BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false);
- BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem);
- }
- }
-
- s = stats->infostr;
- ofs = 0;
+ /* Add some extra margin above this section. */
+ *y -= (0.6f * height);
if (object_mode == OB_MODE_OBJECT) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- "%s | ",
- BKE_collection_ui_name_get(layer_collection->collection));
- }
-
- if (ob) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
}
if (obedit) {
- if (BKE_keyblock_from_object(obedit)) {
- ofs += BLI_strncpy_rlen(s + ofs, TIP_("(Key) "), MAX_INFO_LEN - ofs);
- }
-
if (obedit->type == OB_MESH) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totedgesel,
- stats_fmt.totedge,
- stats_fmt.totfacesel,
- stats_fmt.totface,
- stats_fmt.tottri);
+ stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else if (obedit->type == OB_ARMATURE) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s | Bones:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert,
- stats_fmt.totbonesel,
- stats_fmt.totbone);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s/%s"),
- stats_fmt.totvertsel,
- stats_fmt.totvert);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height);
}
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
}
else if (ob && (object_mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Bones:%s/%s %s%s"),
- stats_fmt.totbonesel,
- stats_fmt.totbone,
- memstr,
- gpumemstr);
+ stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height);
}
else if ((ob) && (ob->type == OB_GPENCIL)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"),
- stats_fmt.totgplayer,
- stats_fmt.totgpframe,
- stats_fmt.totgpstroke,
- stats_fmt.totgppoint,
- stats_fmt.totobjsel,
- stats_fmt.totobj);
-
- ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
- ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs);
+ stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height);
+ stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height);
+ stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height);
+ stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height);
}
else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Tris:%s%s"),
- stats_fmt.totvert,
- stats_fmt.tottri,
- gpumemstr);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
else {
- ofs += BLI_snprintf(s + ofs,
- MAX_INFO_LEN - ofs,
- TIP_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"),
- stats_fmt.totvert,
- stats_fmt.totface,
- stats_fmt.tottri,
- stats_fmt.totobjsel,
- stats_fmt.totobj,
- memstr,
- gpumemstr);
+ stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height);
+ stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height);
+ stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height);
+ stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height);
}
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr);
-#undef MAX_INFO_MEM_LEN
-}
-
-#undef MAX_INFO_LEN
-
-void ED_info_stats_clear(ViewLayer *view_layer)
-{
- if (view_layer->stats) {
- MEM_freeN(view_layer->stats);
- view_layer->stats = NULL;
- }
-}
-
-const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer)
-{
- /* Looping through dependency graph when interface is locked in not safe.
- * Thew interface is marked as locked when jobs wants to modify the
- * dependency graph. */
- wmWindowManager *wm = bmain->wm.first;
- if (wm->is_interface_locked) {
- return "";
- }
- Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true);
- if (!view_layer->stats) {
- stats_update(depsgraph, view_layer);
- }
- stats_string(view_layer);
- return view_layer->stats->infostr;
+ BLF_disable(font_id, BLF_SHADOW);
}
diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c
index 58ce3316c4b..04df0f0d4f0 100644
--- a/source/blender/editors/space_info/space_info.c
+++ b/source/blender/editors/space_info/space_info.c
@@ -97,7 +97,7 @@ static void info_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void info_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void info_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -209,12 +209,12 @@ static void info_header_region_draw(const bContext *C, ARegion *region)
}
static void info_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- // SpaceInfo *sinfo = sa->spacedata.first;
+ // SpaceInfo *sinfo = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -228,7 +228,7 @@ static void info_main_region_listener(wmWindow *UNUSED(win),
}
static void info_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -267,7 +267,7 @@ static void info_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index c842fa8b4ac..8076d3d7eaf 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -394,25 +394,26 @@ int textview_draw(TextViewContext *tvc,
tvc->line_get(tvc, &ext_line, &ext_len);
- if (!textview_draw_string(&tds,
- ext_line,
- ext_len,
- (data_flag & TVC_LINE_FG) ? fg : NULL,
- (data_flag & TVC_LINE_BG) ? bg : NULL,
- (data_flag & TVC_LINE_ICON) ? icon : 0,
- (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
- (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
- bg_sel)) {
- /* When drawing, if we pass v2d->cur.ymax, then quit. */
- if (do_draw) {
- /* Past the y limits. */
- break;
- }
- }
+ const bool is_out_of_view_y = !textview_draw_string(
+ &tds,
+ ext_line,
+ ext_len,
+ (data_flag & TVC_LINE_FG) ? fg : NULL,
+ (data_flag & TVC_LINE_BG) ? bg : NULL,
+ (data_flag & TVC_LINE_ICON) ? icon : 0,
+ (data_flag & TVC_LINE_ICON_FG) ? icon_fg : NULL,
+ (data_flag & TVC_LINE_ICON_BG) ? icon_bg : NULL,
+ bg_sel);
if (do_draw) {
+ /* We always want the cursor to draw. */
if (tvc->draw_cursor && iter_index == 0) {
- tvc->draw_cursor(tvc, tds.cwidth, tds.columns, tds.lofs);
+ tvc->draw_cursor(tvc, tds.cwidth, tds.columns);
+ }
+
+ /* When drawing, if we pass v2d->cur.ymax, then quit. */
+ if (is_out_of_view_y) {
+ break;
}
}
@@ -428,6 +429,11 @@ int textview_draw(TextViewContext *tvc,
tvc->end(tvc);
+ /* Sanity checks (bugs here can be tricky to track down). */
+ BLI_assert(tds.lheight == tvc->lheight);
+ BLI_assert(tds.row_vpadding == tvc->row_vpadding);
+ BLI_assert(tds.do_draw == do_draw);
+
xy[1] += tvc->lheight * 2;
return xy[1] - y_orig;
diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h
index 8eef4ef5d56..41f8baf634e 100644
--- a/source/blender/editors/space_info/textview.h
+++ b/source/blender/editors/space_info/textview.h
@@ -60,7 +60,7 @@ typedef struct TextViewContext {
int *r_icon,
uchar r_icon_fg[4],
uchar r_icon_bg[4]);
- void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender);
+ void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns);
/* constant theme colors */
void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]);
const void *iter;
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index ca7f8791f75..307b6d9bc21 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -143,7 +143,8 @@ bool nla_panel_context(const bContext *C,
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* for these channels, we only do AnimData */
if (ale->adt && adt_ptr) {
ID *id;
@@ -242,11 +243,11 @@ static bool nla_strip_eval_panel_poll(const bContext *C, PanelType *UNUSED(pt))
/* -------------- */
/* active AnimData */
-static void nla_panel_animdata(const bContext *C, Panel *pa)
+static void nla_panel_animdata(const bContext *C, Panel *panel)
{
PointerRNA adt_ptr;
/* AnimData *adt; */
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *row;
uiBlock *block;
@@ -312,10 +313,10 @@ static void nla_panel_animdata(const bContext *C, Panel *pa)
}
/* generic settings for active NLA-Strip */
-static void nla_panel_stripname(const bContext *C, Panel *pa)
+static void nla_panel_stripname(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *row;
uiBlock *block;
@@ -350,11 +351,11 @@ static void nla_panel_stripname(const bContext *C, Panel *pa)
}
/* generic settings for active NLA-Strip */
-static void nla_panel_properties(const bContext *C, Panel *pa)
+static void nla_panel_properties(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
- uiLayout *column;
+ uiLayout *layout = panel->layout;
+ uiLayout *column, *row;
uiBlock *block;
short showEvalProps = 1;
@@ -401,28 +402,27 @@ static void nla_panel_properties(const bContext *C, Panel *pa)
uiItemR(column, &strip_ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE);
uiItemR(column, &strip_ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
- uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
-
- uiItemS(layout);
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false);
+ uiItemR(row, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle?
/* settings */
- column = uiLayoutColumn(layout, true);
- uiLayoutSetActive(column,
+ column = uiLayoutColumnWithHeading(layout, true, "Playback");
+ row = uiLayoutRow(column, true);
+ uiLayoutSetActive(row,
!(RNA_boolean_get(&strip_ptr, "use_animated_influence") ||
RNA_boolean_get(&strip_ptr, "use_animated_time")));
- uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
+ uiItemR(row, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE);
- uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
+ uiItemR(column, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE);
}
}
/* action-clip only settings for active NLA-Strip */
-static void nla_panel_actclip(const bContext *C, Panel *pa)
+static void nla_panel_actclip(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *column, *row;
uiBlock *block;
@@ -442,15 +442,12 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION);
/* action extents */
- // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column = uiLayoutColumn(layout, true);
uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE);
uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE);
- /* XXX: this layout may actually be too abstract and confusing,
- * and may be better using standard column layout. */
- row = uiLayoutRow(layout, false);
- uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE);
+ row = uiLayoutRowWithHeading(layout, false, "Sync Length");
+ uiItemR(row, &strip_ptr, "use_sync_length", 0, "", ICON_NONE);
uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length");
/* action usage */
@@ -461,10 +458,10 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
}
/* evaluation settings for active NLA-Strip */
-static void nla_panel_animated_influence_header(const bContext *C, Panel *pa)
+static void nla_panel_animated_influence_header(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
uiBlock *block;
@@ -481,10 +478,10 @@ static void nla_panel_animated_influence_header(const bContext *C, Panel *pa)
}
/* evaluation settings for active NLA-Strip */
-static void nla_panel_evaluation(const bContext *C, Panel *pa)
+static void nla_panel_evaluation(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiBlock *block;
/* check context and also validity of pointer */
@@ -500,10 +497,10 @@ static void nla_panel_evaluation(const bContext *C, Panel *pa)
uiItemR(layout, &strip_ptr, "influence", 0, NULL, ICON_NONE);
}
-static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa)
+static void nla_panel_animated_strip_time_header(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiLayout *col;
uiBlock *block;
@@ -519,10 +516,10 @@ static void nla_panel_animated_strip_time_header(const bContext *C, Panel *pa)
uiItemR(col, &strip_ptr, "use_animated_time", 0, "", ICON_NONE);
}
-static void nla_panel_animated_strip_time(const bContext *C, Panel *pa)
+static void nla_panel_animated_strip_time(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
- uiLayout *layout = pa->layout;
+ uiLayout *layout = panel->layout;
uiBlock *block;
/* check context and also validity of pointer */
@@ -539,7 +536,7 @@ static void nla_panel_animated_strip_time(const bContext *C, Panel *pa)
}
/* F-Modifiers for active NLA-Strip */
-static void nla_panel_modifiers(const bContext *C, Panel *pa)
+static void nla_panel_modifiers(const bContext *C, Panel *panel)
{
PointerRNA strip_ptr;
NlaStrip *strip;
@@ -553,12 +550,12 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
}
strip = strip_ptr.data;
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_nla_region_buttons, NULL);
/* 'add modifier' button at top of panel */
{
- row = uiLayoutRow(pa->layout, false);
+ row = uiLayoutRow(panel->layout, false);
block = uiLayoutGetBlock(row);
// FIXME: we need to set the only-active property so that this
@@ -574,7 +571,7 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa)
/* draw each modifier */
for (fcm = strip->modifiers.first; fcm; fcm = fcm->next) {
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
ANIM_uiTemplate_fmodifier_draw(col, strip_ptr.owner_id, &strip->modifiers, fcm);
}
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index a69aed38cab..d399ea47d7e 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -33,7 +33,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_nla.h"
@@ -146,7 +146,7 @@ static int mouse_nla_channels(
else {
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
- for (Base *b = view_layer->object_bases.first; b; b = b->next) {
+ LISTBASE_FOREACH (Base *, b, &view_layer->object_bases) {
ED_object_base_select(b, BA_DESELECT);
if (b->object->adt) {
b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
@@ -193,7 +193,8 @@ static int mouse_nla_channels(
case ANIMTYPE_PALETTE:
case ANIMTYPE_DSHAIR:
case ANIMTYPE_DSPOINTCLOUD:
- case ANIMTYPE_DSVOLUME: {
+ case ANIMTYPE_DSVOLUME:
+ case ANIMTYPE_DSSIMULATION: {
/* sanity checking... */
if (ale->adt) {
/* select/deselect */
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 4ccf752a916..a56b7f8422e 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -150,7 +150,7 @@ static void nla_action_draw_keyframes(
/* - disregard the selection status of keyframes so they draw a certain way
* - size is 6.0f which is smaller than the editable keyframes, so that there is a distinction
*/
- for (ActKeyColumn *ak = keys.first; ak; ak = ak->next) {
+ LISTBASE_FOREACH (ActKeyColumn *, ak, &keys) {
draw_keyframe_shape(ak->cfra,
y,
6.0f,
@@ -207,7 +207,7 @@ static void nla_actionclip_draw_markers(
immUniformThemeColorShade(TH_STRIP_SELECT, shade);
immBeginAtMost(GPU_PRIM_LINES, BLI_listbase_count(&act->markers) * 2);
- for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) {
+ LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) {
if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) {
float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP);
@@ -238,7 +238,7 @@ static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc)
/* just a solid color, so that it is very easy to spot */
int shade = 20;
/* draw the markers in the first level of strips only (if they are actions) */
- for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) {
+ LISTBASE_FOREACH (NlaStrip *, nls, &strip->strips) {
if (nls->type == NLASTRIP_TYPE_CLIP) {
nla_actionclip_draw_markers(nls, yminc, ymaxc, shade, false);
}
@@ -313,7 +313,7 @@ static void nla_strip_get_color_inside(AnimData *adt, NlaStrip *strip, float col
}
/* helper call for drawing influence/time control curves for a given NLA-strip */
-static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, unsigned int pos)
+static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uint pos)
{
const float yheight = ymaxc - yminc;
@@ -325,7 +325,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uns
/* influence -------------------------- */
if (strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) {
- FCurve *fcu = list_find_fcurve(&strip->fcurves, "influence", 0);
+ FCurve *fcu = BKE_fcurve_find(&strip->fcurves, "influence", 0);
float cfra;
/* plot the curve (over the strip's main region) */
@@ -565,7 +565,7 @@ static void nla_draw_strip(SpaceNla *snla,
immBeginAtMost(GPU_PRIM_LINES, 4 * BLI_listbase_count(&strip->strips));
/* only draw first-level of child-strips, but don't draw any lines on the endpoints */
- for (NlaStrip *cs = strip->strips.first; cs; cs = cs->next) {
+ LISTBASE_FOREACH (NlaStrip *, cs, &strip->strips) {
/* draw start-line if not same as end of previous (and only if not the first strip)
* - on upper half of strip
*/
@@ -828,7 +828,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
/* need to do a view-sync here, so that the keys area doesn't jump around
* (it must copy this) */
- UI_view2d_sync(NULL, ac->sa, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(NULL, ac->area, v2d, V2D_LOCK_COPY);
/* draw channels */
{ /* first pass: just the standard GL-drawing for backdrop + text */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 2427001657a..dec7a0fd93c 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -410,8 +410,8 @@ void NLA_OT_previewrange_set(wmOperatorType *ot)
/**
* Find the extents of the active channel
*
- * \param[out] min Bottom y-extent of channel
- * \param[out] max Top y-extent of channel
+ * \param[out] min: Bottom y-extent of channel.
+ * \param[out] max: Top y-extent of channel.
* \return Success of finding a selected channel
*/
static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
@@ -526,7 +526,7 @@ static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
void NLA_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "NLA_OT_view_all";
ot->description = "Reset viewable area to show full strips range";
@@ -567,7 +567,7 @@ void NLA_OT_view_frame(wmOperatorType *ot)
/* identifiers */
ot->name = "Go to Current Frame";
ot->idname = "NLA_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
/* api callbacks */
ot->exec = nlaedit_viewframe_exec;
@@ -1506,7 +1506,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
NlaTrack *nlt = (NlaTrack *)ale->data;
NlaStrip *strip, *stripN = NULL;
- NlaStrip *sa = NULL, *sb = NULL;
+ NlaStrip *area = NULL, *sb = NULL;
/* make temporary metastrips so that entire islands of selections can be moved around */
BKE_nlastrips_make_metas(&nlt->strips, 1);
@@ -1533,9 +1533,9 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* first or second strip? */
- if (sa == NULL) {
+ if (area == NULL) {
/* store as first */
- sa = strip;
+ area = strip;
}
else if (sb == NULL) {
/* store as second */
@@ -1556,7 +1556,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
"Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
nlt->name);
}
- else if (sa == NULL) {
+ else if (area == NULL) {
/* no warning as this is just a common case,
* and it may get annoying when doing multiple tracks */
}
@@ -1573,24 +1573,24 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
/* remove these strips from the track,
* so that we can test if they can fit in the proposed places */
- BLI_remlink(&nlt->strips, sa);
+ BLI_remlink(&nlt->strips, area);
BLI_remlink(&nlt->strips, sb);
/* calculate new extents for strips */
/* a --> b */
nsa[0] = sb->start;
- nsa[1] = sb->start + (sa->end - sa->start);
+ nsa[1] = sb->start + (area->end - area->start);
/* b --> a */
- nsb[0] = sa->start;
- nsb[1] = sa->start + (sb->end - sb->start);
+ nsb[0] = area->start;
+ nsb[1] = area->start + (sb->end - sb->start);
/* check if the track has room for the strips to be swapped */
if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) &&
BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1])) {
/* set new extents for strips then */
- sa->start = nsa[0];
- sa->end = nsa[1];
- BKE_nlameta_flush_transforms(sa);
+ area->start = nsa[0];
+ area->end = nsa[1];
+ BKE_nlameta_flush_transforms(area);
sb->start = nsb[0];
sb->end = nsb[1];
@@ -1598,7 +1598,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
else {
/* not enough room to swap, so show message */
- if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
+ if ((area->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
BKE_report(
op->reports,
RPT_WARNING,
@@ -1609,13 +1609,13 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
RPT_WARNING,
"Cannot swap '%s' and '%s' as one or both will not be able to fit in their "
"new places",
- sa->name,
+ area->name,
sb->name);
}
}
/* add strips back to track now */
- BKE_nlatrack_add_strip(nlt, sa);
+ BKE_nlatrack_add_strip(nlt, area);
BKE_nlatrack_add_strip(nlt, sb);
}
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 09abfc300c7..ec41368b9f0 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -308,7 +308,7 @@ static void nlaedit_strip_at_region_position(
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt = (NlaTrack *)ale->data;
- for (NlaStrip *strip = nlt->strips.first; strip; strip = strip->next) {
+ LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) {
*r_ale = ale;
*r_strip = strip;
diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c
index c4e1431ee26..f060693d9f4 100644
--- a/source/blender/editors/space_nla/space_nla.c
+++ b/source/blender/editors/space_nla/space_nla.c
@@ -57,7 +57,7 @@
/* ******************** default callbacks for nla space ***************** */
-static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
+static SpaceLink *nla_new(const ScrArea *area, const Scene *scene)
{
ARegion *region;
SpaceNla *snla;
@@ -105,7 +105,7 @@ static SpaceLink *nla_new(const ScrArea *sa, const Scene *scene)
region->regiontype = RGN_TYPE_WINDOW;
region->v2d.tot.xmin = (float)(SFRA - 10);
- region->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ region->v2d.tot.ymin = (float)(-area->winy) / 3.0f;
region->v2d.tot.xmax = (float)(EFRA + 10);
region->v2d.tot.ymax = 0.0f;
@@ -141,9 +141,9 @@ static void nla_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
+static void nla_init(struct wmWindowManager *wm, ScrArea *area)
{
- SpaceNla *snla = (SpaceNla *)sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)area->spacedata.first;
/* init dopesheet data if non-existent (i.e. for old files) */
if (snla->ads == NULL) {
@@ -151,7 +151,7 @@ static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
snla->ads->source = (ID *)WM_window_get_active_scene(wm->winactive);
}
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
static SpaceLink *nla_duplicate(SpaceLink *sl)
@@ -325,7 +325,7 @@ static void nla_buttons_region_draw(const bContext *C, ARegion *region)
}
static void nla_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -365,7 +365,7 @@ static void nla_region_listener(wmWindow *UNUSED(win),
}
static void nla_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -427,12 +427,12 @@ static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -466,7 +466,7 @@ static void nla_main_region_message_subscribe(const struct bContext *UNUSED(C),
}
static void nla_channel_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -512,12 +512,12 @@ static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *screen,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
PointerRNA ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceNLA, sa->spacedata.first, &ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
@@ -543,24 +543,27 @@ static void nla_channel_region_message_subscribe(const struct bContext *UNUSED(C
}
/* editor level listener */
-static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Scene *UNUSED(scene))
+static void nla_listener(wmWindow *UNUSED(win),
+ ScrArea *area,
+ wmNotifier *wmn,
+ Scene *UNUSED(scene))
{
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
// TODO: filter specific types of changes?
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_SCENE:
#if 0
switch (wmn->data) {
case ND_OB_ACTIVE:
case ND_OB_SELECT:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
#endif
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_OBJECT:
switch (wmn->data) {
@@ -568,19 +571,19 @@ static void nla_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, Sc
/* do nothing */
break;
default:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_NLA) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
-static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNla *snla = (SpaceNla *)slink;
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index f8c30f9a688..4e21cdc9d16 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -75,6 +75,10 @@ if(WITH_OPENIMAGEDENOISE)
add_definitions(-DWITH_OPENIMAGEDENOISE)
endif()
+if (WITH_NEW_SIMULATION_TYPE)
+ add_definitions(-DWITH_NEW_SIMULATION_TYPE)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 55a5a043014..01ac3a80871 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -69,9 +69,13 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
+/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */
+#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME
+
/* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */
static void node_socket_button_label(bContext *UNUSED(C),
@@ -93,7 +97,7 @@ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *p
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -107,7 +111,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr
col = uiLayoutColumn(layout, false);
uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0);
- uiItemR(col, &sockptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(col, &sockptr, "default_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
}
static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -118,12 +122,12 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) {
- uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA);
+ uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA);
}
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -145,8 +149,8 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE);
- uiItemR(row, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
+ uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE);
+ uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE);
}
static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -196,7 +200,7 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *
PointerRNA sockptr;
RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr);
- uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
#if 0 /* not used in 2.5x yet */
@@ -242,33 +246,33 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
short multi = (node->id && ((Tex *)node->id)->use_nodes && (node->type != CMP_NODE_TEXTURE) &&
(node->type != TEX_NODE_TEXTURE));
- uiItemR(layout, ptr, "texture", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "texture", DEFAULT_FLAGS, "", ICON_NONE);
if (multi) {
/* Number Drawing not optimal here, better have a list*/
- uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "node_output", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
NODE_MAP_RANGE_SMOOTHERSTEP)) {
- uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static int node_resize_area_default(bNode *node, int x, int y)
@@ -534,9 +538,9 @@ static int node_resize_area_frame(bNode *node, int x, int y)
static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE);
- uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE);
- uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE);
+ uiItemR(layout, ptr, "shrink", DEFAULT_FLAGS, IFACE_("Shrink"), ICON_NONE);
+ uiItemR(layout, ptr, "text", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#define NODE_REROUTE_SIZE 8.0f
@@ -697,7 +701,7 @@ static void node_buts_image_user(uiLayout *layout,
col = uiLayoutColumn(layout, false);
- uiItemR(col, imaptr, "source", 0, "", ICON_NONE);
+ uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE);
source = RNA_enum_get(imaptr, "source");
@@ -716,23 +720,23 @@ static void node_buts_image_user(uiLayout *layout,
if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_duration", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "frame_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_cyclic", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER &&
RNA_boolean_get(ptr, "has_layers")) {
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE);
}
uiLayout *split = uiLayoutSplit(layout, 0.5f, true);
PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings");
uiItemL(split, IFACE_("Color Space"), ICON_NONE);
- uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
/* Avoid losing changes image is painted. */
if (BKE_image_is_dirty(imaptr->data)) {
@@ -742,35 +746,35 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "rotation_type", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE);
+ uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE);
}
static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_pixel_size", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -789,14 +793,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA
UI_TEMPLATE_ID_FILTER_ALL,
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) {
- uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE);
+ uiItemR(layout, ptr, "projection_blend", DEFAULT_FLAGS, "Blend", ICON_NONE);
}
- uiItemR(layout, ptr, "extension", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE);
/* note: image user properties used directly here, unlike compositor image node,
* which redefines them in the node struct RNA to get proper updates.
@@ -827,8 +831,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
false,
NULL);
- uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE);
node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false);
}
@@ -838,29 +842,29 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0);
- uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE);
- uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, IFACE_("Interpolation"), ICON_NONE);
+ uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE);
}
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) {
- uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -868,48 +872,48 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE);
int type = RNA_enum_get(ptr, "wave_type");
if (type == SHD_WAVE_BANDS) {
- uiItemR(layout, ptr, "bands_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
else { /* SHD_WAVE_RINGS */
- uiItemR(layout, ptr, "rings_direction", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE);
}
- uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE);
int feature = RNA_enum_get(ptr, "feature");
if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) &&
RNA_enum_get(ptr, "voronoi_dimensions") != 1) {
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE);
}
}
static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -925,7 +929,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr);
uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
PointerRNA dataptr;
@@ -933,15 +937,15 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
- uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, NULL, ICON_NONE);
if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) {
if (ob_ptr.data) {
uiItemPointerR(
@@ -959,18 +963,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout,
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "object", 0, NULL, 0);
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "invert", 0, NULL, 0);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "from_instancer", 0, NULL, 0);
+ uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0);
if (!RNA_boolean_get(ptr, "from_instancer")) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -996,12 +1000,12 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
+ uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, NULL, 0);
}
static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) {
PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
@@ -1011,14 +1015,14 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(layout, ptr, "uv_map", 0, "", 0);
+ uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
}
static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", 0);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0);
}
static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1027,7 +1031,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
split = uiLayoutSplit(layout, 0.0f, false);
- uiItemR(split, ptr, "direction_type", 0, "", 0);
+ uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0);
row = uiLayoutRow(split, false);
@@ -1039,50 +1043,50 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *
uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "uv_map", 0, "", 0);
+ uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0);
}
}
else {
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, 0);
}
}
static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_principled_hair(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1090,15 +1094,15 @@ static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerR
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) {
- uiItemR(row, ptr, "ies", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
}
@@ -1107,15 +1111,15 @@ static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), Point
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) {
- uiItemR(row, ptr, "script", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
- uiItemR(row, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update");
@@ -1129,14 +1133,14 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA
#if 0 /* not implemented yet */
if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) {
- uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, NULL, ICON_NONE);
}
#endif
}
static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "target", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1145,32 +1149,32 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_ambient_occlusion(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -1355,10 +1359,10 @@ static void node_buts_image_views(uiLayout *layout,
if (RNA_boolean_get(ptr, "has_views")) {
if (RNA_enum_get(ptr, "view") == 0) {
- uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_CAMERA_STEREO);
}
else {
- uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE);
+ uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_SCENE);
}
}
}
@@ -1419,7 +1423,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, true);
- uiItemR(row, ptr, "layer", 0, "", ICON_NONE);
+ uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE);
prop = RNA_struct_find_property(ptr, "layer");
if (!(RNA_property_enum_identifier(
@@ -1446,56 +1450,56 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point
filter = RNA_enum_get(ptr, "filter_type");
reference = RNA_boolean_get(ptr, "use_variable_size");
- uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
if (filter != R_FILTER_FAST_GAUSS) {
- uiItemR(col, ptr, "use_variable_size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
if (!reference) {
- uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_relative")) {
uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "factor_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "factor_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
else {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
}
- uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Center:"), ICON_NONE);
- uiItemR(col, ptr, "center_x", 0, IFACE_("X"), ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, IFACE_("Y"), ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE);
uiItemS(layout);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bilateralblur(uiLayout *layout,
@@ -1505,9 +1509,9 @@ static void node_composit_buts_bilateralblur(uiLayout *layout,
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -1516,60 +1520,60 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE);
- uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE);
- uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true);
- uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false);
- uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE);
+ uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* qdn: glare node */
static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "quality", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 1) {
- uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") != 0) {
- uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
- uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, NULL, ICON_NONE);
}
if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) {
- uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "glare_type") == 0) {
- uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
if (RNA_enum_get(ptr, "glare_type") == 1) {
- uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -1578,17 +1582,17 @@ static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "tonemap_type") == 0) {
- uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
- uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1597,12 +1601,12 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(col, false);
uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
- uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1610,46 +1614,46 @@ static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, IFACE_("Blur"), ICON_NONE);
+ uiItemR(col, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE);
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Speed:"), ICON_NONE);
- uiItemR(col, ptr, "speed_min", 0, IFACE_("Min"), ICON_NONE);
- uiItemR(col, ptr, "speed_max", 0, IFACE_("Max"), ICON_NONE);
+ uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE);
+ uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE);
- uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "axis", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
if (RNA_boolean_get(ptr, "relative")) {
- uiItemR(col, ptr, "rel_min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "rel_min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "rel_max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
else {
- uiItemR(col, ptr, "min_x", 0, IFACE_("Left"), ICON_NONE);
- uiItemR(col, ptr, "max_x", 0, IFACE_("Right"), ICON_NONE);
- uiItemR(col, ptr, "min_y", 0, IFACE_("Up"), ICON_NONE);
- uiItemR(col, ptr, "max_y", 0, IFACE_("Down"), ICON_NONE);
+ uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE);
+ uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE);
+ uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE);
+ uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE);
}
}
@@ -1659,8 +1663,8 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C)
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, ptr, "factor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_double_edge_mask(uiLayout *layout,
@@ -1672,9 +1676,9 @@ static void node_composit_buts_double_edge_mask(uiLayout *layout,
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE);
- uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE);
uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE);
- uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1682,7 +1686,7 @@ static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1690,20 +1694,20 @@ static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C),
uiLayout *sub, *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "size", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, NULL, ICON_NONE);
sub = uiLayoutColumn(col, false);
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1711,8 +1715,8 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "premul", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1720,27 +1724,27 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
switch (RNA_enum_get(ptr, "mode")) {
case CMP_NODE_DILATEERODE_DISTANCE_THRESH:
- uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case CMP_NODE_DILATEERODE_DISTANCE_FEATHER:
- uiItemR(layout, ptr, "falloff", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
}
}
static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1748,8 +1752,8 @@ static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold_neighbor", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1757,8 +1761,8 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_distance_matte(uiLayout *layout,
@@ -1771,10 +1775,10 @@ static void node_composit_buts_distance_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1783,23 +1787,23 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C)
uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_boolean_get(ptr, "use_unspill") == true) {
- uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
}
@@ -1808,12 +1812,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
/*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now */
- uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
/*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now*/
}
@@ -1822,9 +1826,9 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C)
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_channel_matte(uiLayout *layout,
@@ -1835,24 +1839,24 @@ static void node_composit_buts_channel_matte(uiLayout *layout,
uiItemL(layout, IFACE_("Color Space:"), ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemL(col, IFACE_("Key Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "limit_method") == 0) {
uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1860,19 +1864,19 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C),
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "index", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -1886,7 +1890,7 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C)
else {
uiItemL(layout, IFACE_("Base Path:"), ICON_NONE);
}
- uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
@@ -1972,7 +1976,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("Layer:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -1987,7 +1991,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
uiItemL(col, IFACE_("File Subpath:"), ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &active_input_ptr, "path", 0, "", ICON_NONE);
+ uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE);
uiItemFullO(row,
"NODE_OT_output_file_remove_active_socket",
"",
@@ -2002,7 +2006,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
col = uiLayoutColumn(layout, true);
uiItemL(col, IFACE_("Format:"), ICON_NONE);
- uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, ICON_NONE);
+ uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false);
@@ -2017,20 +2021,20 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "space", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE);
if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) {
uiLayout *row;
- uiItemR(layout, ptr, "frame_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "offset_x", 0, "X", ICON_NONE);
- uiItemR(row, ptr, "offset_y", 0, "Y", ICON_NONE);
+ uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE);
+ uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE);
}
}
static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2038,25 +2042,25 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi
uiLayout *col;
col = uiLayoutColumn(layout, false);
- uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *split, *col, *row;
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
@@ -2064,17 +2068,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
@@ -2082,46 +2086,46 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
col = uiLayoutColumn(split, false);
uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1);
row = uiLayoutRow(col, false);
- uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
static void node_composit_buts_colorbalance_ex(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "correction_method") == 0) {
uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1);
- uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1);
- uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE);
}
else {
uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1);
- uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1);
- uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE);
uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1);
- uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2143,7 +2147,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C),
static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2180,19 +2184,19 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe
return;
}
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_relative", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "wrap_axis", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2206,7 +2210,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po
return;
}
- uiItemR(layout, ptr, "distortion_type", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_colorcorrection(uiLayout *layout,
@@ -2216,9 +2220,9 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, "", ICON_NONE);
@@ -2230,39 +2234,39 @@ static void node_composit_buts_colorcorrection(uiLayout *layout,
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Master"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Highlights"), ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Midtones"), ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
uiItemL(row, IFACE_("Shadows"), ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
@@ -2272,48 +2276,48 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout,
uiLayout *row;
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "red", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "green", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE);
row = layout;
uiItemL(row, IFACE_("Saturation"), ICON_NONE);
- uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Contrast"), ICON_NONE);
- uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gamma"), ICON_NONE);
- uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Gain"), ICON_NONE);
- uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
uiItemL(row, IFACE_("Lift"), ICON_NONE);
- uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "check", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_switch_view_ex(uiLayout *layout,
@@ -2335,32 +2339,32 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE);
- // uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED
- uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE);
+ // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); // UNUSED
+ uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_backdrop_viewer(
@@ -2486,36 +2490,36 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C)
{
uiLayout *row;
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "x", 0, NULL, ICON_NONE);
- uiItemR(row, ptr, "y", 0, NULL, ICON_NONE);
+ uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
- uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiLayout *col;
- uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, NULL, ICON_NONE);
if (RNA_enum_get(ptr, "tile_order") == 0) {
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE);
- uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2524,19 +2528,19 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p
bNode *node = ptr->data;
uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL);
- uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE);
if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) {
- uiItemR(layout, ptr, "size_x", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "size_y", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2562,18 +2566,18 @@ static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), Poi
{
/* bNode *node = ptr->data; */ /* UNUSED */
- uiItemR(layout, ptr, "blur_pre", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "screen_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_factor", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "despill_balance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_radius", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "edge_kernel_tolerance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_black", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "clip_white", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "dilate_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_falloff", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "feather_distance", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "blur_post", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -2605,13 +2609,13 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA);
}
else {
- uiItemR(layout, ptr, "track_name", 0, "", ICON_ANIM_DATA);
+ uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA);
}
- uiItemR(layout, ptr, "position", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "position", DEFAULT_FLAGS, NULL, ICON_NONE);
if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) {
- uiItemR(layout, ptr, "frame_relative", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
}
@@ -2650,10 +2654,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
}
}
- uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
- uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
- uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE);
}
}
@@ -2665,8 +2669,8 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout),
static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE);
- uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE);
}
static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2679,7 +2683,7 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C)
uiTemplateCryptoPicker(row, ptr, "add");
uiTemplateCryptoPicker(row, ptr, "remove");
- uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE);
}
static void node_composit_buts_cryptomatte_ex(uiLayout *layout,
@@ -2694,7 +2698,7 @@ static void node_composit_buts_brightcontrast(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
- uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE);
}
static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2707,7 +2711,7 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po
}
#endif
- uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE);
}
/* only once called */
@@ -2957,12 +2961,12 @@ static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), Poin
uiLayout *col;
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
- uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE);
+ uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE);
- uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE);
+ uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE);
+ uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE);
}
static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2979,68 +2983,73 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe
switch (tex->type) {
case TEX_BLEND:
- uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "progression", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "use_flip_axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MARBLE:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "marble_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_MAGIC:
- uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_depth", DEFAULT_FLAGS, NULL, ICON_NONE);
break;
case TEX_STUCCI:
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "stucci_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_WOOD:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "wood_type", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
uiLayoutSetActive(row, !(ELEM(tex->stype, TEX_BAND, TEX_RING)));
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
break;
case TEX_CLOUDS:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, &tex_ptr, "cloud_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
row = uiLayoutRow(col, false);
- uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, IFACE_("Depth"), ICON_NONE);
+ uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(col,
+ &tex_ptr,
+ "noise_depth",
+ DEFAULT_FLAGS | UI_ITEM_R_EXPAND,
+ IFACE_("Depth"),
+ ICON_NONE);
break;
case TEX_DISTNOISE:
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_distortion", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_MUSGRAVE:
- uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE);
- uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE);
break;
case TEX_VORONOI:
- uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "distance_metric", DEFAULT_FLAGS, "", ICON_NONE);
if (tex->vn_distm == TEX_MINKOVSKY) {
- uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE);
+ uiItemR(col, &tex_ptr, "minkovsky_exponent", DEFAULT_FLAGS, NULL, ICON_NONE);
}
- uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE);
+ uiItemR(col, &tex_ptr, "color_mode", DEFAULT_FLAGS, "", ICON_NONE);
break;
}
}
@@ -3070,7 +3079,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA
static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE);
}
/* only once called */
@@ -3122,6 +3131,96 @@ static void node_texture_set_butfunc(bNodeType *ntype)
}
}
+/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */
+
+static void node_simulation_buts_particle_simulation(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "name", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_time_step_event(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_set_particle_attribute(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_simulation_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case SIM_NODE_PARTICLE_SIMULATION:
+ ntype->draw_buttons = node_simulation_buts_particle_simulation;
+ break;
+ case SIM_NODE_PARTICLE_TIME_STEP_EVENT:
+ ntype->draw_buttons = node_simulation_buts_particle_time_step_event;
+ break;
+ case SIM_NODE_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_particle_attribute;
+ break;
+ case SIM_NODE_SET_PARTICLE_ATTRIBUTE:
+ ntype->draw_buttons = node_simulation_buts_set_particle_attribute;
+ break;
+ case SIM_NODE_TIME:
+ ntype->draw_buttons = node_simulation_buts_time;
+ break;
+ }
+}
+
+/* ****************** BUTTON CALLBACKS FOR FUNCTION NODES ***************** */
+
+static void node_function_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_float_compare(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
+}
+
+static void node_function_set_butfunc(bNodeType *ntype)
+{
+ switch (ntype->type) {
+ case FN_NODE_BOOLEAN_MATH:
+ ntype->draw_buttons = node_function_buts_boolean_math;
+ break;
+ case FN_NODE_FLOAT_COMPARE:
+ ntype->draw_buttons = node_function_buts_float_compare;
+ break;
+ case FN_NODE_SWITCH:
+ ntype->draw_buttons = node_function_buts_switch;
+ break;
+ }
+}
+
/* ****** init draw callbacks for all tree types, only called in usiblender.c, once ************ */
static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -3133,7 +3232,7 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin
static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp)
{
- StructRNA *srna = ntype->ext.srna;
+ StructRNA *srna = ntype->rna_ext.srna;
PropertyRNA *prop = RNA_struct_type_find_property(srna, stemp->identifier);
if (prop) {
@@ -3230,6 +3329,8 @@ void ED_node_init_butfuncs(void)
node_composit_set_butfunc(ntype);
node_shader_set_butfunc(ntype);
node_texture_set_butfunc(ntype);
+ node_simulation_set_butfunc(ntype);
+ node_function_set_butfunc(ntype);
/* define update callbacks for socket properties */
node_template_properties_update(ntype);
@@ -3240,6 +3341,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
+ ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3268,6 +3370,12 @@ static const float std_node_socket_colors[][4] = {
{0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */
{0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
+ {0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
+ {0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
+ {0.80, 0.80, 0.20, 1.0}, /* SOCK_EMITTERS */
+ {0.80, 0.20, 0.80, 1.0}, /* SOCK_EVENTS */
+ {0.20, 0.80, 0.80, 1.0}, /* SOCK_FORCES */
+ {0.30, 0.30, 0.30, 1.0}, /* SOCK_CONTROL_FLOW */
};
/* common color callbacks for standard types */
@@ -3362,7 +3470,7 @@ static void std_node_socket_draw(
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
- uiItemR(layout, ptr, "default_value", 0, text, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
case SOCK_VECTOR:
if (sock->flag & SOCK_COMPACT) {
@@ -3370,11 +3478,11 @@ static void std_node_socket_draw(
}
else {
if (sock->typeinfo->subtype == PROP_DIRECTION) {
- uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE);
}
else {
uiLayout *column = uiLayoutColumn(layout, true);
- uiItemR(column, ptr, "default_value", 0, text, ICON_NONE);
+ uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE);
}
}
break;
@@ -3382,7 +3490,15 @@ static void std_node_socket_draw(
case SOCK_STRING: {
uiLayout *row = uiLayoutSplit(layout, 0.5f, false);
uiItemL(row, text, 0);
- uiItemR(row, ptr, "default_value", 0, "", 0);
+ uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0);
+ break;
+ }
+ case SOCK_OBJECT: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
+ break;
+ }
+ case SOCK_IMAGE: {
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0);
break;
}
default:
@@ -3400,32 +3516,32 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout
switch (type) {
case SOCK_FLOAT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_INT: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_VECTOR: {
uiLayout *row;
- uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, 0);
+ uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, DEFAULT_FLAGS);
row = uiLayoutRow(layout, true);
- uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0);
- uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0);
+ uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0);
+ uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0);
break;
}
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING: {
- uiItemR(layout, ptr, "default_value", 0, NULL, 0);
+ uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0);
break;
}
}
@@ -3522,7 +3638,7 @@ void draw_nodespace_back_pix(const bContext *C,
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
GPU_shader_uniform_vector(
- state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, shuffle);
+ state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, shuffle);
immDrawPixelsTex(&state,
x,
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 1d73937d762..95a37f85828 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -82,7 +82,7 @@ bNode *node_add_node(const bContext *C, const char *idname, int type, float locx
nodeSetSelected(node, true);
ntreeUpdateTree(bmain, snode->edittree);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, NULL);
snode_update(snode, node);
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index ee1d2b43c5f..8fc343a9ed4 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -66,13 +66,13 @@ static bool node_sockets_poll(const bContext *C, PanelType *UNUSED(pt))
return (snode && snode->nodetree && G.debug_value == 777);
}
-static void node_sockets_panel(const bContext *C, Panel *pa)
+static void node_sockets_panel(const bContext *C, Panel *panel)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = (snode) ? snode->edittree : NULL;
bNode *node = (ntree) ? nodeGetActive(ntree) : NULL;
bNodeSocket *sock;
- uiLayout *layout = pa->layout, *split;
+ uiLayout *layout = panel->layout, *split;
char name[UI_MAX_NAME_STR];
if (ELEM(NULL, ntree, node)) {
@@ -84,7 +84,7 @@ static void node_sockets_panel(const bContext *C, Panel *pa)
split = uiLayoutSplit(layout, 0.35f, false);
uiItemL(split, name, ICON_NONE);
- uiTemplateNodeLink(split, ntree, node, sock);
+ uiTemplateNodeLink(split, (bContext *)C, ntree, node, sock);
}
}
@@ -119,13 +119,13 @@ static bool node_tree_find_active_socket(bNodeTree *ntree, bNodeSocket **r_sock,
return false;
}
-static void node_tree_interface_panel(const bContext *C, Panel *pa)
+static void node_tree_interface_panel(const bContext *C, Panel *panel)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNodeTree *ntree = (snode) ? snode->edittree : NULL;
bNodeSocket *sock;
int in_out;
- uiLayout *layout = pa->layout, *row, *split, *col;
+ uiLayout *layout = panel->layout, *row, *split, *col;
PointerRNA ptr, sockptr, opptr;
wmOperatorType *ot;
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 0552660b9bf..bd8950c5085 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -94,23 +94,11 @@ void ED_node_tree_update(const bContext *C)
static bNodeTree *node_tree_from_ID(ID *id)
{
if (id) {
- short idtype = GS(id->name);
-
- switch (idtype) {
- case ID_NT:
- return (bNodeTree *)id;
- case ID_MA:
- return ((Material *)id)->nodetree;
- case ID_LA:
- return ((Light *)id)->nodetree;
- case ID_WO:
- return ((World *)id)->nodetree;
- case ID_SCE:
- return ((Scene *)id)->nodetree;
- case ID_TE:
- return ((Tex *)id)->nodetree;
- case ID_LS:
- return ((FreestyleLineStyle *)id)->nodetree;
+ if (GS(id->name) == ID_NT) {
+ return (bNodeTree *)id;
+ }
+ else {
+ return ntreeFromID(id);
}
}
@@ -719,39 +707,19 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
#define MARKER_SHAPE_CIRCLE 0x2
#define MARKER_SHAPE_INNER_DOT 0x10
-static void node_socket_draw(const bContext *C,
- bNodeTree *ntree,
- PointerRNA node_ptr,
- bNodeSocket *sock,
+static void node_socket_draw(const bNodeSocket *sock,
+ const float color[4],
+ const float color_outline[4],
+ float size,
+ int locx,
+ int locy,
uint pos_id,
uint col_id,
uint shape_id,
uint size_id,
- uint outline_col_id,
- float size,
- bool selected)
+ uint outline_col_id)
{
- PointerRNA ptr;
- float color[4];
- float outline_color[4];
- uint flags = 0;
-
- RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
- sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color);
-
- bNode *node = node_ptr.data;
- if (node->flag & NODE_MUTED) {
- color[3] *= 0.25f;
- }
-
- if (selected) {
- UI_GetThemeColor4fv(TH_TEXT_HI, outline_color);
- outline_color[3] = 0.9f;
- }
- else {
- copy_v4_fl(outline_color, 0.0f);
- outline_color[3] = 0.6f;
- }
+ int flags;
/* sets shape flags */
switch (sock->display_shape) {
@@ -780,8 +748,120 @@ static void node_socket_draw(const bContext *C,
immAttr4fv(col_id, color);
immAttr1u(shape_id, flags);
immAttr1f(size_id, size);
- immAttr4fv(outline_col_id, outline_color);
- immVertex2f(pos_id, sock->locx, sock->locy);
+ immAttr4fv(outline_col_id, color_outline);
+ immVertex2f(pos_id, locx, locy);
+}
+
+static void node_socket_outline_color_get(bool selected, float r_outline_color[4])
+{
+ if (selected) {
+ UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color);
+ r_outline_color[3] = 0.9f;
+ }
+ else {
+ copy_v4_fl(r_outline_color, 0.0f);
+ r_outline_color[3] = 0.6f;
+ }
+}
+
+/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a
+ * color property socket). */
+void node_socket_color_get(
+ bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4])
+{
+ PointerRNA ptr;
+
+ BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node));
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr);
+
+ sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color);
+
+ bNode *node = node_ptr->data;
+ if (node->flag & NODE_MUTED) {
+ r_color[3] *= 0.25f;
+ }
+}
+
+static void node_socket_draw_nested(const bContext *C,
+ bNodeTree *ntree,
+ PointerRNA *node_ptr,
+ bNodeSocket *sock,
+ uint pos_id,
+ uint col_id,
+ uint shape_id,
+ uint size_id,
+ uint outline_col_id,
+ float size,
+ bool selected)
+{
+ float color[4];
+ float outline_color[4];
+
+ node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color);
+ node_socket_outline_color_get(selected, outline_color);
+
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ size,
+ sock->locx,
+ sock->locy,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+}
+
+/**
+ * Draw a single node socket at default size.
+ * \note this is only called from external code, internally #node_socket_draw_nested() is used for
+ * optimized drawing of multiple/all sockets of a node.
+ */
+void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale)
+{
+ const float size = 2.25f * NODE_SOCKSIZE * scale;
+ rcti draw_rect = *rect;
+ float outline_color[4] = {0};
+
+ node_socket_outline_color_get(sock->flag & SELECT, outline_color);
+
+ BLI_rcti_resize(&draw_rect, size, size);
+
+ GPUVertFormat *format = immVertexFormat();
+ uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+ uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
+ uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
+ uint outline_col_id = GPU_vertformat_attr_add(
+ format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
+
+ gpuPushAttr(GPU_BLEND_BIT);
+ GPU_blend(true);
+ GPU_program_point_size(true);
+
+ immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND);
+ immUniform1f("outline_scale", 0.7f);
+ immUniform2f("ViewportSize", -1.0f, -1.0f);
+
+ /* Single point */
+ immBegin(GPU_PRIM_POINTS, 1);
+ node_socket_draw(sock,
+ color,
+ outline_color,
+ BLI_rcti_size_y(&draw_rect),
+ BLI_rcti_cent_x(&draw_rect),
+ BLI_rcti_cent_y(&draw_rect),
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id);
+ immEnd();
+
+ immUnbindProgram();
+ GPU_program_point_size(false);
+ gpuPopAttr();
}
/* ************** Socket callbacks *********** */
@@ -974,17 +1054,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
/* socket outputs */
@@ -999,17 +1079,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
}
}
@@ -1032,17 +1112,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_input_len == 0) {
break; /* stop as soon as last one is drawn */
}
@@ -1057,17 +1137,17 @@ void node_draw_sockets(View2D *v2d,
continue;
}
if (select_all || (sock->flag & SELECT)) {
- node_socket_draw(C,
- ntree,
- node_ptr,
- sock,
- pos_id,
- col_id,
- shape_id,
- size_id,
- outline_col_id,
- scale,
- selected);
+ node_socket_draw_nested(C,
+ ntree,
+ &node_ptr,
+ sock,
+ pos_id,
+ col_id,
+ shape_id,
+ size_id,
+ outline_col_id,
+ scale,
+ selected);
if (--selected_output_len == 0) {
break; /* stop as soon as last one is drawn */
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index e50f5a818aa..ac58ec1e636 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -69,6 +69,7 @@
#include "NOD_composite.h"
#include "NOD_shader.h"
+#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -127,12 +128,12 @@ static int compo_get_recalc_flags(const bContext *C)
int recalc_flags = 0;
for (win = wm->windows.first; win; win = win->next) {
- const bScreen *sc = WM_window_get_active_screen(win);
- ScrArea *sa;
+ const bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *area;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ for (area = screen->areabase.first; area; area = area->next) {
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
if (sima->image) {
if (sima->image->type == IMA_TYPE_R_RESULT) {
recalc_flags |= COM_RECALC_COMPOSITE;
@@ -142,8 +143,8 @@ static int compo_get_recalc_flags(const bContext *C)
}
}
}
- else if (sa->spacetype == SPACE_NODE) {
- SpaceNode *snode = sa->spacedata.first;
+ else if (area->spacetype == SPACE_NODE) {
+ SpaceNode *snode = area->spacedata.first;
if (snode->flag & SNODE_BACKDRAW) {
recalc_flags |= COM_RECALC_VIEWER;
}
@@ -438,6 +439,11 @@ bool ED_node_is_texture(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
+bool ED_node_is_simulation(struct SpaceNode *snode)
+{
+ return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
+}
+
/* assumes nothing being done in ntree yet, sets the default in/out node */
/* called from shading buttons or header */
void ED_node_shader_default(const bContext *C, ID *id)
@@ -642,9 +648,12 @@ void snode_update(SpaceNode *snode, bNode *node)
}
}
-void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
+void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed)
{
const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = false;
+ }
nodeSetActive(ntree, node);
@@ -713,6 +722,9 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
}
}
+ if (r_active_texture_changed) {
+ *r_active_texture_changed = true;
+ }
ED_node_tag_update_nodetree(bmain, ntree, node);
WM_main_add_notifier(NC_IMAGE, NULL);
}
@@ -1284,7 +1296,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
newnode = node->new_node;
nodeSetSelected(node, false);
- node->flag &= ~NODE_ACTIVE;
+ node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE);
nodeSetSelected(newnode, true);
do_tag_update |= (do_tag_update || node_connected_to_output(bmain, ntree, newnode));
@@ -1326,7 +1338,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
bool ED_node_select_check(ListBase *lb)
{
- for (bNode *node = lb->first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, lb) {
if (node->flag & NODE_SELECT) {
return true;
}
@@ -1346,7 +1358,7 @@ void ED_node_select_all(ListBase *lb, int action)
}
}
- for (bNode *node = lb->first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, lb) {
switch (action) {
case SEL_SELECT:
nodeSetSelected(node, true);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 2a4c6147d5d..2617384d046 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -69,7 +69,8 @@ static bool node_group_operator_active(bContext *C)
*/
if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
STREQ(snode->tree_idname, "CompositorNodeTree") ||
- STREQ(snode->tree_idname, "TextureNodeTree")) {
+ STREQ(snode->tree_idname, "TextureNodeTree") ||
+ STREQ(snode->tree_idname, "SimulationNodeTree")) {
return true;
}
}
@@ -85,7 +86,8 @@ static bool node_group_operator_editable(bContext *C)
* Disabled otherwise to allow pynodes define their own operators
* with same keymap.
*/
- if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode)) {
+ if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
+ ED_node_is_simulation(snode)) {
return true;
}
}
@@ -111,6 +113,9 @@ static const char *group_node_idname(bContext *C)
else if (ED_node_is_texture(snode)) {
return "TextureNodeGroup";
}
+ else if (ED_node_is_simulation(snode)) {
+ return "SimulationNodeGroup";
+ }
return "";
}
@@ -193,11 +198,11 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
}
/* wgroup is a temporary copy of the NodeTree we're merging in
- * - all of wgroup's nodes are transferred across to their new home
+ * - all of wgroup's nodes are copied across to their new home
* - ngroup (i.e. the source NodeTree) is left unscathed
- * - temp copy. don't change ID usercount
+ * - temp copy. do change ID usercount for the copies
*/
- wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, false);
+ wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true);
/* Add the nodes into the ntree */
for (node = wgroup->nodes.first; node; node = nextnode) {
@@ -351,8 +356,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
nodeRemoveNode(bmain, ntree, node, false);
}
- /* delete the group instance */
- nodeRemoveNode(bmain, ntree, gnode, false);
+ /* delete the group instance and dereference group tree */
+ nodeRemoveNode(bmain, ntree, gnode, true);
ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS;
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index 8c7c490b181..04186c3a727 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -38,6 +38,7 @@ struct bContext;
struct bNode;
struct bNodeLink;
struct bNodeSocket;
+struct wmGizmoGroupType;
struct wmKeyConfig;
struct wmWindow;
@@ -77,6 +78,11 @@ void node_draw_sockets(struct View2D *v2d,
void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node);
int node_select_area_default(struct bNode *node, int x, int y);
int node_tweak_area_default(struct bNode *node, int x, int y);
+void node_socket_color_get(struct bContext *C,
+ struct bNodeTree *ntree,
+ struct PointerRNA *node_ptr,
+ struct bNodeSocket *sock,
+ float r_color[4]);
void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree);
void node_draw_nodetree(const struct bContext *C,
struct ARegion *region,
@@ -122,7 +128,7 @@ void NODE_OT_find_node(struct wmOperatorType *ot);
/* node_view.c */
int space_node_view_flag(struct bContext *C,
- SpaceNode *snode,
+ struct SpaceNode *snode,
ARegion *region,
const int node_flag,
const int smooth_viewtx);
@@ -196,7 +202,7 @@ void NODE_OT_detach(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
-void NODE_OT_insert_offset(wmOperatorType *ot);
+void NODE_OT_insert_offset(struct wmOperatorType *ot);
/* node_edit.c */
void snode_notify(struct bContext *C, struct SpaceNode *snode);
@@ -207,8 +213,8 @@ void snode_update(struct SpaceNode *snode, struct bNode *node);
bool composite_node_active(struct bContext *C);
bool composite_node_editable(struct bContext *C);
-int node_has_hidden_sockets(bNode *node);
-void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set);
+int node_has_hidden_sockets(struct bNode *node);
+void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set);
int node_render_changed_exec(bContext *, struct wmOperator *);
int node_find_indicated_socket(struct SpaceNode *snode,
struct bNode **nodep,
@@ -271,7 +277,7 @@ extern const char *node_context_dir[];
#define NODE_SOCKDY (0.08f * U.widget_unit)
#define NODE_WIDTH(node) (node->width * UI_DPI_FAC)
#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC)
-#define NODE_MARGIN_X (0.75f * U.widget_unit)
+#define NODE_MARGIN_X (0.95f * U.widget_unit)
#define NODE_SOCKSIZE (0.25f * U.widget_unit)
#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit)
#define NODE_LINK_RESOL 12
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 5dc98a3905a..144e3bd3506 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -30,7 +30,7 @@
#include "BLI_easing.h"
#include "BLI_math.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -466,7 +466,7 @@ static int node_link_viewer(const bContext *C, bNode *tonode)
if (tonode) {
/* Find a selected socket that overrides the socket to connect to */
- for (bNodeSocket *sock2 = tonode->outputs.first; sock2; sock2 = sock2->next) {
+ LISTBASE_FOREACH (bNodeSocket *, sock2, &tonode->outputs) {
if (!nodeSocketIsHidden(sock2) && sock2->flag & SELECT) {
sock = sock2;
break;
@@ -1446,9 +1446,12 @@ void NODE_OT_detach(wmOperatorType *ot)
/* ********************* automatic node insert on dragging ******************* */
/* prevent duplicate testing code below */
-static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode, bNode **r_select)
+static bool ed_node_link_conditions(ScrArea *area,
+ bool test,
+ SpaceNode **r_snode,
+ bNode **r_select)
{
- SpaceNode *snode = sa ? sa->spacedata.first : NULL;
+ SpaceNode *snode = area ? area->spacedata.first : NULL;
bNode *node, *select = NULL;
bNodeLink *link;
@@ -1456,7 +1459,7 @@ static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode,
*r_select = NULL;
/* no unlucky accidents */
- if (sa == NULL || sa->spacetype != SPACE_NODE) {
+ if (area == NULL || area->spacetype != SPACE_NODE) {
return false;
}
@@ -1501,14 +1504,14 @@ static bool ed_node_link_conditions(ScrArea *sa, bool test, SpaceNode **r_snode,
}
/* test == 0, clear all intersect flags */
-void ED_node_link_intersect_test(ScrArea *sa, int test)
+void ED_node_link_intersect_test(ScrArea *area, int test)
{
bNode *select;
SpaceNode *snode;
bNodeLink *link, *selink = NULL;
float dist_best = FLT_MAX;
- if (!ed_node_link_conditions(sa, test, &snode, &select)) {
+ if (!ed_node_link_conditions(area, test, &snode, &select)) {
return;
}
@@ -1619,8 +1622,8 @@ static void node_parent_offset_apply(NodeInsertOfsData *data, bNode *parent, con
node_offset_apply(parent, offset_x);
- /* flag all childs as offset to prevent them from being offset
- * separately (they've already moved with the parent) */
+ /* Flag all children as offset to prevent them from being offset
+ * separately (they've already moved with the parent). */
for (node = data->ntree->nodes.first; node; node = node->next) {
if (nodeIsChildOf(parent, node)) {
/* NODE_TEST is used to flag nodes that shouldn't be offset (again) */
@@ -1654,7 +1657,7 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode,
}
/**
- * Applies NodeInsertOfsData.offset_x to all childs of \a parent
+ * Applies #NodeInsertOfsData.offset_x to all children of \a parent.
*/
static void node_link_insert_offset_frame_chains(const bNodeTree *ntree,
const bNode *parent,
@@ -1919,14 +1922,14 @@ void NODE_OT_insert_offset(wmOperatorType *ot)
}
/* assumes link with NODE_LINKFLAG_HILITE set */
-void ED_node_link_insert(Main *bmain, ScrArea *sa)
+void ED_node_link_insert(Main *bmain, ScrArea *area)
{
bNode *node, *select;
SpaceNode *snode;
bNodeLink *link;
bNodeSocket *sockto;
- if (!ed_node_link_conditions(sa, true, &snode, &select)) {
+ if (!ed_node_link_conditions(area, true, &snode, &select)) {
return;
}
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 98fcf862290..06f568c80f3 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -24,8 +24,10 @@
#include <stdlib.h>
#include "DNA_node_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_lasso_2d.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
@@ -35,10 +37,12 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_node.h"
+#include "BKE_workspace.h"
#include "ED_node.h" /* own include */
#include "ED_screen.h"
#include "ED_select_utils.h"
+#include "ED_view3d.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -50,10 +54,42 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "DEG_depsgraph.h"
+
#include "MEM_guardedalloc.h"
#include "node_intern.h" /* own include */
+/* Function to detect if there is a visible view3d that uses workbench in texture mode.
+ * This function is for fixing T76970 for Blender 2.83. The actual fix should add a mechanism in
+ * the depsgraph that can be used by the draw engines to check if they need to be redrawn.
+ *
+ * We don't want to add these risky changes this close before releasing 2.83 without good testing
+ * hence this workaround. There are still cases were too many updates happen. For example when you
+ * have both a Cycles and workbench with textures viewport.
+ * */
+static bool has_workbench_in_texture_color(const wmWindowManager *wm,
+ const Scene *scene,
+ const Object *ob)
+{
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
+ if (win->scene != scene) {
+ continue;
+ }
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ const View3D *v3d = area->spacedata.first;
+
+ if (ED_view3d_has_workbench_in_texture_color(scene, ob, v3d)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
/* -------------------------------------------------------------------- */
/** \name Public Node Selection API
* \{ */
@@ -284,7 +320,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo
{
bNode *node;
bool changed = false;
- const unsigned int delims[] = {'.', '-', '_', '\0'};
+ const uint delims[] = {'.', '-', '_', '\0'};
size_t pref_len_act, pref_len_curr;
const char *sep, *suf_act, *suf_curr;
@@ -412,6 +448,10 @@ void node_select_single(bContext *C, bNode *node)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ bool active_texture_changed = false;
bNode *tnode;
for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next) {
@@ -421,10 +461,13 @@ void node_select_single(bContext *C, bNode *node)
}
nodeSetSelected(node, true);
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
@@ -437,6 +480,9 @@ static int node_mouse_select(bContext *C,
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
ARegion *region = CTX_wm_region(C);
+ const Object *ob = CTX_data_active_object(C);
+ const Scene *scene = CTX_data_scene(C);
+ const wmWindowManager *wm = CTX_wm_manager(C);
bNode *node, *tnode;
bNodeSocket *sock = NULL;
bNodeSocket *tsock;
@@ -543,11 +589,15 @@ static int node_mouse_select(bContext *C,
/* update node order */
if (ret_value != OPERATOR_CANCELLED) {
+ bool active_texture_changed = false;
if (node != NULL && ret_value != OPERATOR_RUNNING_MODAL) {
- ED_node_set_active(bmain, snode->edittree, node);
+ ED_node_set_active(bmain, snode->edittree, node, &active_texture_changed);
}
ED_node_set_active_viewer_key(snode);
ED_node_sort(snode->edittree);
+ if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) {
+ DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE);
+ }
WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
}
@@ -622,7 +672,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op)
ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT);
}
- for (bNode *node = snode->edittree->nodes.first; node; node = node->next) {
+ LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) {
bool is_inside;
if (node->type == NODE_FRAME) {
is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr);
@@ -765,7 +815,10 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent *
return WM_gesture_lasso_invoke(C, op, event);
}
-static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, eSelectOp sel_op)
+static bool do_lasso_select_node(bContext *C,
+ const int mcoords[][2],
+ const int mcoords_len,
+ eSelectOp sel_op)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
@@ -782,7 +835,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
}
/* get rectangle from operator */
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* do actual selection */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -798,7 +851,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
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(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) {
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) {
nodeSetSelected(node, select);
changed = true;
}
@@ -813,15 +866,15 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves
static int node_lasso_select_exec(bContext *C, wmOperator *op)
{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- do_lasso_select_node(C, mcords, mcords_tot, sel_op);
+ do_lasso_select_node(C, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
return OPERATOR_FINISHED;
}
@@ -1112,10 +1165,10 @@ void NODE_OT_select_same_type_step(wmOperatorType *ot)
* \{ */
/* generic search invoke */
-static void node_find_cb(const struct bContext *C,
- void *UNUSED(arg),
- const char *str,
- uiSearchItems *items)
+static void node_find_update_fn(const struct bContext *C,
+ void *UNUSED(arg),
+ const char *str,
+ uiSearchItems *items)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *node;
@@ -1138,7 +1191,7 @@ static void node_find_cb(const struct bContext *C,
}
}
-static void node_find_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2)
+static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2)
{
SpaceNode *snode = CTX_wm_space_node(C);
bNode *active = arg2;
@@ -1178,7 +1231,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *region, void *arg_op)
0,
0,
"");
- UI_but_func_search_set(but, NULL, node_find_cb, op->type, NULL, node_find_call_cb, NULL);
+ UI_but_func_search_set(but, NULL, node_find_update_fn, op->type, NULL, node_find_exec_fn, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* fake button, it holds space for search items */
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 7d4095326f8..87b1f662b59 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -45,6 +45,7 @@
#include "UI_interface.h"
#include "ED_node.h" /* own include */
+#include "node_intern.h"
#include "ED_undo.h"
@@ -662,17 +663,23 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group"));
}
-void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
+void uiTemplateNodeLink(
+ uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock)
{
uiBlock *block = uiLayoutGetBlock(layout);
NodeLinkArg *arg;
uiBut *but;
+ float socket_col[4];
arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg");
arg->ntree = ntree;
arg->node = node;
arg->sock = sock;
+ PointerRNA node_ptr;
+ RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr);
+ node_socket_color_get(C, ntree, &node_ptr, sock, socket_col);
+
UI_block_layout_set_current(block, layout);
if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) {
@@ -687,8 +694,9 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo
}
UI_but_type_set_menu_from_pulldown(but);
+ UI_but_node_link_set(but, sock, socket_col);
+ UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT);
- but->flag |= UI_BUT_NODE_LINK;
but->poin = (char *)but;
but->func_argN = arg;
@@ -708,18 +716,14 @@ static void ui_node_draw_node(
uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth)
{
bNodeSocket *input;
- uiLayout *col, *split;
PointerRNA nodeptr;
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
if (node->typeinfo->draw_buttons) {
if (node->type != NODE_GROUP) {
- split = uiLayoutSplit(layout, 0.5f, false);
- col = uiLayoutColumn(split, false);
- col = uiLayoutColumn(split, false);
-
- node->typeinfo->draw_buttons(col, C, &nodeptr);
+ uiLayoutSetPropSep(layout, true);
+ node->typeinfo->draw_buttons(layout, C, &nodeptr);
}
}
@@ -733,12 +737,9 @@ static void ui_node_draw_input(
{
PointerRNA inputptr, nodeptr;
uiBlock *block = uiLayoutGetBlock(layout);
- uiBut *bt;
- uiLayout *split, *row, *col;
+ uiLayout *row = NULL;
bNode *lnode;
- char label[UI_MAX_NAME_STR];
- int i, indent = (depth > 1) ? 2 * (depth - 1) : 0;
- int dependency_loop;
+ bool dependency_loop;
if (input->flag & SOCK_UNAVAIL) {
return;
@@ -757,48 +758,43 @@ static void ui_node_draw_input(
RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr);
RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr);
- /* indented label */
- for (i = 0; i < indent; i++) {
- label[i] = ' ';
- }
- label[indent] = '\0';
- BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name));
+ row = uiLayoutRow(layout, true);
+ /* Decorations are added manually here. */
+ uiLayoutSetPropDecorate(row, false);
- /* split in label and value */
- split = uiLayoutSplit(layout, 0.5f, false);
+ uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(row);
+ /* Empty decorator item for alignment. */
+ bool add_dummy_decorator = false;
- row = uiLayoutRow(split, true);
+ {
+ uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true);
- if (depth > 0) {
- UI_block_emboss_set(block, UI_EMBOSS_NONE);
+ if (depth > 0) {
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
- 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;
- uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
- }
- else {
- uiItemL(row, "", ICON_BLANK1);
- }
+ 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;
+ uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon);
+ }
- bt = block->buttons.last;
- bt->rect.xmax = UI_UNIT_X / 2;
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
- UI_block_emboss_set(block, UI_EMBOSS);
+ sub = uiLayoutRow(sub, true);
+ uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
+ uiItemL(sub, IFACE_(input->name), ICON_NONE);
}
- uiItemL(row, label, ICON_NONE);
- bt = block->buttons.last;
- bt->drawflag = UI_BUT_TEXT_RIGHT;
-
if (dependency_loop) {
- row = uiLayoutRow(split, false);
uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR);
+ add_dummy_decorator = true;
}
else if (lnode) {
/* input linked to a node */
- uiTemplateNodeLink(split, ntree, node, input);
+ uiTemplateNodeLink(row, C, ntree, node, input);
+ add_dummy_decorator = true;
if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) {
if (depth == 0) {
@@ -809,33 +805,41 @@ static void ui_node_draw_input(
}
}
else {
+ row = uiLayoutRow(row, true);
+
+ uiTemplateNodeLink(row, C, ntree, node, input);
+
+ if (input->flag & SOCK_HIDE_VALUE) {
+ add_dummy_decorator = true;
+ }
/* input not linked, show value */
- if (!(input->flag & SOCK_HIDE_VALUE)) {
+ else {
+ uiLayout *sub = row;
+
switch (input->type) {
+ case SOCK_VECTOR:
+ if (input->type == SOCK_VECTOR) {
+ uiItemS(row);
+ sub = uiLayoutColumn(row, true);
+ }
+ ATTR_FALLTHROUGH;
case SOCK_FLOAT:
case SOCK_INT:
case SOCK_BOOLEAN:
case SOCK_RGBA:
case SOCK_STRING:
- row = uiLayoutRow(split, true);
- uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE);
- break;
- case SOCK_VECTOR:
- row = uiLayoutRow(split, false);
- col = uiLayoutColumn(row, false);
- uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE);
+ uiItemDecoratorR(
+ split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX);
break;
-
default:
- row = uiLayoutRow(split, false);
- break;
+ add_dummy_decorator = true;
}
}
- else {
- row = uiLayoutRow(split, false);
- }
+ }
- uiTemplateNodeLink(row, ntree, node, input);
+ if (add_dummy_decorator) {
+ uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0);
}
/* clear */
diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c
index 9283b073e86..e879e01ecc4 100644
--- a/source/blender/editors/space_node/node_view.c
+++ b/source/blender/editors/space_node/node_view.c
@@ -141,7 +141,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op)
void NODE_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->idname = "NODE_OT_view_all";
ot->description = "Resize view so you can see all nodes";
@@ -209,6 +209,7 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, const wmEvent *e
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
break;
@@ -354,6 +355,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op))
ED_region_tag_redraw(region);
WM_main_add_notifier(NC_NODE | ND_DISPLAY, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
return OPERATOR_FINISHED;
}
@@ -382,7 +384,7 @@ typedef struct ImageSampleInfo {
int x, y;
int channels;
- unsigned char col[4];
+ uchar col[4];
float colf[4];
float linearcol[4];
@@ -450,7 +452,7 @@ bool ED_space_node_color_sample(
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -463,7 +465,7 @@ bool ED_space_node_color_sample(
ret = true;
}
else if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
rgb_uchar_to_float(r_col, cp);
IMB_colormanagement_colorspace_to_scene_linear_v3(r_col, ibuf->rect_colorspace);
ret = true;
@@ -507,7 +509,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
if (fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
const float *fp;
- unsigned char *cp;
+ uchar *cp;
int x = (int)(fx * ibuf->x), y = (int)(fy * ibuf->y);
CLAMP(x, 0, ibuf->x - 1);
@@ -522,7 +524,7 @@ static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
info->zfp = NULL;
if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+ cp = (uchar *)(ibuf->rect + y * ibuf->x + x);
info->col[0] = cp[0];
info->col[1] = cp[1];
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index f6f13a8ba20..5da187c166d 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -328,17 +328,17 @@ static void node_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
static void node_area_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
/* note, ED_area_tag_refresh will re-execute compositor */
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
/* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */
short shader_type = snode->shaderfrom;
@@ -347,32 +347,32 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_SCENE:
switch (wmn->data) {
case ND_NODES: {
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
bNodeTreePath *path = snode->treepath.last;
/* shift view to node tree center */
if (region && path) {
UI_view2d_center_set(&region->v2d, path->view_center[0], path->view_center[1]);
}
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
case ND_FRAME:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case ND_COMPO_RESULT:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_TRANSFORM_DONE:
if (ED_node_is_compositor(snode)) {
if (snode->flag & SNODE_AUTO_RENDER) {
snode->recalc = 1;
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case ND_LAYER_CONTENT:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
@@ -381,13 +381,13 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_MATERIAL:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_SHADING) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SHADING_DRAW) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SHADING_LINKS) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->action == NA_ADDED && snode->edittree) {
nodeSetActiveID(snode->edittree, ID_MA, wmn->reference);
@@ -397,49 +397,49 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_TEXTURE:
if (ED_node_is_shader(snode) || ED_node_is_texture(snode)) {
if (wmn->data == ND_NODES) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case NC_WORLD:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_WORLD) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_OBJECT:
if (ED_node_is_shader(snode)) {
if (wmn->data == ND_OB_SHADING) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_NODE) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->data == ND_SPACE_NODE_VIEW) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_NODE:
if (wmn->action == NA_EDITED) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
else if (wmn->action == NA_SELECTED) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
case NC_SCREEN:
switch (wmn->data) {
case ND_ANIMPLAY:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
}
break;
case NC_MASK:
if (wmn->action == NA_EDITED) {
if (snode->nodetree && snode->nodetree->type == NTREE_COMPOSIT) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
break;
@@ -451,7 +451,7 @@ static void node_area_listener(wmWindow *UNUSED(win),
* scenes so really this is just to know if the images is used in the compo else
* painting on images could become very slow when the compositor is open. */
if (nodeUpdateID(snode->nodetree, wmn->reference)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
}
@@ -461,7 +461,7 @@ static void node_area_listener(wmWindow *UNUSED(win),
if (wmn->action == NA_EDITED) {
if (ED_node_is_compositor(snode)) {
if (nodeUpdateID(snode->nodetree, wmn->reference)) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
}
}
@@ -469,26 +469,26 @@ static void node_area_listener(wmWindow *UNUSED(win),
case NC_LINESTYLE:
if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_WM:
if (wmn->data == ND_UNDO) {
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
}
break;
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
-static void node_area_refresh(const struct bContext *C, ScrArea *sa)
+static void node_area_refresh(const struct bContext *C, ScrArea *area)
{
/* default now: refresh node is starting preview */
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
snode_set_context(C);
@@ -497,19 +497,19 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa)
if (GS(snode->id->name) == ID_MA) {
Material *ma = (Material *)snode->id;
if (ma->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
else if (GS(snode->id->name) == ID_LA) {
Light *la = (Light *)snode->id;
if (la->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
else if (GS(snode->id->name) == ID_WO) {
World *wo = (World *)snode->id;
if (wo->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
}
@@ -529,7 +529,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *sa)
else if (snode->nodetree->type == NTREE_TEXTURE) {
Tex *tex = (Tex *)snode->id;
if (tex->use_nodes) {
- ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
+ ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER);
}
}
}
@@ -585,9 +585,9 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region)
ED_region_panels(C, region);
}
-static void node_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
/* convert mouse coordinates to v2d space */
UI_view2d_region_to_view(&region->v2d,
@@ -642,7 +642,7 @@ static void node_header_region_draw(const bContext *C, ARegion *region)
/* used for header + main region */
static void node_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -791,23 +791,21 @@ static void node_widgets(void)
WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin);
}
-static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceNode *snode = (SpaceNode *)slink;
- if (GS(old_id->name) == ID_SCE) {
- if (snode->id == old_id) {
- /* nasty DNA logic for SpaceNode:
- * ideally should be handled by editor code, but would be bad level call
- */
- BLI_freelistN(&snode->treepath);
-
- /* XXX Untested in case new_id != NULL... */
- snode->id = new_id;
- snode->from = NULL;
- snode->nodetree = NULL;
- snode->edittree = NULL;
- }
+ if (snode->id == old_id) {
+ /* nasty DNA logic for SpaceNode:
+ * ideally should be handled by editor code, but would be bad level call
+ */
+ BLI_freelistN(&snode->treepath);
+
+ /* XXX Untested in case new_id != NULL... */
+ snode->id = new_id;
+ snode->from = NULL;
+ snode->nodetree = NULL;
+ snode->edittree = NULL;
}
else if (GS(old_id->name) == ID_OB) {
if (snode->from == old_id) {
@@ -830,8 +828,7 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
for (path = snode->treepath.first; path; path = path->next) {
if ((ID *)path->nodetree == old_id) {
path->nodetree = (bNodeTree *)new_id;
- id_us_min(old_id);
- id_us_plus(new_id);
+ id_us_ensure_real(new_id);
}
if (path == snode->treepath.first) {
/* first nodetree in path is same as snode->nodetree */
@@ -862,15 +859,15 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID
}
}
-static int node_space_subtype_get(ScrArea *sa)
+static int node_space_subtype_get(ScrArea *area)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
return rna_node_tree_idname_to_enum(snode->tree_idname);
}
-static void node_space_subtype_set(ScrArea *sa, int value)
+static void node_space_subtype_set(ScrArea *area, int value)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value));
}
@@ -879,6 +876,11 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
bool free;
const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
+#ifndef WITH_NEW_SIMULATION_TYPE
+ if (STREQ(item_iter->identifier, "SimulationNodeTree")) {
+ continue;
+ }
+#endif
RNA_enum_item_add(item, totitem, item_iter);
}
if (free) {
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 8563b7d8c24..82ff9e06194 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -300,19 +300,15 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c
return TRAVERSE_CONTINUE;
}
-static int collection_delete_exec(bContext *C, wmOperator *op)
+void outliner_collection_delete(
+ bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool hierarchy)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
+
struct CollectionEditData data = {
.scene = scene,
.soops = soops,
};
- bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy");
data.collections_to_edit = BLI_gset_ptr_new(__func__);
@@ -336,8 +332,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
skip = true;
}
else {
- for (CollectionParent *cparent = collection->parents.first; cparent;
- cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
Collection *parent = cparent->collection;
if (ID_IS_LINKED(parent)) {
skip = true;
@@ -359,7 +354,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
else {
BKE_reportf(
- op->reports,
+ reports,
RPT_WARNING,
"Cannot delete linked collection '%s', it is used by other linked scenes/collections",
collection->id.name + 2);
@@ -368,6 +363,17 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
}
BLI_gset_free(data.collections_to_edit, NULL);
+}
+
+static int collection_hierarchy_delete_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);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ const Base *basact_prev = BASACT(view_layer);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, true);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
DEG_relations_tag_update(bmain);
@@ -378,27 +384,24 @@ static int collection_delete_exec(bContext *C, wmOperator *op)
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
+ ED_outliner_select_sync_from_object_tag(C);
+
return OPERATOR_FINISHED;
}
-void OUTLINER_OT_collection_delete(wmOperatorType *ot)
+void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Collection";
- ot->idname = "OUTLINER_OT_collection_delete";
- ot->description = "Delete selected collections";
+ ot->name = "Delete Hierarchy";
+ ot->idname = "OUTLINER_OT_collection_hierarchy_delete";
+ ot->description = "Delete selected collection hierarchies";
/* api callbacks */
- ot->exec = collection_delete_exec;
+ ot->exec = collection_hierarchy_delete_exec;
ot->poll = ED_outliner_collections_editor_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
- PropertyRNA *prop = RNA_def_boolean(
- ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
@@ -459,6 +462,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -581,6 +585,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
DEG_relations_tag_update(bmain);
WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C));
+ ED_outliner_select_sync_from_object_tag(C);
return OPERATOR_FINISHED;
}
@@ -846,20 +851,6 @@ static bool collections_indirect_only_clear_poll(bContext *C)
return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY);
}
-static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag)
-{
- for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) {
- if (lc->flag & flag) {
- nlc->flag |= flag;
- }
- else {
- nlc->flag &= ~flag;
- }
-
- layer_collection_flag_recursive_set(nlc, flag);
- }
-}
-
static int collection_view_layer_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -884,15 +875,7 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op)
GSetIterator collections_to_edit_iter;
GSET_ITER (collections_to_edit_iter, data.collections_to_edit) {
LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter);
-
- if (clear) {
- lc->flag &= ~flag;
- }
- else {
- lc->flag |= flag;
- }
-
- layer_collection_flag_recursive_set(lc, flag);
+ BKE_layer_collection_set_flag(lc, flag, !clear);
}
BLI_gset_free(data.collections_to_edit, NULL);
@@ -1468,14 +1451,12 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op))
/* Unhide all the collections. */
LayerCollection *lc_master = view_layer->layer_collections.first;
- for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
- lc_iter->flag &= ~LAYER_COLLECTION_HIDE;
- layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_HIDE);
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) {
+ BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false);
}
/* Unhide all objects. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag &= ~BASE_HIDDEN;
}
diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c
index 68a02e7614c..9fb1d1cf8cf 100644
--- a/source/blender/editors/space_outliner/outliner_dragdrop.c
+++ b/source/blender/editors/space_outliner/outliner_dragdrop.c
@@ -264,8 +264,7 @@ static bool parent_drop_allowed(TreeElement *te, Object *potential_child)
* element for object it means that all displayed objects belong to
* active scene and parenting them is allowed (sergey) */
if (scene) {
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
if (BKE_view_layer_base_find(view_layer, potential_child)) {
return true;
}
@@ -482,7 +481,7 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven
ListBase *lb = event->customdata;
wmDrag *drag = lb->first;
- for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
if (GS(drag_id->id->name) == ID_OB) {
Object *object = (Object *)drag_id->id;
@@ -549,8 +548,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
BKE_collection_object_add(bmain, collection, ob);
- for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
- view_layer = view_layer->next) {
+ LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
if (base) {
ED_object_base_select(base, BA_SELECT);
@@ -678,6 +676,10 @@ static bool collection_drop_init(bContext *C,
if (ID_IS_LINKED(to_collection)) {
return false;
}
+ /* Currently this should not be allowed (might be supported in the future though...). */
+ if (ID_IS_OVERRIDE_LIBRARY(to_collection)) {
+ return false;
+ }
/* Get drag datablocks. */
if (drag->type != WM_DRAG_ID) {
@@ -818,7 +820,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE
TREESTORE(data.te)->flag &= ~TSE_CLOSED;
}
- for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) {
+ LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) {
/* Ctrl enables linking, so we don't need a from collection then. */
Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent);
@@ -985,6 +987,8 @@ static int outliner_item_drag_drop_invoke(bContext *C,
WM_drag_add_ID(drag, data.drag_id, data.drag_parent);
}
+ ED_outliner_select_sync_from_all_tag(C);
+
return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH);
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 3c569a71e93..7d3b95721c6 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -91,7 +91,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *soops,
int *width,
int *height)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
*width = MAX2(*width, te->xend);
if (height != NULL) {
*height += UI_UNIT_Y;
@@ -178,20 +178,13 @@ static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2)
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin);
}
-static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *poin2)
+static void restrictbutton_bone_visibility_cb(bContext *C, void *poin, void *UNUSED(poin2))
{
- bArmature *arm = (bArmature *)poin;
- Bone *bone = (Bone *)poin2;
- if (bone->flag & BONE_HIDDEN_P) {
- bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
+ Bone *bone = (Bone *)poin;
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0);
}
-
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE);
}
static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2)
@@ -387,8 +380,7 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
if (base_or_object_prop) {
/* Note: We can't use BKE_collection_object_cache_get()
* otherwise we would not take collection exclusion into account. */
- for (CollectionObject *cob = layer_collection->collection->gobject.first; cob;
- cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &layer_collection->collection->gobject) {
outliner_base_or_object_pointer_create(view_layer, collection, cob->ob, &ptr);
RNA_property_boolean_set(&ptr, base_or_object_prop, value);
@@ -401,7 +393,7 @@ static void outliner_collection_set_flag_recursive(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
- for (Link *link = lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (Link *, link, lb) {
LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
Collection *collection_iter = layer_collection ?
(collection ? layer_collection_iter->collection : NULL) :
@@ -467,7 +459,7 @@ static bool outliner_collection_is_isolated(Scene *scene,
/* Keep going recursively. */
ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children);
- for (Link *link = lb->first; link; link = link->next) {
+ LISTBASE_FOREACH (Link *, link, lb) {
LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL;
Collection *collection_iter = layer_collection ?
(collection ? layer_collection_iter->collection : NULL) :
@@ -542,8 +534,7 @@ void outliner_collection_isolate_flag(Scene *scene,
/* Make this collection direct parents also "visible". */
if (layer_collection) {
LayerCollection *lc_parent = layer_collection;
- for (LayerCollection *lc_iter = top_layer_collection->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &top_layer_collection->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
lc_parent = lc_iter;
break;
@@ -555,8 +546,7 @@ void outliner_collection_isolate_flag(Scene *scene,
scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr);
RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide);
- for (LayerCollection *lc_iter = lc_parent->layer_collections.first; lc_iter;
- lc_iter = lc_iter->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) {
if (BKE_layer_collection_has_layer_collection(lc_iter, layer_collection)) {
lc_parent = lc_iter;
break;
@@ -862,6 +852,7 @@ typedef struct RestrictProperties {
*layer_collection_hide_viewport;
PropertyRNA *modifier_show_viewport, *modifier_show_render;
PropertyRNA *constraint_enable;
+ PropertyRNA *bone_hide_viewport;
} RestrictProperties;
/* We don't care about the value of the property
@@ -880,6 +871,7 @@ typedef struct RestrictPropertiesActive {
bool modifier_show_viewport;
bool modifier_show_render;
bool constraint_enable;
+ bool bone_hide_viewport;
} RestrictPropertiesActive;
static void outliner_restrict_properties_enable_collection_set(
@@ -1014,6 +1006,8 @@ static void outliner_draw_restrictbuts(uiBlock *block,
props.constraint_enable = RNA_struct_type_find_property(&RNA_Constraint, "mute");
+ props.bone_hide_viewport = RNA_struct_type_find_property(&RNA_Bone, "hide");
+
props.initialized = true;
}
@@ -1054,7 +1048,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
/* Create buttons. */
uiBut *bt;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
RestrictPropertiesActive props_active = props_active_parent;
@@ -1282,27 +1276,32 @@ static void outliner_draw_restrictbuts(uiBlock *block,
}
}
else if (tselem->type == TSE_POSE_CHANNEL) {
+ PointerRNA ptr;
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
Bone *bone = pchan->bone;
Object *ob = (Object *)tselem->id;
+ bArmature *arm = ob->data;
+
+ RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr);
if (soops->show_restrict_flags & SO_RESTRICT_VIEWPORT) {
- bt = uiDefIconButBitI(block,
- UI_BTYPE_ICON_TOGGLE,
- BONE_HIDDEN_P,
- 0,
- ICON_RESTRICT_VIEW_OFF,
- (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
- te->ys,
- UI_UNIT_X,
- UI_UNIT_Y,
- &(bone->flag),
- 0,
- 0,
- 0,
- 0,
- TIP_("Restrict visibility in the 3D View"));
- UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone);
+ bt = uiDefIconButR_prop(block,
+ UI_BTYPE_ICON_TOGGLE,
+ 0,
+ 0,
+ (int)(region->v2d.cur.xmax - restrict_offsets.viewport),
+ te->ys,
+ UI_UNIT_X,
+ UI_UNIT_Y,
+ &ptr,
+ props.bone_hide_viewport,
+ -1,
+ 0,
+ 0,
+ -1,
+ -1,
+ TIP_("Restrict visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_bone_visibility_cb, bone, NULL);
UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE);
}
@@ -1651,7 +1650,7 @@ static void outliner_draw_userbuts(uiBlock *block,
ListBase *lb)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
if (tselem->type == 0) {
@@ -1770,7 +1769,7 @@ static void outliner_draw_rnabuts(
PointerRNA *ptr;
PropertyRNA *prop;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) {
if (tselem->type == TSE_RNA_PROPERTY) {
@@ -2194,6 +2193,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case eModifierType_WeightedNormal:
data.icon = ICON_MOD_NORMALEDIT;
break;
+ case eModifierType_Simulation:
+ data.icon = ICON_PHYSICS; /* TODO: Use correct icon. */
+ break;
/* Default */
case eModifierType_None:
case eModifierType_ShapeKey:
@@ -2584,6 +2586,10 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_PC:
data.icon = ICON_CURVE_BEZCURVE;
break;
+ case ID_SIM:
+ /* TODO: Use correct icon. */
+ data.icon = ICON_PHYSICS;
+ break;
default:
break;
}
@@ -2861,7 +2867,7 @@ static void outliner_draw_iconrow(bContext *C,
{
eOLDrawState active = OL_DRAWSEL_NONE;
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
/* object hierarchy always, further constrained on level */
@@ -3204,7 +3210,7 @@ static void outliner_draw_tree_element(bContext *C,
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
/* check if element needs to be drawn grayed out, but also gray out
* childs of a grayed out parent (pass on draw_grayed_out to childs) */
bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING);
@@ -3223,7 +3229,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
outliner_set_coord_tree_element(ten, startx, *starty);
}
@@ -3357,7 +3363,7 @@ static void outliner_draw_struct_marks(ARegion *region,
ListBase *lb,
int *starty)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
/* selection status */
@@ -3406,7 +3412,7 @@ static void outliner_draw_highlights_recursive(uint pos,
const bool is_searching = (SEARCHING_OUTLINER(soops) ||
(soops->outlinevis == SO_DATA_API && soops->search_string[0] != 0));
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
const TreeStoreElem *tselem = TREESTORE(te);
const int start_y = *io_start_y;
@@ -3555,7 +3561,7 @@ static void outliner_draw_tree(bContext *C,
// items themselves
starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
- for (TreeElement *te = soops->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &soops->tree) {
outliner_draw_tree_element(C,
block,
fstyle,
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 20dbfb71fa6..7c729612255 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -54,6 +54,7 @@
#include "BKE_outliner_treehash.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -82,9 +83,11 @@
#include "outliner_intern.h"
-/* ************************************************************** */
+/** \} */
-/* Highlight --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Highlight on Cursor Motion Operator
+ * \{ */
static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -139,7 +142,11 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* Toggle Open/Closed ------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Open/Closed Operator
+ * \{ */
/* Open or close a tree element, optionally toggling all children recursively */
void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all)
@@ -261,8 +268,10 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items");
}
+/** \} */
+
/* -------------------------------------------------------------------- */
-/** \name Object Mode Enter/Exit
+/** \name Object Mode Enter/Exit Utilities
* \{ */
static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter)
@@ -316,7 +325,9 @@ void item_object_mode_exit_cb(bContext *C,
/** \} */
-/* Rename --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Rename Operator
+ * \{ */
static void do_item_rename(ARegion *region,
TreeElement *te,
@@ -351,6 +362,12 @@ static void do_item_rename(ARegion *region,
else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
+ else if (ID_IS_LINKED(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit external library data");
+ }
+ else if (ID_IS_OVERRIDE_LIBRARY(tselem->id)) {
+ BKE_report(reports, RPT_WARNING, "Cannot edit name of an override data-block");
+ }
else if (outliner_is_collection_tree_element(te)) {
Collection *collection = outliner_collection_from_tree_element(te);
@@ -361,9 +378,6 @@ static void do_item_rename(ARegion *region,
add_textbut = true;
}
}
- else if (ID_IS_LINKED(tselem->id)) {
- BKE_report(reports, RPT_WARNING, "Cannot edit external library data");
- }
else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) {
BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library");
}
@@ -446,9 +460,16 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot)
ot->invoke = outliner_item_rename;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ID delete --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Delete Operator
+ * \{ */
static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem)
{
@@ -473,6 +494,14 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto
id->name);
return;
}
+ else if (te->idcode == ID_WS) {
+ BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
+ if (id->tag & LIB_TAG_DOIT) {
+ BKE_reportf(
+ reports, RPT_WARNING, "Cannot delete currently visible workspace id '%s'", id->name);
+ return;
+ }
+ }
BKE_id_delete(bmain, id);
@@ -552,9 +581,16 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot)
ot->invoke = outliner_id_delete_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ID remap --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Remap Operator
+ * \{ */
static int outliner_id_remap_exec(bContext *C, wmOperator *op)
{
@@ -685,7 +721,8 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
ot->exec = outliner_id_remap_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", "");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID);
@@ -727,7 +764,11 @@ void id_remap_cb(bContext *C,
WM_operator_properties_free(&op_props);
}
-/* ID copy/Paste ------------------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Copy Operator
+ * \{ */
static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree)
{
@@ -789,9 +830,16 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot)
ot->exec = outliner_id_copy_exec;
ot->poll = ED_operator_outliner_active;
+ /* Flags, don't need any undo here (this operator does not change anything in Blender data). */
ot->flag = 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID Paste Operator
+ * \{ */
+
static int outliner_id_paste_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
@@ -808,6 +856,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
+
return OPERATOR_FINISHED;
}
@@ -822,10 +871,15 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot)
ot->exec = outliner_id_paste_exec;
ot->poll = ED_operator_outliner_active;
- ot->flag = 0;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Library relocate/reload --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Relocate Operator
+ * \{ */
static int lib_relocate(
bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload)
@@ -929,6 +983,9 @@ void OUTLINER_OT_lib_relocate(wmOperatorType *ot)
ot->invoke = outliner_lib_relocate_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* XXX This does not work with several items
@@ -969,6 +1026,12 @@ static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Reload Operator
+ * \{ */
+
void OUTLINER_OT_lib_reload(wmOperatorType *ot)
{
ot->name = "Reload Library";
@@ -977,6 +1040,9 @@ void OUTLINER_OT_lib_reload(wmOperatorType *ot)
ot->invoke = outliner_lib_reload_invoke;
ot->poll = ED_operator_outliner_active;
+
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
void lib_reload_cb(bContext *C,
@@ -992,13 +1058,11 @@ void lib_reload_cb(bContext *C,
lib_relocate(C, te, tselem, ot, true);
}
-/* ************************************************************** */
-/* Setting Toggling Operators */
-
-/* =============================================== */
-/* Toggling Utilities (Exported) */
+/** \} */
-/* Apply Settings ------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Apply Settings Utilities
+ * \{ */
static int outliner_count_levels(ListBase *lb, const int curlevel)
{
@@ -1080,7 +1144,11 @@ bool outliner_flag_flip(ListBase *lb, short flag)
return changed;
}
-/* Restriction Columns ------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Restriction Column Utility
+ * \{ */
/* same check needed for both object operation and restrict column button func
* return 0 when in edit mode (cannot restrict view or select)
@@ -1106,10 +1174,11 @@ int common_restrict_check(bContext *C, Object *ob)
return 1;
}
-/* =============================================== */
-/* Outliner setting toggles */
+/** \} */
-/* Toggle Expanded (Outliner) ---------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name Toggle Expanded (Outliner) Operator
+ * \{ */
static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1142,7 +1211,11 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* Toggle Selected (Outliner) ---------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Selected (Outliner) Operator
+ * \{ */
static int outliner_select_all_exec(bContext *C, wmOperator *op)
{
@@ -1166,9 +1239,7 @@ static int outliner_select_all_exec(bContext *C, wmOperator *op)
break;
}
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -1194,10 +1265,11 @@ void OUTLINER_OT_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
-/* ************************************************************** */
-/* Hotkey Only Operators */
+/** \} */
-/* Show Active --------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/** \name View Show Active (Outliner) Operator
+ * \{ */
static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops,
TreeElement *te,
@@ -1292,7 +1364,7 @@ static void outliner_show_active(SpaceOutliner *so, ARegion *region, TreeElement
return;
}
- for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) {
+ LISTBASE_FOREACH (TreeElement *, ten, &te->subtree) {
outliner_show_active(so, region, ten, id);
}
}
@@ -1310,7 +1382,7 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
ID *id = TREESTORE(active_element)->id;
/* Expand all elements in the outliner with matching ID */
- for (TreeElement *te = so->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &so->tree) {
outliner_show_active(so, region, te, id);
}
@@ -1347,7 +1419,11 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* View Panning --------------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Panning (Outliner) Operator
+ * \{ */
static int outliner_scroll_page_exec(bContext *C, wmOperator *op)
{
@@ -1385,10 +1461,14 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Search ------------------------------------------------------- */
-// TODO: probably obsolete now with filtering?
+/** \} */
+
+#if 0 // TODO: probably obsolete now with filtering?
+
+/* -------------------------------------------------------------------- */
+/** \name Search
+ * \{ */
-#if 0
/* find next element that has this name */
static TreeElement *outliner_find_name(
@@ -1501,9 +1581,14 @@ static void outliner_find_panel(
BKE_reportf(reports, RPT_WARNING, "Not found: %s", name);
}
}
-#endif
-/* Show One Level ----------------------------------------------- */
+/** \} */
+
+#endif /* if 0 */
+
+/* -------------------------------------------------------------------- */
+/** \name Show One Level Operator
+ * \{ */
/* helper function for Show/Hide one level operator */
static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open)
@@ -1576,7 +1661,11 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* Show Hierarchy ----------------------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Show Hierarchy Operator
+ * \{ */
/* Helper function for tree_element_shwo_hierarchy() -
* recursively checks whether subtrees have any objects. */
@@ -1668,15 +1757,19 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot)
/* no undo or registry, UI option */
}
-/* ************************************************************** */
-/* ANIMATO OPERATIONS */
-/* KeyingSet and Driver Creation - Helper functions */
+/** \} */
-/* specialized poll callback for these operators to work in Datablocks view only */
+/* -------------------------------------------------------------------- */
+/** \name Animation Internal Utilities
+ * \{ */
+
+/**
+ * Specialized poll callback for these operators to work in data-blocks view only.
+ */
static bool ed_operator_outliner_datablocks_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if ((sa) && (sa->spacetype == SPACE_OUTLINER)) {
+ ScrArea *area = CTX_wm_area(C);
+ if ((area) && (area->spacetype == SPACE_OUTLINER)) {
SpaceOutliner *so = CTX_wm_space_outliner(C);
return (so->outlinevis == SO_DATA_API);
}
@@ -1834,19 +1927,23 @@ static void tree_element_to_path(TreeElement *te,
BLI_freelistN(&hierarchy);
}
-/* =============================================== */
-/* Driver Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
- * they depend on having RNA paths and/or hierarchies available.
+/* -------------------------------------------------------------------- */
+/** \name Driver Internal Utilities
+ * \{ */
+
+/**
+ * Driver Operations
+ *
+ * These operators are only available in data-browser mode for now,
+ * as they depend on having RNA paths and/or hierarchies available.
*/
enum {
DRIVERS_EDITMODE_ADD = 0,
DRIVERS_EDITMODE_REMOVE,
} /*eDrivers_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* Recursively iterate over tree, finding and working on selected items */
static void do_outliner_drivers_editop(SpaceOutliner *soops,
ListBase *tree,
@@ -1922,7 +2019,11 @@ static void do_outliner_drivers_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Add Operator
+ * \{ */
static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op)
{
@@ -1957,7 +2058,11 @@ void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Driver Remove Operator
+ * \{ */
static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op)
{
@@ -1992,10 +2097,16 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* =============================================== */
-/* Keying Set Operations */
+/** \} */
-/* These operators are only available in databrowser mode for now, as
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Internal Utilities
+ * \{ */
+
+/**
+ * Keying-Set Operations
+ *
+ * These operators are only available in data-browser mode for now, as
* they depend on having RNA paths and/or hierarchies available.
*/
enum {
@@ -2003,8 +2114,6 @@ enum {
KEYINGSET_EDITMODE_REMOVE,
} /*eKeyingSet_EditModes*/;
-/* Utilities ---------------------------------- */
-
/* find the 'active' KeyingSet, and add if not found (if adding is allowed) */
// TODO: should this be an API func?
static KeyingSet *verify_active_keyingset(Scene *scene, short add)
@@ -2096,7 +2205,11 @@ static void do_outliner_keyingset_editop(SpaceOutliner *soops,
}
}
-/* Add Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Add Operator
+ * \{ */
static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op)
{
@@ -2137,7 +2250,11 @@ void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* Remove Operator ---------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Keying-Set Remove Operator
+ * \{ */
static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2174,20 +2291,23 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************************************************************** */
-/* ORPHANED DATABLOCKS */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Purge Orphan Data-Blocks Operator
+ * \{ */
static bool ed_operator_outliner_id_orphans_active(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- if (sa != NULL && sa->spacetype == SPACE_OUTLINER) {
+ ScrArea *area = CTX_wm_area(C);
+ if (area != NULL && area->spacetype == SPACE_OUTLINER) {
SpaceOutliner *so = CTX_wm_space_outliner(C);
return (so->outlinevis == SO_ID_ORPHANS);
}
return true;
}
-/* Purge Orphans Operator --------------------------------------- */
+/** \} */
static void outliner_orphans_purge_tag(ID *id, int *num_tagged)
{
@@ -2249,7 +2369,7 @@ static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEv
static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int num_tagged[INDEX_ID_MAX] = {0};
@@ -2276,7 +2396,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
* outliner several mouse events can be handled in one cycle without
* handling notifiers/redraw which leads to deleting the same object twice.
* cleanup tree here to prevent such cases. */
- if ((sa != NULL) && (sa->spacetype == SPACE_OUTLINER)) {
+ if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) {
outliner_cleanup_tree(soops);
}
@@ -2305,3 +2425,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX);
RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
+
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index ae252d3dd30..8df0c3ec9ba 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -108,7 +108,8 @@ typedef struct TreeElementIcon {
ID_LP, \
ID_HA, \
ID_PT, \
- ID_VO) || /* Only in 'blendfile' mode ... :/ */ \
+ ID_VO, \
+ ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \
ELEM(GS((_id)->name), \
ID_SCR, \
ID_WM, \
@@ -193,7 +194,8 @@ typedef enum {
/* is the current element open? if so we also show children */
#define TSELEM_OPEN(telm, sv) \
- ((telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)))
+ (((telm)->flag & TSE_CLOSED) == 0 || \
+ (SEARCHING_OUTLINER(sv) && ((telm)->flag & TSE_CHILDSEARCH)))
/**
* Container to avoid passing around these variables to many functions.
@@ -426,6 +428,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot);
void OUTLINER_OT_action_set(struct wmOperatorType *ot);
void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot);
void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot);
+void OUTLINER_OT_delete(struct wmOperatorType *ot);
/* ---------------------------------------------------------------- */
@@ -437,11 +440,16 @@ void outliner_keymap(struct wmKeyConfig *keyconf);
bool outliner_is_collection_tree_element(const TreeElement *te);
struct Collection *outliner_collection_from_tree_element(const TreeElement *te);
+void outliner_collection_delete(struct bContext *C,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct ReportList *reports,
+ bool hierarchy);
void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot);
void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
-void OUTLINER_OT_collection_delete(struct wmOperatorType *ot);
+void OUTLINER_OT_collection_hierarchy_delete(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
void OUTLINER_OT_collection_link(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index f2c833e48af..e62d400e881 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -66,6 +66,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_action_set);
WM_operatortype_append(OUTLINER_OT_constraint_operation);
WM_operatortype_append(OUTLINER_OT_modifier_operation);
+ WM_operatortype_append(OUTLINER_OT_delete);
WM_operatortype_append(OUTLINER_OT_show_one_level);
WM_operatortype_append(OUTLINER_OT_show_active);
@@ -87,7 +88,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_collection_new);
WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked);
WM_operatortype_append(OUTLINER_OT_collection_duplicate);
- WM_operatortype_append(OUTLINER_OT_collection_delete);
+ WM_operatortype_append(OUTLINER_OT_collection_hierarchy_delete);
WM_operatortype_append(OUTLINER_OT_collection_objects_select);
WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
WM_operatortype_append(OUTLINER_OT_collection_link);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index d50a097e6f6..fa8422573ab 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -308,10 +308,11 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
bool recursive)
{
TreeStoreElem *tselem = TREESTORE(te);
- TreeStoreElem *parent_tselem;
+ TreeStoreElem *parent_tselem = NULL;
Scene *sce;
Base *base;
Object *ob = NULL;
+ TreeElement *te_ob = NULL;
/* if id is not object, we search back */
if (te->idcode == ID_OB) {
@@ -355,17 +356,25 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
}
}
- parent_tselem = TREESTORE(outliner_find_id(soops, &soops->tree, (ID *)ob));
+ te_ob = outliner_find_id(soops, &soops->tree, (ID *)ob);
+ if (te_ob != NULL && te_ob != te) {
+ parent_tselem = TREESTORE(te_ob);
+ }
+
if (base) {
if (set == OL_SETSEL_EXTEND) {
/* swap select */
if (base->flag & BASE_SELECTED) {
ED_object_base_select(base, BA_DESELECT);
- parent_tselem->flag &= ~TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag &= ~TSE_SELECTED;
+ }
}
else {
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
}
else {
@@ -381,7 +390,9 @@ static eOLDrawState tree_element_set_active_object(bContext *C,
BKE_view_layer_base_deselect_all(view_layer);
}
ED_object_base_select(base, BA_SELECT);
- parent_tselem->flag |= TSE_SELECTED;
+ if (parent_tselem) {
+ parent_tselem->flag |= TSE_SELECTED;
+ }
}
if (recursive) {
@@ -1252,7 +1263,7 @@ static bool do_outliner_range_select_recursive(ListBase *lb,
TreeElement *cursor,
bool selecting)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (selecting) {
@@ -1412,9 +1423,7 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
ED_region_tag_redraw_no_rebuild(region);
}
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
}
return OPERATOR_FINISHED;
@@ -1496,7 +1505,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
- for (TreeElement *te = soops->tree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &soops->tree) {
outliner_item_box_select(soops, scene, &rectf, te, select);
}
@@ -1504,9 +1513,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
ED_region_tag_redraw(region);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
return OPERATOR_FINISHED;
}
@@ -1744,9 +1751,7 @@ static int outliner_walk_select_invoke(bContext *C, wmOperator *op, const wmEven
/* Scroll outliner to focus on walk element */
outliner_walk_scroll(region, walk_element);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
ED_region_tag_redraw(region);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 745a527cc15..852773d3979 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -32,6 +32,7 @@
#include "BLI_compiler_compat.h"
#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BKE_armature.h"
#include "BKE_context.h"
@@ -95,8 +96,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C)
wmWindowManager *wm = CTX_wm_manager(C);
for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
- for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
+ LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOutliner *soutliner = (SpaceOutliner *)sl;
@@ -318,7 +319,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
SelectedItems *selected_items)
{
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
@@ -350,8 +351,9 @@ static void outliner_sync_selection_from_outliner(Scene *scene,
/* Set clean outliner and mark other outliners for syncing */
void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *soops)
{
- /* Don't sync in certain outliner display modes */
- if (ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
+ /* Don't sync if not checked or in certain outliner display modes */
+ if (!(soops->flag & SO_SYNC_SELECT) ||
+ ELEM(soops->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) {
return;
}
@@ -499,7 +501,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer,
SyncSelectActiveData *active_data,
const SyncSelectTypes *sync_types)
{
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0 && te->idcode == ID_OB) {
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 12be08550af..80a63af3f42 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -39,12 +39,14 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BKE_anim_data.h"
#include "BKE_animsys.h"
#include "BKE_collection.h"
#include "BKE_constraint.h"
@@ -87,9 +89,9 @@
#include "outliner_intern.h"
-/* ****************************************************** */
-
-/* ************ SELECTION OPERATIONS ********* */
+/* -------------------------------------------------------------------- */
+/** \name ID/Library/Data Set/Un-link Utilities
+ * \{ */
static void set_operation_types(SpaceOutliner *soops,
ListBase *lb,
@@ -159,6 +161,7 @@ static void set_operation_types(SpaceOutliner *soops,
case ID_HA:
case ID_PT:
case ID_VO:
+ case ID_SIM:
is_standard_id = true;
break;
case ID_WM:
@@ -411,7 +414,12 @@ static void outliner_do_libdata_operation(bContext *C,
}
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scene Menu Operator
+ * \{ */
+
typedef enum eOutliner_PropSceneOps {
OL_SCENE_OP_DELETE = 1,
} eOutliner_PropSceneOps;
@@ -499,7 +507,12 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", "");
}
-/* ******************************************** */
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Search Utilities
+ * \{ */
/**
* Stores the parent and a child element of a merged icon-row icon for
@@ -517,7 +530,7 @@ static void merged_element_search_cb_recursive(
char name[64];
int iconid;
- for (TreeElement *te = tree->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, tree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tree_element_id_type_to_index(te) == type && tselem_type == tselem->type) {
@@ -540,10 +553,10 @@ static void merged_element_search_cb_recursive(
}
/* Get a list of elements that match the search string */
-static void merged_element_search_cb(const bContext *UNUSED(C),
- void *data,
- const char *str,
- uiSearchItems *items)
+static void merged_element_search_update_fn(const bContext *UNUSED(C),
+ void *data,
+ const char *str,
+ uiSearchItems *items)
{
MergedSearchData *search_data = (MergedSearchData *)data;
TreeElement *parent = search_data->parent_element;
@@ -555,7 +568,7 @@ static void merged_element_search_cb(const bContext *UNUSED(C),
}
/* Activate an element from the merged element search menu */
-static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element)
+static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1), void *element)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te = (TreeElement *)element;
@@ -563,9 +576,7 @@ static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1)
outliner_item_select(soops, te, false, false);
outliner_item_do_activate_from_tree_element(C, te, te->store_elem, false, false);
- if (soops->flag & SO_SYNC_SELECT) {
- ED_outliner_select_sync_from_outliner(C, soops);
- }
+ ED_outliner_select_sync_from_outliner(C, soops);
}
/**
@@ -589,7 +600,7 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d
but = uiDefSearchBut(
block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, "");
UI_but_func_search_set(
- but, NULL, merged_element_search_cb, data, NULL, merged_element_search_call_cb, NULL);
+ but, NULL, merged_element_search_update_fn, data, NULL, merged_element_search_exec_fn, NULL);
UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT);
/* Fake button to hold space for search items */
@@ -642,6 +653,12 @@ static void object_select_cb(bContext *C,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Callbacks (Selection, Users & Library) Utilities
+ * \{ */
+
static void object_select_hierarchy_cb(bContext *C,
ReportList *UNUSED(reports),
Scene *UNUSED(scene),
@@ -672,13 +689,10 @@ static void object_deselect_cb(bContext *C,
}
}
-static void object_delete_cb(bContext *C,
- ReportList *reports,
- Scene *scene,
- TreeElement *UNUSED(te),
- TreeStoreElem *UNUSED(tsep),
- TreeStoreElem *tselem,
- void *UNUSED(user_data))
+static void outliner_object_delete(bContext *C,
+ ReportList *reports,
+ Scene *scene,
+ TreeStoreElem *tselem)
{
Object *ob = (Object *)tselem->id;
if (ob) {
@@ -884,7 +898,11 @@ void outliner_do_object_operation(bContext *C,
outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true);
}
-/* ******************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Tagging Utilities
+ * \{ */
static void clear_animdata_cb(int UNUSED(event),
TreeElement *UNUSED(te),
@@ -913,7 +931,7 @@ static void cleardrivers_animdata_cb(int UNUSED(event),
IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id;
/* just free drivers - stored as a list of F-Curves */
- free_fcurves(&iat->adt->drivers);
+ BKE_fcurves_free(&iat->adt->drivers);
DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION);
}
@@ -936,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event),
}
}
-/* --------------------------------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Operation Utilities
+ * \{ */
typedef enum eOutliner_PropDataOps {
OL_DOP_SELECT = 1,
@@ -1309,13 +1331,16 @@ static void object_batch_delete_hierarchy_cb(bContext *C,
}
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Object Menu Operator
+ * \{ */
enum {
OL_OP_SELECT = 1,
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
- OL_OP_DELETE,
OL_OP_DELETE_HIERARCHY,
OL_OP_REMAP,
OL_OP_LOCALIZED, /* disabled, see below */
@@ -1331,7 +1356,6 @@ static const EnumPropertyItem prop_object_op_types[] = {
{OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""},
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
- {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""},
{OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_REMAP,
"REMAP",
@@ -1353,6 +1377,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int event;
const char *str = NULL;
+ bool selection_changed = false;
/* check for invalid states */
if (soops == NULL) {
@@ -1369,8 +1394,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
}
str = "Select Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ selection_changed = true;
}
else if (event == OL_OP_SELECT_HIERARCHY) {
Scene *sce = scene; // to be able to delete, scenes are set...
@@ -1380,36 +1404,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_window_set_active_scene(bmain, C, win, sce);
}
str = "Select Object Hierarchy";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ selection_changed = true;
}
else if (event == OL_OP_DESELECT) {
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb);
str = "Deselect Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- }
- else if (event == OL_OP_DELETE) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const Base *basact_prev = BASACT(view_layer);
-
- outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb);
-
- /* XXX: tree management normally happens from draw_outliner(), but when
- * you're clicking to fast on Delete object from context menu in
- * outliner several mouse events can be handled in one cycle without
- * handling notifiers/redraw which leads to deleting the same object twice.
- * cleanup tree here to prevent such cases. */
- outliner_cleanup_tree(soops);
-
- DEG_relations_tag_update(bmain);
- str = "Delete Objects";
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
- if (basact_prev != BASACT(view_layer)) {
- WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
- WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
- }
+ selection_changed = true;
}
else if (event == OL_OP_DELETE_HIERARCHY) {
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1435,7 +1435,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
}
- /* XXX: See OL_OP_DELETE comment above. */
+ /* XXX: See outliner_delete_exec comment below. */
outliner_cleanup_tree(soops);
DEG_relations_tag_update(bmain);
@@ -1446,10 +1446,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
}
+ selection_changed = true;
}
else if (event == OL_OP_REMAP) {
outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- str = "Remap ID";
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth trick
+ * does not work here). */
}
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb);
@@ -1474,7 +1476,15 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- ED_undo_push(C, str);
+ if (selection_changed) {
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+ }
+
+ if (str != NULL) {
+ ED_undo_push(C, str);
+ }
return OPERATOR_FINISHED;
}
@@ -1495,7 +1505,85 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Delete Object/Collection Operator
+ * \{ */
+
+static void outliner_objects_delete(
+ bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb)
+{
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if (tselem->flag & TSE_SELECTED) {
+ if (tselem->type == 0 && te->idcode == ID_OB) {
+ outliner_object_delete(C, reports, scene, tselem);
+ }
+ }
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ outliner_objects_delete(C, scene, soops, reports, &te->subtree);
+ }
+ }
+}
+
+static int outliner_delete_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ SpaceOutliner *soops = 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);
+
+ outliner_collection_delete(C, bmain, scene, op->reports, false);
+ outliner_objects_delete(C, scene, soops, op->reports, &soops->tree);
+
+ /* Tree management normally happens from draw_outliner(), but when
+ * you're clicking too fast on Delete object from context menu in
+ * outliner several mouse events can be handled in one cycle without
+ * handling notifiers/redraw which leads to deleting the same object twice.
+ * cleanup tree here to prevent such cases. */
+ outliner_cleanup_tree(soops);
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
+ DEG_relations_tag_update(bmain);
+
+ if (basact_prev != BASACT(view_layer)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active);
+ }
+
+ DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ ED_outliner_select_sync_from_object_tag(C);
+
+ return OPERATOR_FINISHED;
+}
+
+void OUTLINER_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "OUTLINER_OT_delete";
+ ot->description = "Delete selected objects and collections";
+
+ /* callbacks */
+ ot->exec = outliner_delete_exec;
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ID-Data Menu Operator
+ * \{ */
typedef enum eOutlinerIdOpTypes {
OUTLINER_IDOP_INVALID = 0,
@@ -1596,6 +1684,7 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C,
static int outliner_id_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
@@ -1716,16 +1805,23 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
if (idlevel > 0) {
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL);
- ED_undo_push(C, "Remap");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
}
break;
}
case OUTLINER_IDOP_COPY: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
+ /* No need for undo, this operation does not change anything... */
break;
}
case OUTLINER_IDOP_PASTE: {
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL);
+ wm->op_undo_depth--;
+ ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Paste");
break;
}
@@ -1759,6 +1855,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_IDOP_SELECT_LINKED:
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL);
+ ED_outliner_select_sync_from_all_tag(C);
ED_undo_push(C, "Select");
break;
@@ -1793,7 +1890,11 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot)
RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf);
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Library Menu Operator
+ * \{ */
typedef enum eOutlinerLibOpTypes {
OL_LIB_INVALID = 0,
@@ -1838,7 +1939,6 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
switch (event) {
case OL_LIB_RENAME: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL);
@@ -1853,16 +1953,17 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op)
break;
}
case OL_LIB_RELOCATE: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL);
- ED_undo_push(C, "Relocate Library");
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
case OL_LIB_RELOAD: {
- /* rename */
outliner_do_libdata_operation(
C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL);
+ /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth
+ * trick does not work here). */
break;
}
default:
@@ -1894,7 +1995,11 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot)
ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Outliner Set Active Action Operator
+ * \{ */
static void outliner_do_id_set_operation(
SpaceOutliner *soops,
@@ -1920,8 +2025,6 @@ static void outliner_do_id_set_operation(
}
}
-/* ------------------------------------------ */
-
static void actionset_id_cb(TreeElement *UNUSED(te),
TreeStoreElem *tselem,
TreeStoreElem *tsep,
@@ -2009,7 +2112,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
/* flags */
- ot->flag = 0;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
// TODO: this would be nicer as an ID-pointer...
@@ -2019,7 +2122,11 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
ot->prop = prop;
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Menu Operator
+ * \{ */
typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
@@ -2053,6 +2160,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = {
static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
eOutliner_AnimDataOps event;
@@ -2081,7 +2189,10 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
+ wm->op_undo_depth++;
WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
+ wm->op_undo_depth--;
+ ED_undo_push(C, "Set active action");
break;
case OUTLINER_ANIMOP_CLEAR_ACT:
@@ -2135,7 +2246,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", "");
}
-/* **************************************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Constraint Menu Operator
+ * \{ */
static const EnumPropertyItem prop_constraint_op_types[] = {
{OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""},
@@ -2181,7 +2296,11 @@ void OUTLINER_OT_constraint_operation(wmOperatorType *ot)
ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modifier Menu Operator
+ * \{ */
static const EnumPropertyItem prop_modifier_op_types[] = {
{OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""},
@@ -2226,7 +2345,11 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Data Menu Operator
+ * \{ */
// XXX: select linked is for RNA structs only
static const EnumPropertyItem prop_data_op_types[] = {
@@ -2319,7 +2442,11 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", "");
}
-/* ******************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Context Menu Operator
+ * \{ */
static int outliner_operator_menu(bContext *C, const char *opname)
{
@@ -2331,11 +2458,9 @@ static int outliner_operator_menu(bContext *C, const char *opname)
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN);
uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop));
- MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false);
- if (mt) {
- uiItemS(layout);
- UI_menutype_draw(C, mt, layout);
- }
+ uiItemS(layout);
+
+ uiItemMContents(layout, "OUTLINER_MT_context_menu");
UI_popup_menu_end(C, pup);
@@ -2363,6 +2488,7 @@ static int do_outliner_operation_event(
/* Only redraw, don't rebuild here because TreeElement pointers will
* become invalid and operations will crash. */
ED_region_tag_redraw_no_rebuild(region);
+ ED_outliner_select_sync_from_outliner(C, soops);
}
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
@@ -2470,14 +2596,8 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
}
- /* Menus for clicking in empty space. */
- if (soops->outlinevis == SO_VIEW_LAYER) {
- WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_FINISHED;
- }
-
- WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN);
- return OPERATOR_FINISHED;
+ /* Let this fall through to 'OUTLINER_MT_context_menu'. */
+ return OPERATOR_PASS_THROUGH;
}
/* Menu only! Calls other operators */
@@ -2492,4 +2612,4 @@ void OUTLINER_OT_operation(wmOperatorType *ot)
ot->poll = ED_operator_outliner_active;
}
-/* ****************************************************** */
+/** \} */
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index d89a755f1c6..d6efe683673 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -46,6 +46,7 @@
#include "DNA_pointcloud_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_simulation_types.h"
#include "DNA_speaker_types.h"
#include "DNA_volume_types.h"
#include "DNA_world_types.h"
@@ -58,7 +59,7 @@
#include "BLT_translation.h"
-#include "BKE_fcurve.h"
+#include "BKE_fcurve_driver.h"
#include "BKE_idtype.h"
#include "BKE_layer.h"
#include "BKE_lib_id.h"
@@ -773,6 +774,13 @@ static void outliner_add_id_contents(SpaceOutliner *soops,
outliner_add_element(soops, &te->subtree, volume, te, TSE_ANIM_DATA, 0);
break;
}
+ case ID_SIM: {
+ Simulation *simulation = (Simulation *)id;
+ if (outliner_animdata_test(simulation->adt)) {
+ outliner_add_element(soops, &te->subtree, simulation, te, TSE_ANIM_DATA, 0);
+ }
+ break;
+ }
default:
break;
}
@@ -1254,7 +1262,7 @@ static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type)
Collection *collection = (Collection *)id;
bool has_non_scene_parent = false;
- for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) {
+ LISTBASE_FOREACH (CollectionParent *, cparent, &collection->parents) {
if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) {
has_non_scene_parent = true;
}
@@ -1387,7 +1395,7 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *soops
static void outliner_add_layer_collection_objects(
SpaceOutliner *soops, ListBase *tree, ViewLayer *layer, LayerCollection *lc, TreeElement *ten)
{
- for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &lc->collection->gobject) {
Base *base = BKE_view_layer_base_find(layer, cob->ob);
TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
te_object->directdata = base;
@@ -1405,7 +1413,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
TreeElement *parent_ten,
const bool show_objects)
{
- for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) {
+ LISTBASE_FOREACH (LayerCollection *, lc, layer_collections) {
const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0;
TreeElement *ten;
@@ -1419,9 +1427,9 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
ten->name = id->name + 2;
ten->directdata = lc;
- /* Open by default. */
+ /* Open by default, except linked collections, which may contain many elements. */
TreeStoreElem *tselem = TREESTORE(ten);
- if (!tselem->used) {
+ if (!(tselem->used || ID_IS_LINKED(id) || ID_IS_OVERRIDE_LIBRARY(id))) {
tselem->flag &= ~TSE_CLOSED;
}
@@ -1468,7 +1476,7 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *soops,
Collection *collection,
TreeElement *parent)
{
- for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) {
+ LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
outliner_add_element(soops, tree, cob->ob, parent, 0, 0);
}
}
@@ -1479,7 +1487,7 @@ static TreeElement *outliner_add_collection_recursive(SpaceOutliner *soops,
{
outliner_add_collection_init(ten, collection);
- for (CollectionChild *child = collection->children.first; child; child = child->next) {
+ LISTBASE_FOREACH (CollectionChild *, child, &collection->children) {
outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0);
}
@@ -1542,7 +1550,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
continue;
}
- for (LinkData *link = parent_ob_tree_elements->first; link; link = link->next) {
+ LISTBASE_FOREACH (LinkData *, link, parent_ob_tree_elements) {
TreeElement *parent_ob_tree_element = link->data;
TreeElement *parent_ob_collection_tree_element = NULL;
bool found = false;
@@ -1556,8 +1564,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
parent_ob_collection_tree_element = parent_ob_collection_tree_element->parent;
}
- for (LinkData *link_iter = child_ob_tree_elements->first; link_iter;
- link_iter = link_iter->next) {
+ LISTBASE_FOREACH (LinkData *, link_iter, child_ob_tree_elements) {
TreeElement *child_ob_tree_element = link_iter->data;
if (child_ob_tree_element->parent == parent_ob_collection_tree_element) {
@@ -1589,7 +1596,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo
static void outliner_object_tree_elements_lookup_create_recursive(GHash *object_tree_elements_hash,
TreeElement *te_parent)
{
- for (TreeElement *te = te_parent->subtree.first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, &te_parent->subtree) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == TSE_LAYER_COLLECTION) {
@@ -2427,7 +2434,7 @@ void outliner_build_tree(
else if (soops->outlinevis == SO_VIEW_LAYER) {
if (soops->filter & SO_FILTER_NO_COLLECTION) {
/* Show objects in the view layer. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
TreeElement *te_object = outliner_add_element(
soops, &soops->tree, base->object, NULL, 0, 0);
te_object->directdata = base;
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 45b46788c8f..a058c30cef2 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -23,6 +23,7 @@
#include <string.h>
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
@@ -77,7 +78,7 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
const ListBase *tree,
float view_co_y)
{
- for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) {
+ LISTBASE_FOREACH (TreeElement *, te_iter, tree) {
if (view_co_y < (te_iter->ys + UI_UNIT_Y)) {
if (view_co_y >= te_iter->ys) {
/* co_y is inside this element */
@@ -203,7 +204,7 @@ TreeElement *outliner_find_tse(SpaceOutliner *soops, const TreeStoreElem *tse)
/* Find treestore that refers to given ID */
TreeElement *outliner_find_id(SpaceOutliner *soops, ListBase *lb, const ID *id)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
TreeStoreElem *tselem = TREESTORE(te);
if (tselem->type == 0) {
if (tselem->id == id) {
@@ -221,7 +222,7 @@ TreeElement *outliner_find_id(SpaceOutliner *soops, ListBase *lb, const ID *id)
TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if (te->directdata == pchan) {
return te;
}
@@ -239,7 +240,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan)
TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if (te->directdata == ebone) {
return te;
}
@@ -360,7 +361,7 @@ float outliner_restrict_columns_width(const SpaceOutliner *soops)
/* Find first tree element in tree with matching treestore flag */
TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag)
{
- for (TreeElement *te = lb->first; te; te = te->next) {
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
if ((TREESTORE(te)->flag & flag) == flag) {
return te;
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 62268a1d455..00b62bc32ce 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -101,7 +101,7 @@ static void outliner_main_region_free(ARegion *UNUSED(region))
}
static void outliner_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -236,11 +236,11 @@ static void outliner_main_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
- SpaceOutliner *soops = sa->spacedata.first;
+ SpaceOutliner *soops = area->spacedata.first;
wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
.owner = region,
.user_data = region,
@@ -270,7 +270,7 @@ static void outliner_header_region_free(ARegion *UNUSED(region))
}
static void outliner_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -336,7 +336,7 @@ static void outliner_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -355,7 +355,7 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl)
return (SpaceLink *)soutlinern;
}
-static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void outliner_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceOutliner *so = (SpaceOutliner *)slink;
@@ -388,12 +388,12 @@ static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id,
}
}
-static void outliner_deactivate(struct ScrArea *sa)
+static void outliner_deactivate(struct ScrArea *area)
{
/* Remove hover highlights */
- SpaceOutliner *soops = sa->spacedata.first;
+ SpaceOutliner *soops = area->spacedata.first;
outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED, false);
- ED_region_tag_redraw(BKE_area_find_region_type(sa, RGN_TYPE_WINDOW));
+ ED_region_tag_redraw(BKE_area_find_region_type(area, RGN_TYPE_WINDOW));
}
/* only called once, from space_api/spacetypes.c */
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 79311cac6b5..e9ed1cec228 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -92,7 +92,7 @@ static bool script_test_modal_operators(bContext *C)
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
if (handler->op != NULL) {
wmOperatorType *ot = handler->op->type;
- if (ot->ext.srna) {
+ if (ot->rna_ext.srna) {
return true;
}
}
diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c
index d872facd488..343f35421a4 100644
--- a/source/blender/editors/space_script/space_script.c
+++ b/source/blender/editors/space_script/space_script.c
@@ -94,7 +94,7 @@ static void script_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void script_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void script_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -160,7 +160,7 @@ static void script_header_region_draw(const bContext *C, ARegion *region)
}
static void script_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index ac9b605b193..6202a3556a4 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -51,8 +51,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* for menu/popup icons etc etc*/
-
+/* For menu, popup, icons, etc. */
#include "ED_screen.h"
#include "ED_sequencer.h"
@@ -67,16 +66,16 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
typedef struct SequencerAddData {
ImageFormatData im_format;
} SequencerAddData;
-/* Generic functions, reused by add strip operators */
+/* Generic functions, reused by add strip operators. */
-/* avoid passing multiple args and be more verbose */
+/* Avoid passing multiple args and be more verbose. */
#define SEQPROP_STARTFRAME (1 << 0)
#define SEQPROP_ENDFRAME (1 << 1)
#define SEQPROP_NOPATHS (1 << 2)
@@ -101,7 +100,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
}
if (flag & SEQPROP_ENDFRAME) {
- /* not usual since most strips have a fixed length */
+ /* Not usual since most strips have a fixed length. */
RNA_def_int(ot->srna,
"frame_end",
0,
@@ -119,7 +118,7 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag)
RNA_def_boolean(
ot->srna, "replace_sel", 1, "Replace Selection", "Replace the current selection");
- /* only for python scripts which import strips and place them after */
+ /* Only for python scripts which import strips and place them after. */
prop = RNA_def_boolean(
ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips");
RNA_def_property_flag(prop, PROP_HIDDEN);
@@ -175,7 +174,7 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i
int cfra = (int)CFRA;
- /* effect strips don't need a channel initialized from the mouse */
+ /* Effect strips don't need a channel initialized from the mouse. */
if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) {
RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type));
}
@@ -203,18 +202,17 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
memset(seq_load, 0, sizeof(SeqLoadInfo));
seq_load->start_frame = RNA_int_get(op->ptr, "frame_start");
- seq_load->end_frame = seq_load->start_frame; /* un-set */
-
+ seq_load->end_frame = seq_load->start_frame;
seq_load->channel = RNA_int_get(op->ptr, "channel");
- seq_load->len = 1; // images only, if endframe isn't set!
+ seq_load->len = 1;
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
- /* full path, file is set by the caller */
+ /* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
is_file = 1;
}
else if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
- /* full path, file is set by the caller */
+ /* Full path, file is set by the caller. */
RNA_property_string_get(op->ptr, prop, seq_load->path);
is_file = 0;
}
@@ -252,15 +250,13 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
seq_load->flag |= SEQ_LOAD_SYNC_FPS;
}
- /* always use this for ops */
+ /* Create consecutive array of strips. */
seq_load->flag |= SEQ_LOAD_FRAME_ADVANCE;
if (is_file == 1) {
BLI_strncpy(seq_load->name, BLI_path_basename(seq_load->path), sizeof(seq_load->name));
}
else if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
- /* used for image strip */
- /* best guess, first images name */
RNA_PROP_BEGIN (op->ptr, itemptr, prop) {
char *name = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
BLI_strncpy(seq_load->name, name, sizeof(seq_load->name));
@@ -278,9 +274,6 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato
seq_load->views_format = imf->views_format;
seq_load->flag |= SEQ_USE_VIEWS;
-
- /* operator custom data is always released after the SeqLoadInfo,
- * no need to handle the memory here */
seq_load->stereo3d_format = &imf->stereo3d_format;
}
}
@@ -332,22 +325,17 @@ static bool seq_effect_add_properties_poll(const bContext *UNUSED(C),
return true;
}
-/* add scene operator */
static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
Scene *sce_seq;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
sce_seq = BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene"));
if (sce_seq == NULL) {
@@ -356,11 +344,8 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_SCENE);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
-
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->scene = sce_seq;
-
- /* basic defaults */
seq->len = sce_seq->r.efra - sce_seq->r.sfra + 1;
BLI_strncpy(seq->name + 2, sce_seq->id.name + 2, sizeof(seq->name) - 2);
@@ -388,26 +373,23 @@ static int sequencer_add_scene_strip_invoke(bContext *C, wmOperator *op, const w
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_SCENE);
return sequencer_add_scene_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Scene Strip";
ot->idname = "SEQUENCER_OT_scene_strip_add";
ot->description = "Add a strip to the sequencer using a blender scene as a source";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_scene_strip_invoke;
ot->exec = sequencer_add_scene_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -417,22 +399,17 @@ void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
-/* add movieclip operator */
static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
MovieClip *clip;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
clip = BLI_findlink(&bmain->movieclips, RNA_enum_get(op->ptr, "clip"));
if (clip == NULL) {
@@ -443,12 +420,10 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MOVIECLIP);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
+ seq->len = BKE_movieclip_get_duration(clip);
id_us_ensure_real(&seq->clip->id);
- /* basic defaults */
- seq->len = BKE_movieclip_get_duration(clip);
-
BLI_strncpy(seq->name + 2, clip->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
@@ -473,26 +448,23 @@ static int sequencer_add_movieclip_strip_invoke(bContext *C, wmOperator *op, con
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIECLIP);
return sequencer_add_movieclip_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_movieclip_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add MovieClip Strip";
ot->idname = "SEQUENCER_OT_movieclip_strip_add";
ot->description = "Add a movieclip strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_movieclip_strip_invoke;
ot->exec = sequencer_add_movieclip_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -508,16 +480,12 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
Mask *mask;
+ Sequence *seq;
- Sequence *seq; /* generic strip vars */
-
- int start_frame, channel; /* operator props */
-
+ int start_frame, channel;
start_frame = RNA_int_get(op->ptr, "frame_start");
channel = RNA_int_get(op->ptr, "channel");
-
mask = BLI_findlink(&bmain->masks, RNA_enum_get(op->ptr, "mask"));
if (mask == NULL) {
@@ -528,12 +496,10 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, SEQ_TYPE_MASK);
seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
+ seq->len = BKE_mask_get_duration(mask);
id_us_ensure_real(&seq->mask->id);
- /* basic defaults */
- seq->len = BKE_mask_get_duration(mask);
-
BLI_strncpy(seq->name + 2, mask->id.name + 2, sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
@@ -558,26 +524,23 @@ static int sequencer_add_mask_strip_invoke(bContext *C, wmOperator *op, const wm
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MASK);
return sequencer_add_mask_strip_exec(C, op);
- // needs a menu
- // return WM_menu_invoke(C, op, event);
}
void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Mask Strip";
ot->idname = "SEQUENCER_OT_mask_strip_add";
ot->description = "Add a mask strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_mask_strip_invoke;
ot->exec = sequencer_add_mask_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME);
@@ -587,9 +550,9 @@ void SEQUENCER_OT_mask_strip_add(struct wmOperatorType *ot)
ot->prop = prop;
}
-static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFunc seq_load_func)
+static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoadFn seq_load_fn)
{
- Scene *scene = CTX_data_scene(C); /* only for sound */
+ Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
int tot_files;
@@ -603,7 +566,6 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
tot_files = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
if (tot_files > 1) {
- /* multiple files */
char dir_only[FILE_MAX];
char file_only[FILE_MAX];
@@ -614,10 +576,10 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only);
- /* Set seq_load.name, else all video/audio files get the same name! ugly! */
+ /* Set seq_load.name, otherwise all video/audio files get the same name. */
BLI_strncpy(seq_load.name, file_only, sizeof(seq_load.name));
- seq = seq_load_func(C, ed->seqbasep, &seq_load);
+ seq = seq_load_fn(C, ed->seqbasep, &seq_load);
if (seq) {
sequencer_add_apply_overlap(C, op, seq);
if (seq_load.seq_sound) {
@@ -627,11 +589,10 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
}
RNA_END;
}
- else {
+ else { /* Single file./ */
Sequence *seq;
+ seq = seq_load_fn(C, ed->seqbasep, &seq_load);
- /* single file */
- seq = seq_load_func(C, ed->seqbasep, &seq_load);
if (seq) {
sequencer_add_apply_overlap(C, op, seq);
if (seq_load.seq_sound) {
@@ -658,7 +619,6 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
return OPERATOR_FINISHED;
}
-/* add sequencer operators */
static void sequencer_add_init(bContext *UNUSED(C), wmOperator *op)
{
op->customdata = MEM_callocN(sizeof(SequencerAddData), __func__);
@@ -672,9 +632,9 @@ static void sequencer_add_cancel(bContext *UNUSED(C), wmOperator *op)
op->customdata = NULL;
}
-static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr),
- PropertyRNA *prop,
- void *UNUSED(user_data))
+static bool sequencer_add_draw_check_fn(PointerRNA *UNUSED(ptr),
+ PropertyRNA *prop,
+ void *UNUSED(user_data))
{
const char *prop_id = RNA_property_identifier(prop);
@@ -682,7 +642,6 @@ static bool sequencer_add_draw_check_prop(PointerRNA *UNUSED(ptr),
STREQ(prop_id, "filename"));
}
-/* add movie operator */
static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_movie_strip);
@@ -696,20 +655,12 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- /* only enable "use_framerate" if there aren't any existing strips
- * - When there are no strips yet, there is no harm in enabling this,
- * and it makes the single-strip case really nice for casual users
- * - When there are strips, it's best we don't touch the framerate,
- * as all hell may break loose (e.g. audio strips start overlapping
- * and can't be restored)
- * - These initial guesses can still be manually overridden by users
- * from the modal options panel
- */
+ /* Only enable "use_framerate" if there aren't any existing strips, unless overridden by user. */
if (ed && ed->seqbasep && ed->seqbasep->first) {
RNA_boolean_set(op->ptr, "use_framerate", false);
}
- /* This is for drag and drop */
+ /* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
@@ -717,17 +668,14 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
}
sequencer_generic_invoke_xy__internal(C, op, 0, SEQ_TYPE_MOVIE);
-
sequencer_add_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multiview save options only if scene use multiview. */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
-
- // return sequencer_add_movie_strip_exec(C, op);
}
static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
@@ -737,15 +685,15 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
ImageFormatData *imf = &sad->im_format;
PointerRNA imf_ptr, ptr;
- /* main draw call */
+ /* Main draw call. */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, sequencer_add_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, &ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
- /* image template */
+ /* Image template. */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
- /* multiview template */
+ /* Multiview template. */
if (RNA_boolean_get(op->ptr, "show_multiview")) {
uiTemplateImageFormatViews(layout, &imf_ptr, op->ptr);
}
@@ -754,20 +702,19 @@ static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Movie Strip";
ot->idname = "SEQUENCER_OT_movie_strip_add";
ot->description = "Add a movie strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_movie_strip_invoke;
ot->exec = sequencer_add_movie_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -787,8 +734,6 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot)
"Use framerate from the movie to keep sound and video in sync");
}
-/* add sound operator */
-
static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
{
return sequencer_add_generic_strip_exec(C, op, BKE_sequencer_add_sound_strip);
@@ -798,7 +743,7 @@ static int sequencer_add_sound_strip_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
{
- /* This is for drag and drop */
+ /* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath")) {
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
@@ -809,25 +754,22 @@ static int sequencer_add_sound_strip_invoke(bContext *C,
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
-
- // return sequencer_add_sound_strip_exec(C, op);
}
void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Sound Strip";
ot->idname = "SEQUENCER_OT_sound_strip_add";
ot->description = "Add a sound strip to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_sound_strip_invoke;
ot->exec = sequencer_add_sound_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -854,7 +796,6 @@ int sequencer_image_seq_get_minmax_frame(wmOperator *op,
RNA_BEGIN (op->ptr, itemptr, "files") {
char *filename;
int frame;
- /* just get the first filename */
filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
if (filename) {
@@ -885,7 +826,6 @@ void sequencer_image_seq_reserve_frames(
int i;
char *filename = NULL;
RNA_BEGIN (op->ptr, itemptr, "files") {
- /* just get the first filename */
filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
break;
}
@@ -894,7 +834,7 @@ void sequencer_image_seq_reserve_frames(
if (filename) {
char ext[PATH_MAX];
char filename_stripped[PATH_MAX];
- /* strip the frame from filename and substitute with # */
+ /* Strip the frame from filename and substitute with `#`. */
BLI_path_frame_strip(filename, ext);
for (i = 0; i < len; i++, se++) {
@@ -907,23 +847,20 @@ void sequencer_image_seq_reserve_frames(
}
}
-/* add image operator */
static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
{
int minframe, numdigits;
- /* cant use the generic function for this */
- Scene *scene = CTX_data_scene(C); /* only for sound */
+ Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
Sequence *seq;
-
Strip *strip;
StripElem *se;
const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
seq_load_operator_info(&seq_load, C, op);
- /* images are unique in how they handle this - 1 per strip elem */
+ /* Images are unique in how they handle this - 1 per strip elem. */
if (use_placeholders) {
seq_load.len = sequencer_image_seq_get_minmax_frame(
op, seq_load.start_frame, &minframe, &numdigits);
@@ -941,11 +878,10 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
ED_sequencer_deselect_all(scene);
}
- /* main adding function */
+ /* Main adding function. */
seq = BKE_sequencer_add_image_strip(C, ed->seqbasep, &seq_load);
strip = seq->strip;
se = strip->stripdata;
-
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
if (use_placeholders) {
@@ -968,21 +904,18 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
}
BKE_sequence_init_colorspace(seq);
-
BKE_sequence_calc_disp(scene, seq);
-
BKE_sequencer_sort(scene);
- /* last active name */
+ /* Last active name. */
BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir));
-
sequencer_add_apply_overlap(C, op, seq);
if (op->customdata) {
MEM_freeN(op->customdata);
}
- BKE_sequence_invalidate_cache_composite(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -996,7 +929,7 @@ static int sequencer_add_image_strip_invoke(bContext *C,
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
- /* drag drop has set the names */
+ /* Name set already by drag and drop. */
if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(
C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
@@ -1004,10 +937,9 @@ static int sequencer_add_image_strip_invoke(bContext *C,
}
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_ENDFRAME, SEQ_TYPE_IMAGE);
-
sequencer_add_init(C, op);
- /* show multiview save options only if scene has multiviews */
+ /* Show multiview save options only if scene use multiview. */
prop = RNA_struct_find_property(op->ptr, "show_multiview");
RNA_property_boolean_set(op->ptr, prop, (scene->r.scemode & R_MULTIVIEW) != 0);
@@ -1018,20 +950,19 @@ static int sequencer_add_image_strip_invoke(bContext *C,
void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Image Strip";
ot->idname = "SEQUENCER_OT_image_strip_add";
ot->description = "Add an image or image sequence to the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_image_strip_invoke;
ot->exec = sequencer_add_image_strip_exec;
ot->cancel = sequencer_add_cancel;
ot->ui = sequencer_add_draw;
-
ot->poll = ED_operator_sequencer_active_editable;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -1051,65 +982,54 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot)
"Use placeholders for missing frames of the strip");
}
-/* add_effect_strip operator */
static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, true);
-
- Sequence *seq; /* generic strip vars */
+ Sequence *seq;
struct SeqEffectHandle sh;
-
- int start_frame, end_frame, channel, type; /* operator props */
-
Sequence *seq1, *seq2, *seq3;
const char *error_msg;
+ int start_frame, end_frame, channel, type;
start_frame = RNA_int_get(op->ptr, "frame_start");
end_frame = RNA_int_get(op->ptr, "frame_end");
channel = RNA_int_get(op->ptr, "channel");
-
type = RNA_enum_get(op->ptr, "type");
- // XXX move to invoke
if (!seq_effect_find_selected(scene, NULL, type, &seq1, &seq2, &seq3, &error_msg)) {
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
- /* If seq1 is NULL and no error was raised it means the seq is standalone
- * (like color strips) and we need to check its start and end frames are valid */
+ /* Check its start and end frames are valid. */
if (seq1 == NULL && end_frame <= start_frame) {
end_frame = start_frame + 1;
RNA_int_set(op->ptr, "frame_end", end_frame);
}
seq = BKE_sequence_alloc(ed->seqbasep, start_frame, channel, type);
-
BLI_strncpy(seq->name + 2, BKE_sequence_give_name(seq), sizeof(seq->name) - 2);
BKE_sequence_base_unique_name_recursive(&ed->seqbase, seq);
sh = BKE_sequence_get_effect(seq);
-
+ sh.init(seq);
seq->seq1 = seq1;
seq->seq2 = seq2;
seq->seq3 = seq3;
- sh.init(seq);
-
- if (!seq1) { /* effect has no deps */
- seq->len = 1;
+ if (!seq1) {
+ seq->len = 1; /* Effect is generator, set non zero length. */
BKE_sequence_tx_set_final_right(seq, end_frame);
}
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
-
BKE_sequence_calc(scene, seq);
if (seq->type == SEQ_TYPE_COLOR) {
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
RNA_float_get_array(op->ptr, "color", colvars->col);
- seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
+ seq->blend_mode = SEQ_TYPE_CROSS;
}
else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
seq->blend_mode = SEQ_TYPE_CROSS;
@@ -1118,8 +1038,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- /* an unset channel is a special case where we automatically go above
- * the other strips. */
+ /* Set channel. If unset, use lowest free one above strips. */
if (!RNA_struct_property_is_set(op->ptr, "channel")) {
if (seq->seq1) {
int chan = max_iii(seq->seq1 ? seq->seq1->machine : 0,
@@ -1134,20 +1053,16 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
- BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */
-
- /* not sure if this is needed with update_changed_seq_and_deps.
- * it was NOT called in blender 2.4x, but wont hurt */
+ BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* Runs BKE_sequence_calc. */
BKE_sequencer_sort(scene);
- BKE_sequence_invalidate_cache_composite(scene, seq);
+ BKE_sequence_invalidate_cache_composite(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
-/* add color */
static int sequencer_add_effect_strip_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -1159,10 +1074,8 @@ static int sequencer_add_effect_strip_invoke(bContext *C,
if (is_type_set) {
type = RNA_enum_get(op->ptr, "type");
- /* when invoking an effect strip which uses inputs,
- * skip initializing the channel from the mouse.
- * Instead leave the property unset so exec() initializes it to be
- * above the strips its applied to. */
+ /* When invoking an effect strip which uses inputs, skip initializing the channel from the
+ * mouse. */
if (BKE_sequence_effect_get_num_inputs(type) != 0) {
prop_flag |= SEQPROP_NOCHAN;
}
@@ -1177,19 +1090,18 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Add Effect Strip";
ot->idname = "SEQUENCER_OT_effect_strip_add";
ot->description = "Add an effect to the sequencer, most are applied on top of existing strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_add_effect_strip_invoke;
ot->exec = sequencer_add_effect_strip_exec;
-
ot->poll = ED_operator_sequencer_active_editable;
ot->poll_property = seq_effect_add_properties_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_enum(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index a2568e2e827..dce8aa16985 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -54,7 +54,7 @@ static bool sequencer_grease_pencil_panel_poll(const bContext *C, PanelType *UNU
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
- /* don't show the gpencil if we are not showing the image */
+ /* Don't show the gpencil if we are not showing the image. */
return ED_space_sequencer_check_show_imbuf(sseq);
}
#endif
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 0766996c00b..1f06ab68516 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -79,29 +79,26 @@
#include "MEM_guardedalloc.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
#define SEQ_LEFTHANDLE 1
#define SEQ_RIGHTHANDLE 2
-
#define SEQ_HANDLE_SIZE 8.0f
-
#define SEQ_SCROLLER_TEXT_OFFSET 8
-
#define MUTE_ALPHA 120
/* Note, Don't use SEQ_BEGIN/SEQ_END while drawing!
- * it messes up transform, - Campbell */
+ * it messes up transform. */
#undef SEQ_BEGIN
#undef SEQP_BEGIN
#undef SEQ_END
static Sequence *special_seq_update = NULL;
-void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
+void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3])
{
- unsigned char blendcol[3];
+ uchar blendcol[3];
switch (seq->type) {
case SEQ_TYPE_IMAGE:
@@ -141,7 +138,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
col[2] = 130;
break;
- /* effects */
+ /* Effects. */
case SEQ_TYPE_TRANSFORM:
case SEQ_TYPE_SPEED:
case SEQ_TYPE_ADD:
@@ -223,6 +220,10 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3])
}
}
+/**
+ * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2.
+ * \param stepsize: The width of a pixel.
+ */
static void draw_seq_waveform(View2D *v2d,
const bContext *C,
SpaceSeq *sseq,
@@ -234,13 +235,7 @@ static void draw_seq_waveform(View2D *v2d,
float y2,
float stepsize)
{
- /*
- * x1 is the starting x value to draw the wave,
- * x2 the end x value, same for y1 and y2
- * stepsize is width of a pixel.
- */
-
- /* offset x1 and x2 values, to match view min/max, if strip is out of bounds */
+ /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */
int x1_offset = max_ff(v2d->cur.xmin, x1);
int x2_offset = min_ff(v2d->cur.xmax + 1.0f, x2);
@@ -254,8 +249,6 @@ static void draw_seq_waveform(View2D *v2d,
float volume = seq->volume;
float value1, value2;
bSound *sound = seq->sound;
- FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
-
SoundWaveform *waveform;
if (length < 2) {
@@ -265,7 +258,7 @@ static void draw_seq_waveform(View2D *v2d,
BLI_spin_lock(sound->spinlock);
if (!sound->waveform) {
if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {
- /* prevent sounds from reloading */
+ /* Prevent sounds from reloading. */
sound->tags |= SOUND_TAGS_WAVEFORM_LOADING;
BLI_spin_unlock(sound->spinlock);
sequencer_preview_add_sound(C, seq);
@@ -273,15 +266,14 @@ static void draw_seq_waveform(View2D *v2d,
else {
BLI_spin_unlock(sound->spinlock);
}
- return; /* nothing to draw */
+ return; /* Nothing to draw. */
}
BLI_spin_unlock(sound->spinlock);
waveform = sound->waveform;
+ /* Waveform could not be built. */
if (waveform->length == 0) {
- /* BKE_sound_read_waveform() set an empty SoundWaveform data in case it cannot generate a
- * valid one. See T45726. */
return;
}
@@ -299,6 +291,9 @@ static void draw_seq_waveform(View2D *v2d,
return;
}
+ /* Fcurve lookup is quite expensive, so do this after precondition. */
+ FCurve *fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+
GPU_blend(true);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -325,7 +320,7 @@ static void draw_seq_waveform(View2D *v2d,
}
}
else if (p + 1 < waveform->length) {
- /* use simple linear interpolation */
+ /* Use simple linear interpolation. */
float f = sampleoffset - p;
value1 = (1.0f - f) * value1 + f * waveform->data[p * 3 + 3];
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
@@ -361,12 +356,10 @@ static void draw_seq_waveform(View2D *v2d,
static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2)
{
- /* note: this used to use SEQ_BEGIN/SEQ_END, but it messes up the
- * seq->depth value, (needed by transform when doing overlap checks)
- * so for now, just use the meta's immediate children, could be fixed but
- * its only drawing - campbell */
+ /* Don't use SEQ_BEGIN/SEQ_END here,
+ * because it changes seq->depth, which is needed for transform. */
Sequence *seq;
- unsigned char col[4];
+ uchar col[4];
int chan_min = MAXSEQ;
int chan_max = 0;
@@ -400,12 +393,12 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
chan_range = (chan_max - chan_min) + 1;
draw_height = draw_range / chan_range;
- col[3] = 196; /* alpha, used for all meta children */
+ 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);
+ /* Draw only immediate children (1 level depth). */
for (seq = seqbase->first; seq; seq = seq->next) {
const int startdisp = seq->startdisp + offset;
const int enddisp = seq->enddisp + offset;
@@ -433,7 +426,7 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
immUniformColor4ubv(col);
- /* clamp within parent sequence strip bounds */
+ /* Clamp within parent sequence strip bounds. */
if (x1_chan < x1) {
x1_chan = x1;
}
@@ -453,29 +446,29 @@ static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1,
GPU_blend(false);
}
-/* clamp handles to defined size in pixel space */
+/* Get handle width in pixels. */
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
{
const float maxhandle = (pixelx * SEQ_HANDLE_SIZE) * U.pixelsize;
- /* ensure we're not greater than half width */
+ /* Ensure that handle is not wider, than half of strip. */
return min_ff(maxhandle, ((float)(seq->enddisp - seq->startdisp) / 2.0f) / pixelx);
}
-/* draw a handle, for each end of a sequence strip */
+/* Draw a handle, on left or right side of strip. */
static void draw_seq_handle(View2D *v2d,
Sequence *seq,
const float handsize_clamped,
const short direction,
- unsigned int pos,
+ uint pos,
bool seq_active,
float pixelx,
bool y_threshold)
{
float rx1 = 0, rx2 = 0;
float x1, x2, y1, y2;
- unsigned int whichsel = 0;
- unsigned char col[4];
+ uint whichsel = 0;
+ uchar col[4];
x1 = seq->startdisp;
x2 = seq->enddisp;
@@ -483,7 +476,7 @@ static void draw_seq_handle(View2D *v2d,
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
- /* set up co-ordinates/dimensions for either left or right handle */
+ /* Set up co-ordinates and dimensions for either left or right handle. */
if (direction == SEQ_LEFTHANDLE) {
rx1 = x1;
rx2 = x1 + handsize_clamped;
@@ -495,7 +488,6 @@ static void draw_seq_handle(View2D *v2d,
whichsel = SEQ_RIGHTSEL;
}
- /* draw! */
if (!(seq->type & SEQ_TYPE_EFFECT) || BKE_sequence_effect_get_num_inputs(seq->type) == 0) {
GPU_blend(true);
@@ -522,9 +514,7 @@ static void draw_seq_handle(View2D *v2d,
GPU_blend(false);
}
- /* Draw numbers for start and end of the strip next to its handles.
- * - Draw only when handles are selected or while translating the strip.
- */
+ /* Draw numbers for start and end of the strip next to its handles. */
if (y_threshold &&
(((seq->flag & SELECT) && (G.moving & G_TRANSFORM_SEQ)) || (seq->flag & whichsel))) {
@@ -557,7 +547,7 @@ static void draw_seq_handle(View2D *v2d,
}
static void draw_seq_outline(Sequence *seq,
- unsigned int pos,
+ uint pos,
float x1,
float x2,
float y1,
@@ -566,7 +556,7 @@ static void draw_seq_outline(Sequence *seq,
float pixely,
bool seq_active)
{
- unsigned char col[3];
+ uchar col[3];
/* Get the color for the outline. */
if (seq_active && (seq->flag & SELECT)) {
@@ -575,8 +565,8 @@ static void draw_seq_outline(Sequence *seq,
else if (seq->flag & SELECT) {
UI_GetThemeColor3ubv(TH_SEQ_SELECTED, col);
}
- /* Regular color for unselected strips: a bit darker than the background. */
else {
+ /* Color for unselected strips is a bit darker than the background. */
UI_GetThemeColor3ubv(TH_BACK, col);
UI_GetColorPtrShade3ubv(col, col, -40);
}
@@ -610,13 +600,13 @@ static void draw_seq_outline(Sequence *seq,
/* Top */
immRectf(pos, x1 - pixelx, y2 - 2 * pixely, x2 + pixelx, y2);
}
- /* 1px wide outline for unselected strips. */
else {
+ /* 1px wide outline for unselected strips. */
imm_draw_box_wire_2d(pos, x1, y1, x2, y2);
}
}
-/* draw info text on a sequence strip */
+/* Draw info text on a sequence strip. */
static void draw_seq_text(View2D *v2d,
Sequence *seq,
SpaceSeq *sseq,
@@ -633,7 +623,7 @@ static void draw_seq_text(View2D *v2d,
const char *name = seq->name + 2;
uchar col[4];
- /* note, all strings should include 'name' */
+ /* All strings should include name. */
if (name[0] == '\0') {
name = BKE_sequence_give_name(seq);
}
@@ -723,7 +713,7 @@ static void draw_seq_text(View2D *v2d,
seq->len);
}
else {
- /* should never get here!, but might with files from future */
+ /* Should never get here!, but might with files from future. */
BLI_assert(0);
str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len);
@@ -751,10 +741,10 @@ static void draw_seq_text(View2D *v2d,
UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col);
}
-static void draw_sequence_extensions(Scene *scene, Sequence *seq, unsigned int pos, float pixely)
+static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely)
{
float x1, x2, y1, y2;
- unsigned char col[4], blend_col[3];
+ uchar col[4], blend_col[3];
x1 = seq->startdisp;
x2 = seq->enddisp;
@@ -793,9 +783,9 @@ static void draw_sequence_extensions(Scene *scene, Sequence *seq, unsigned int p
GPU_blend(false);
}
-static void draw_color_strip_band(Sequence *seq, unsigned int pos, float text_margin_y, float y1)
+static void draw_color_strip_band(Sequence *seq, uint pos, float text_margin_y, float y1)
{
- unsigned char col[4];
+ uchar col[4];
SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
rgb_float_to_uchar(col, colvars->col);
@@ -827,14 +817,14 @@ static void draw_color_strip_band(Sequence *seq, unsigned int pos, float text_ma
static void draw_seq_background(Scene *scene,
Sequence *seq,
- unsigned int pos,
+ uint pos,
float x1,
float x2,
float y1,
float y2,
bool is_single_image)
{
- unsigned char col[4];
+ uchar col[4];
/* Get the correct color per strip type, transitions use their inputs ones. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
@@ -888,7 +878,7 @@ static void draw_seq_background(Scene *scene,
}
}
- /* Transition strips.. Draw right half. */
+ /* Draw right half of transition strips. */
if (ELEM(seq->type, SEQ_TYPE_CROSS, SEQ_TYPE_GAMCROSS, SEQ_TYPE_WIPE)) {
float vert_pos[3][2];
Sequence *seq1 = seq->seq1;
@@ -966,7 +956,7 @@ static void calculate_seq_text_offsets(
float scroller_vert_xoffs = (V2D_SCROLL_HANDLE_WIDTH + SEQ_SCROLLER_TEXT_OFFSET) * pixelx;
- /* info text on the strip */
+ /* Info text on the strip. */
if (*x1 < v2d->cur.xmin + scroller_vert_xoffs) {
*x1 = v2d->cur.xmin + scroller_vert_xoffs;
}
@@ -981,11 +971,102 @@ static void calculate_seq_text_offsets(
}
}
-/*
- * Draw a sequence strip, bounds check already made
- * ARegion is currently only used to get the windows width in pixels
- * so wave file sample drawing precision is zoom adjusted
+static void fcurve_batch_add_verts(GPUVertBuf *vbo,
+ float y1,
+ float y2,
+ float y_height,
+ int cfra,
+ float curve_val,
+ unsigned int *vert_count)
+{
+ float vert_pos[2][2];
+
+ copy_v2_fl2(vert_pos[0], cfra, (curve_val * y_height) + y1);
+ copy_v2_fl2(vert_pos[1], cfra, y2);
+
+ GPU_vertbuf_vert_set(vbo, *vert_count, vert_pos[0]);
+ GPU_vertbuf_vert_set(vbo, *vert_count + 1, vert_pos[1]);
+ *vert_count += 2;
+}
+
+/**
+ * Draw f-curves as darkened regions of the strip:
+ * - Volume for sound strips.
+ * - Opacity for the other types.
*/
+static void draw_seq_fcurve(
+ Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx)
+{
+ FCurve *fcu;
+
+ if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, NULL);
+ }
+ else {
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "blend_alpha", 0, NULL);
+ }
+
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
+
+ /* Clamp curve evaluation to the editor's borders. */
+ int eval_start = max_ff(x1, v2d->cur.xmin);
+ int eval_end = min_ff(x2, v2d->cur.xmax + 1);
+
+ int eval_step = max_ii(1, floor(pixelx));
+
+ if (eval_start >= eval_end) {
+ return;
+ }
+
+ GPUVertFormat format = {0};
+ GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
+
+ uint max_verts = 2 * ((eval_end - eval_start) / eval_step + 1);
+ GPU_vertbuf_data_alloc(vbo, max_verts);
+ uint vert_count = 0;
+
+ const float y_height = y2 - y1;
+ float curve_val;
+ float prev_val = INT_MIN;
+ bool skip = false;
+
+ for (int cfra = eval_start; cfra <= eval_end; cfra += eval_step) {
+ curve_val = evaluate_fcurve(fcu, cfra);
+ CLAMP(curve_val, 0.0f, 1.0f);
+
+ /* Avoid adding adjacent verts that have the same value. */
+ if (curve_val == prev_val && cfra < eval_end - eval_step) {
+ skip = true;
+ continue;
+ }
+
+ /* If some frames were skipped above, we need to close the shape. */
+ if (skip) {
+ fcurve_batch_add_verts(vbo, y1, y2, y_height, cfra - eval_step, prev_val, &vert_count);
+ skip = false;
+ }
+
+ fcurve_batch_add_verts(vbo, y1, y2, y_height, cfra, curve_val, &vert_count);
+ prev_val = curve_val;
+ }
+
+ 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_uniform_4f(batch, "color", 0.0f, 0.0f, 0.0f, 0.15f);
+ GPU_blend(true);
+
+ if (vert_count > 0) {
+ GPU_batch_draw(batch);
+ }
+
+ GPU_blend(false);
+ GPU_batch_discard(batch);
+ }
+}
+
+/* Draw visible strips. Bounds check are already made. */
static void draw_seq_strip(const bContext *C,
SpaceSeq *sseq,
Scene *scene,
@@ -999,20 +1080,19 @@ static void draw_seq_strip(const bContext *C,
const float handsize_clamped = sequence_handle_size_get_clamped(seq, pixelx);
float pixely = BLI_rctf_size_y(&v2d->cur) / BLI_rcti_size_y(&v2d->mask);
- /* We need to know if this is a single image/color or not for drawing. */
+ /* Check if we are doing "solo preview". */
bool is_single_image = (char)BKE_sequence_single_check(seq);
- /* body */
+ /* Draw strip body. */
x1 = (seq->startstill) ? seq->start : seq->startdisp;
y1 = seq->machine + SEQ_STRIP_OFSBOTTOM;
x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp;
y2 = seq->machine + SEQ_STRIP_OFSTOP;
- /* Position of the text,
- * make sure that the strip content is visible also when the strip height gets lower. */
+ /* Calculate height needed for drawing text on strip. */
float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely);
- /* Show some content only when the strip is high enough. */
+ /* Is there enough space for drawing something else than text? */
bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac;
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1020,12 +1100,12 @@ static void draw_seq_strip(const bContext *C,
draw_seq_background(scene, seq, pos, x1, x2, y1, y2, is_single_image);
- /* Color strips.. Draw a band with the strip's color on its lower part. */
+ /* Draw a color band inside color strip. */
if (seq->type == SEQ_TYPE_COLOR && y_threshold) {
draw_color_strip_band(seq, pos, text_margin_y, y1);
}
- /* Draw strip's offsets when flag is enabled or during "solo preview". */
+ /* Draw strip offsets when flag is enabled or during "solo preview". */
if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) {
if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) {
draw_sequence_extensions(scene, seq, pos, pixely);
@@ -1042,7 +1122,11 @@ static void draw_seq_strip(const bContext *C,
drawmeta_contents(scene, seq, x1, y1, x2, y2);
}
- /* Sound strips.. Draw waveforms. */
+ if (sseq->flag & SEQ_SHOW_FCURVES) {
+ draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx);
+ }
+
+ /* Draw sound strip waveform. */
if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) {
draw_seq_waveform(v2d,
C,
@@ -1061,7 +1145,7 @@ static void draw_seq_strip(const bContext *C,
draw_seq_locked(x1, y1, x2, y2);
}
- /* Missing media indication.. Draw a red line on the top of the strip. */
+ /* Draw Red line on the top of invalid strip (Missing media). */
if (!BKE_sequence_is_valid_check(seq)) {
draw_seq_invalid(x1, x2, y2, text_margin_y);
}
@@ -1082,11 +1166,9 @@ static void draw_seq_strip(const bContext *C,
calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx);
- /* Draw the text on the top section of the strip,
- * - depending on the vertical space, move it to the center or don't draw it.
- * - don't draw it when there is not enough horizontal space.
- */
+ /* Don't draw strip if there is not enough vertical or horizontal space. */
if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) {
+ /* Depending on the vertical space, draw text on top or in the center of strip. */
draw_seq_text(
v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold);
}
@@ -1203,7 +1285,7 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain,
GPU_framebuffer_bind(fb);
}
- /* restore state so real rendering would be canceled (if needed) */
+ /* Restore state so real rendering would be canceled if needed. */
G.is_break = is_break;
return ibuf;
@@ -1239,7 +1321,7 @@ static void sequencer_check_scopes(SequencerScopes *scopes, ImBuf *ibuf)
}
}
-static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_cb)(ImBuf *ibuf))
+static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scope_fn)(ImBuf *ibuf))
{
ImBuf *display_ibuf = IMB_dupImBuf(ibuf);
ImBuf *scope;
@@ -1247,7 +1329,7 @@ static ImBuf *sequencer_make_scope(Scene *scene, ImBuf *ibuf, ImBuf *(*make_scop
IMB_colormanagement_imbuf_make_display_space(
display_ibuf, &scene->view_settings, &scene->display_settings);
- scope = make_scope_cb(display_ibuf);
+ scope = make_scope_fn(display_ibuf);
IMB_freeImBuf(display_ibuf);
@@ -1264,17 +1346,17 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2])
static void sequencer_draw_gpencil(const bContext *C)
{
- /* draw grease-pencil (image aligned) */
+ /* Draw grease-pencil (image aligned). */
ED_annotation_draw_2dimage(C);
- /* ortho at pixel level */
+ /* Ortho at pixel level. */
UI_view2d_view_restore(C);
- /* draw grease-pencil (screen aligned) */
+ /* Draw grease-pencil (screen aligned). */
ED_annotation_draw_view2d(C, 0);
}
-/* draws content borders plus safety borders if needed */
+/* Draw content and safety borders borders. */
static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene)
{
float x1 = v2d->tot.xmin;
@@ -1284,7 +1366,7 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
GPU_line_width(1.0f);
- /* border */
+ /* Draw border. */
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -1301,7 +1383,7 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
imm_draw_box_wire_2d(shdr_pos, x1 - 0.5f, y1 - 0.5f, x2 + 0.5f, y2 + 0.5f);
- /* safety border */
+ /* Draw safety border. */
if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
immUniformThemeColorBlend(TH_VIEW_OVERLAY, TH_BACK, 0.25f);
@@ -1325,8 +1407,8 @@ static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, cons
#if 0
void sequencer_draw_maskedit(const bContext *C, Scene *scene, ARegion *region, SpaceSeq *sseq)
{
- /* NOTE: sequencer mask editing isnt finished, the draw code is working but editing not,
- * for now just disable drawing since the strip frame will likely be offset */
+ /* NOTE: sequencer mask editing isnt finished, the draw code is working but editing not.
+ * For now just disable drawing since the strip frame will likely be offset. */
// if (sc->mode == SC_MODE_MASKEDIT)
if (0 && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
@@ -1377,8 +1459,8 @@ static void *sequencer_OCIO_transform_ibuf(
force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL);
force_fallback |= (ibuf->dither != 0.0f);
+ /* Fallback to CPU based color space conversion. */
if (force_fallback) {
- /* Fallback to CPU based color space conversion */
*r_glsl_used = false;
*r_format = GL_RGBA;
*r_type = GL_UNSIGNED_BYTE;
@@ -1423,9 +1505,8 @@ static void *sequencer_OCIO_transform_ibuf(
display_buffer = NULL;
}
- /* there's a data to be displayed, but GLSL is not initialized
- * properly, in this case we fallback to CPU-based display transform
- */
+ /* There is data to be displayed, but GLSL is not initialized
+ * properly, in this case we fallback to CPU-based display transform. */
if ((ibuf->rect || ibuf->rect_float) && !*r_glsl_used) {
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
*r_format = GL_RGBA;
@@ -1441,14 +1522,12 @@ static void *sequencer_OCIO_transform_ibuf(
static void sequencer_stop_running_jobs(const bContext *C, Scene *scene)
{
if (G.is_rendering == false && (scene->r.seq_prev_type) == OB_RENDER) {
- /* stop all running jobs, except screen one. currently previews frustrate Render
- * needed to make so sequencer's rendering doesn't conflict with compositor
- */
+ /* Stop all running jobs, except screen one. Currently previews frustrate Render.
+ * Need to make so sequencer's rendering doesn't conflict with compositor. */
WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_COMPOSITE);
- /* in case of final rendering used for preview, kill all previews,
- * otherwise threading conflict will happen in rendering module
- */
+ /* In case of final rendering used for preview, kill all previews,
+ * otherwise threading conflict will happen in rendering module. */
WM_jobs_kill_type(CTX_wm_manager(C), NULL, WM_JOB_TYPE_RENDER_PREVIEW);
}
}
@@ -1521,8 +1600,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
}
/* Format needs to be created prior to any immBindProgram call.
- * Do it here because OCIO binds it's own shader.
- */
+ * Do it here because OCIO binds it's own shader. */
int format, type;
bool glsl_used = false;
GLuint texid;
@@ -1538,7 +1616,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
IMB_rect_from_float(ibuf);
}
- display_buffer = (unsigned char *)ibuf->rect;
+ display_buffer = (uchar *)ibuf->rect;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
}
@@ -1671,7 +1749,7 @@ static ImBuf *sequencer_get_scope(Scene *scene, SpaceSeq *sseq, ImBuf *ibuf, boo
break;
}
- /* future files may have new scopes we don't catch above */
+ /* Future files may have new scopes we don't catch above. */
if (scope) {
scopes->reference_ibuf = ibuf;
}
@@ -1708,13 +1786,13 @@ void sequencer_draw_preview(const bContext *C,
return;
}
- /* Setup view */
+ /* Setup view. */
sequencer_display_size(scene, viewrect);
UI_view2d_totRect_set(v2d, viewrect[0] + 0.5f, viewrect[1] + 0.5f);
UI_view2d_curRect_validate(v2d);
UI_view2d_view_ortho(v2d);
- /* Draw background */
+ /* Draw background. */
if (!draw_backdrop && (!draw_overlay || sseq->overlay_type == SEQ_DRAW_OVERLAY_REFERENCE)) {
sequencer_preview_clear();
@@ -1722,18 +1800,18 @@ void sequencer_draw_preview(const bContext *C,
imm_draw_box_checker_2d(v2d->tot.xmin, v2d->tot.ymin, v2d->tot.xmax, v2d->tot.ymax);
}
}
- /* Get image */
+ /* Get image. */
ibuf = sequencer_ibuf_get(
bmain, depsgraph, scene, sseq, cfra, frame_ofs, names[sseq->multiview_eye]);
if (ibuf) {
scope = sequencer_get_scope(scene, sseq, ibuf, draw_backdrop);
- /* Draw image */
+ /* Draw image. */
sequencer_draw_display_buffer(
C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop);
- /* Draw over image */
+ /* Draw over image. */
if (sseq->flag & SEQ_SHOW_METADATA) {
ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0);
}
@@ -1746,12 +1824,11 @@ void sequencer_draw_preview(const bContext *C,
if (draw_gpencil && show_imbuf) {
sequencer_draw_gpencil(C);
}
+#if 0
+ sequencer_draw_maskedit(C, scene, region, sseq);
+#endif
- /* TODO */
- /* sequencer_draw_maskedit(C, scene, region, sseq); */
-
- /* Scope is freed in sequencer_check_scopes when ibuf changes and
- * scope image is to be replaced. */
+ /* Scope is freed in sequencer_check_scopes when ibuf changes and redraw is needed. */
if (ibuf) {
IMB_freeImBuf(ibuf);
}
@@ -1760,7 +1837,7 @@ void sequencer_draw_preview(const bContext *C,
seq_prefetch_wm_notify(C, scene);
}
-/* draw backdrop of the sequencer strips view */
+/* Draw backdrop in sequencer timeline. */
static void draw_seq_backdrop(View2D *v2d)
{
int i;
@@ -1768,11 +1845,11 @@ static void draw_seq_backdrop(View2D *v2d)
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* darker gray overlay over the view backdrop */
+ /* Darker gray overlay over the view backdrop. */
immUniformThemeColorShade(TH_BACK, -20);
immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0);
- /* Alternating horizontal stripes */
+ /* Alternating horizontal stripes. */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
while (i < v2d->cur.ymax) {
@@ -1788,7 +1865,7 @@ static void draw_seq_backdrop(View2D *v2d)
i++;
}
- /* Darker lines separating the horizontal bands */
+ /* Darker lines separating the horizontal bands. */
i = max_ii(1, ((int)v2d->cur.ymin) - 1);
int line_len = (int)v2d->cur.ymax - i + 1;
immUniformThemeColor(TH_GRID);
@@ -1802,7 +1879,6 @@ static void draw_seq_backdrop(View2D *v2d)
immUnbindProgram();
}
-/* draw the contents of the sequencer strips view */
static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -1812,12 +1888,12 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
int sel = 0, j;
float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
- /* loop through twice, first unselected, then selected */
+ /* Loop through twice, first unselected, then selected. */
for (j = 0; j < 2; j++) {
Sequence *seq;
- /* loop through strips, checking for those that are visible */
+ /* Loop through strips, checking for those that are visible. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- /* boundbox and selection tests for NOT drawing the strip... */
+ /* Boundbox and selection tests for NOT drawing the strip. */
if ((seq->flag & SELECT) != sel) {
continue;
}
@@ -1837,11 +1913,11 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
continue;
}
- /* strip passed all tests unscathed... so draw it now */
+ /* Strip passed all tests, draw it now. */
draw_seq_strip(C, sseq, scene, region, seq, pixelx, seq == last_seq ? true : false);
}
- /* draw selected next time round */
+ /* Draw selected next time round. */
sel = SELECT;
}
@@ -1872,7 +1948,7 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region)
}
}
- /* draw highlight when previewing a single strip */
+ /* Draw highlight if "solo preview" is used. */
if (special_seq_update) {
const Sequence *seq = special_seq_update;
GPU_blend(true);
@@ -1904,8 +1980,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* draw darkened area outside of active timeline
- * frame range used is preview range or scene range */
+ /* Draw overlay outside of frame range. */
immUniformThemeColorShadeAlpha(TH_BACK, -25, -100);
if (frame_sta < frame_end) {
@@ -1918,7 +1993,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
immUniformThemeColorShade(TH_BACK, -60);
- /* thin lines where the actual frames are */
+ /* Draw frame range boundary. */
immBegin(GPU_PRIM_LINES, 4);
immVertex2f(pos, frame_sta, v2d->cur.ymin);
@@ -1929,7 +2004,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
immEnd();
- /* While inside a meta strip, draw a checkerboard pattern outside of its range. */
+ /* While in meta strip, draw a checkerboard overlay outside of frame range. */
if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
MetaStack *ms = ed->metastack.last;
immUnbindProgram();
@@ -1979,8 +2054,8 @@ typedef struct CacheDrawData {
size_t final_out_vert_count;
} CacheDrawData;
-/* Called as a callback */
-static bool draw_cache_view_init_cb(void *userdata, size_t item_count)
+/* Called as a callback. */
+static bool draw_cache_view_init_fn(void *userdata, size_t item_count)
{
if (item_count == 0) {
return true;
@@ -1998,7 +2073,7 @@ static bool draw_cache_view_init_cb(void *userdata, size_t item_count)
}
/* Called as a callback */
-static bool draw_cache_view_iter_cb(
+static bool draw_cache_view_iter_fn(
void *userdata, struct Sequence *seq, int nfra, int cache_type, float UNUSED(cost))
{
CacheDrawData *drawdata = userdata;
@@ -2162,7 +2237,7 @@ static void draw_cache_view(const bContext *C)
userdata.composite_vbo = GPU_vertbuf_create_with_format(&format);
userdata.final_out_vbo = GPU_vertbuf_create_with_format(&format);
- BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_cb, draw_cache_view_iter_cb);
+ BKE_sequencer_cache_iterate(scene, &userdata, draw_cache_view_init_fn, draw_cache_view_iter_fn);
draw_cache_view_batch(userdata.raw_vbo, userdata.raw_vert_count, 1.0f, 0.1f, 0.02f, 0.4f);
draw_cache_view_batch(
@@ -2175,7 +2250,7 @@ static void draw_cache_view(const bContext *C)
GPU_blend(false);
}
-/* Draw Timeline/Strip Editor Mode for Sequencer */
+/* Draw sequencer timeline. */
void draw_timeline_seq(const bContext *C, ARegion *region)
{
Scene *scene = CTX_data_scene(C);
@@ -2188,7 +2263,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
seq_prefetch_wm_notify(C, scene);
- /* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
if (ed && ed->metastack.first) {
GPU_clear_color(col[0], col[1], col[2] - 0.1f, 0.0f);
@@ -2199,44 +2273,36 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
GPU_clear(GPU_COLOR_BIT);
UI_view2d_view_ortho(v2d);
-
- /* calculate extents of sequencer strips/data
- * NOTE: needed for the scrollers later
- */
+ /* Get timeline boundbox, needed for the scrollers. */
boundbox_seq(scene, &v2d->tot);
-
- /* draw backdrop */
draw_seq_backdrop(v2d);
-
- /* regular grid-pattern over the rest of the view (i.e. 1-second grid lines) */
UI_view2d_constant_grid_draw(v2d, FPS);
- /* Only draw backdrop in pure sequence view. */
+ /* Only draw backdrop in timeline view. */
if (sseq->view == SEQ_VIEW_SEQUENCE && sseq->draw_flag & SEQ_DRAW_BACKDROP) {
sequencer_draw_preview(C, scene, region, sseq, scene->r.cfra, 0, false, true);
UI_view2d_view_ortho(v2d);
}
+ /* Draw attached callbacks. */
ED_region_draw_cb_draw(C, region, REGION_DRAW_PRE_VIEW);
-
seq_draw_sfra_efra(scene, v2d);
- /* sequence strips (if there is data available to be drawn) */
if (ed) {
- /* draw the data */
draw_seq_strips(C, ed, region);
- /* text draw cached (for sequence names), in pixelspace now */
+ /* Draw text added in previous function. */
UI_view2d_text_cache_draw(region);
}
- /* current frame */
UI_view2d_view_ortho(v2d);
if ((sseq->flag & SEQ_DRAWFRAMES) == 0) {
cfra_flag |= DRAWCFRA_UNIT_SECONDS;
}
+
+ /* Draw the current frame indicator. */
ANIM_draw_cfra(C, v2d, cfra_flag);
- /* overlap playhead */
+ /* Draw overlap frame frame indicator. */
if (scene->ed && scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) {
int cfra_over = (scene->ed->over_flag & SEQ_EDIT_OVERLAY_ABS) ?
scene->ed->over_cfra :
@@ -2247,7 +2313,8 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1i("colors_len", 0); /* "simple" mode */
+ /* Shader may have color set from past usage - reset it. */
+ immUniform1i("colors_len", 0);
immUniform1f("dash_width", 20.0f * U.pixelsize);
immUniform1f("dash_factor", 0.5f);
immUniformThemeColor(TH_CFRAME);
@@ -2260,7 +2327,6 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
immUnbindProgram();
}
- /* markers */
UI_view2d_view_orthoSpecial(region, v2d, 1);
int marker_draw_flag = DRAW_MARKERS_MARGIN;
if (sseq->flag & SEQ_SHOW_MARKERS) {
@@ -2268,28 +2334,22 @@ void draw_timeline_seq(const bContext *C, ARegion *region)
}
UI_view2d_view_ortho(v2d);
- /* draw cache on top of markers area */
+
if (ed) {
draw_cache_view(C);
}
- /* preview range */
+
ANIM_draw_previewrange(C, v2d, 1);
- /* callback */
+ /* Draw registered callbacks. */
ED_region_draw_cb_draw(C, region, REGION_DRAW_POST_VIEW);
-
- /* reset view matrix */
UI_view2d_view_restore(C);
-
- /* scrubbing region */
ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true);
-
- /* scrollers */
scrollers = UI_view2d_scrollers_calc(v2d, NULL);
UI_view2d_scrollers_draw(v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
- /* channel numbers */
+ /* Draw channel numbers. */
{
rcti rect;
BLI_rcti_init(
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 71e63547eae..ea0d5785d22 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -52,10 +52,11 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* for menu/popup icons etc etc*/
+/* For menu, popup, icons, etc. */
#include "ED_anim_api.h"
#include "ED_numinput.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_sequencer.h"
#include "ED_space_api.h"
@@ -67,11 +68,11 @@
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/* XXX */
-/* RNA Enums, used in multiple files */
+/* RNA Enums, used in multiple files. */
EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
{SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
@@ -94,8 +95,6 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{0, NULL, 0, NULL, NULL},
};
-/* mute operator */
-
#define SEQ_SIDE_MOUSE -1
EnumPropertyItem prop_side_types[] = {
@@ -144,7 +143,7 @@ static void proxy_freejob(void *pjv)
MEM_freeN(pj);
}
-/* only this runs inside thread */
+/* Only this runs inside thread. */
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
{
ProxyJob *pj = pjv;
@@ -185,7 +184,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Sequence *seq;
GSet *file_list;
@@ -215,25 +214,46 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports)
}
file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+ bool selected = false; /* Check for no selected strips */
+
SEQP_BEGIN (ed, seq) {
- if ((seq->flag & SELECT)) {
- bool success = BKE_sequencer_proxy_rebuild_context(
- pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
- if (!success) {
- BKE_reportf(reports, RPT_ERROR, "Could not build proxy for strip %s", seq->name);
- }
+ if (!ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META) ||
+ (seq->flag & SELECT) == 0) {
+ continue;
+ }
+
+ selected = true;
+ if (!(seq->flag & SEQ_USE_PROXY)) {
+ BKE_reportf(reports, RPT_WARNING, "Proxy is not enabled for %s, skipping.", seq->name);
+ continue;
+ }
+ else if (seq->strip->proxy->build_size_flags == 0) {
+ BKE_reportf(reports, RPT_WARNING, "Resolution is not selected for %s, skipping.", seq->name);
+ continue;
+ }
+
+ bool success = BKE_sequencer_proxy_rebuild_context(
+ pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+
+ if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) {
+ BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping.", seq->name);
}
}
SEQ_END;
+ if (!selected) {
+ BKE_reportf(reports, RPT_WARNING, "Select movie or image strips.");
+ return;
+ }
+
BLI_gset_free(file_list, MEM_freeN);
- if (!WM_jobs_is_running(wm_job)) {
+ if (selected && !WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/* ********************************************************************** */
@@ -256,7 +276,7 @@ void boundbox_seq(Scene *scene, rctf *rect)
return;
}
- min[0] = 0.0;
+ min[0] = SFRA;
max[0] = EFRA + 1;
min[1] = 0.0;
max[1] = 8.0;
@@ -291,7 +311,7 @@ static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
mval[0] = mouse_x;
mval[1] = 0;
- /* choose the side based on which side of the playhead the mouse is on */
+ /* Choose the side based on which side of the current frame the mouse is on. */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
@@ -299,7 +319,7 @@ static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
{
- /* sel - 0==unselected, 1==selected, -1==done care*/
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -334,7 +354,7 @@ Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int se
static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
{
- /* sel - 0==unselected, 1==selected, -1==done care*/
+ /* sel: 0==unselected, 1==selected, -1==don't care. */
Sequence *seq, *best_seq = NULL;
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -375,7 +395,7 @@ static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, i
}
seq = seq->next;
}
- return best_seq; /* can be null */
+ return best_seq; /* Can be null. */
}
Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
@@ -400,22 +420,21 @@ 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 */
+ /* Check for both normal strips, and strips that have been flipped horizontally. */
if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
if (BKE_sequence_tx_test(seq)) {
- /* clamp handles to defined size in pixel space */
-
+ /* Clamp handles to defined size in pixel space. */
handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
displen = (float)abs(seq->startdisp - seq->enddisp);
- /* don't even try to grab the handles of small strips */
+ /* Don't even try to grab the handles of small strips. */
if (displen / pixelx > 16) {
+
/* Set the max value to handle to 1/3 of the total len when its
* less than 28. This is important because otherwise selecting
* handles happens even when you click in the middle. */
-
if ((displen / 3) < 30 * pixelx) {
handsize = displen / 3;
}
@@ -510,7 +529,6 @@ void recurs_sel_seq(Sequence *seqm)
bool ED_space_sequencer_maskedit_mask_poll(bContext *C)
{
- /* in this case both funcs are the same, for clip editor not */
return ED_space_sequencer_maskedit_poll(C);
}
@@ -535,7 +553,7 @@ bool ED_space_sequencer_maskedit_poll(bContext *C)
return false;
}
-/* are we displaying the seq output (not channels or histogram)*/
+/* Are we displaying the seq output (not channels or histogram). */
bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
{
return (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW) &&
@@ -589,8 +607,8 @@ int seq_effect_find_selected(Scene *scene,
}
}
- /* make sequence selection a little bit more intuitive
- * for 3 strips: the last-strip should be sequence3 */
+ /* Make sequence selection a little bit more intuitive
+ * for 3 strips: the last-strip should be seq3. */
if (seq3 != NULL && seq2 != NULL) {
Sequence *tmp = seq2;
seq2 = seq3;
@@ -600,7 +618,7 @@ int seq_effect_find_selected(Scene *scene,
switch (BKE_sequence_effect_get_num_inputs(type)) {
case 0:
*r_selseq1 = *r_selseq2 = *r_selseq3 = NULL;
- return 1; /* success */
+ return 1; /* Success. */
case 1:
if (seq2 == NULL) {
*r_error_str = N_("At least one selected sequence strip is needed");
@@ -640,8 +658,8 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
{
Sequence *seq1, *seq2, *seq3;
- /* try to find a replacement input sequence, and flag for later deletion if
- * no replacement can be found */
+ /* Try to find a replacement input sequence, and flag for later deletion if
+ * no replacement can be found. */
if (!seq) {
return NULL;
@@ -650,13 +668,13 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
return ((seq->flag & SELECT) ? NULL : seq);
}
else if (!(seq->flag & SELECT)) {
- /* try to find replacement for effect inputs */
+ /* Try to find replacement for effect inputs. */
seq1 = del_seq_find_replace_recurs(scene, seq->seq1);
seq2 = del_seq_find_replace_recurs(scene, seq->seq2);
seq3 = del_seq_find_replace_recurs(scene, seq->seq3);
if (seq1 == seq->seq1 && seq2 == seq->seq2 && seq3 == seq->seq3) {
- /* pass */
+ /* Pass. */
}
else if (seq1 || seq2 || seq3) {
seq->seq1 = (seq1) ? seq1 : (seq2) ? seq2 : seq3;
@@ -666,7 +684,7 @@ static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1);
}
else {
- seq->flag |= SELECT; /* mark for delete */
+ seq->flag |= SELECT; /* Mark for delete. */
}
}
@@ -724,7 +742,7 @@ static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short de
if (seq->type == SEQ_TYPE_META) {
recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
}
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
}
seq = seqn;
}
@@ -740,7 +758,7 @@ static Sequence *split_seq_hard(
/* Unlike soft-split, it's important to use the same value for both strips. */
const bool is_end_exact = ((seq->start + seq->len) == split_frame);
- /* backup values */
+ /* Backup values. */
ts.start = seq->start;
ts.machine = seq->machine;
ts.startstill = seq->startstill;
@@ -753,21 +771,19 @@ static Sequence *split_seq_hard(
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
- /* First Strip! */
- /* strips with extended stillfames before */
-
- /* Precaution, needed because the length saved on-disk may not match the length saved in the
- * blend file, or our code may have minor differences reading file length between versions.
- * This causes hard-split to fail, see: T47862 */
if (seq->type != SEQ_TYPE_META) {
+ /* Precaution, needed because the length saved on-disk may not match the length saved in the
+ * blend file, or our code may have minor differences reading file length between versions.
+ * This causes hard-split to fail, see: T47862. */
BKE_sequence_reload_new_file(bmain, scene, seq, true);
BKE_sequence_calc(scene, seq);
}
+ /* First Strip. */
/* Important to offset the start when 'split_frame == seq->start'
* because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (split_frame <= seq->start)) {
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
seq->startstill = seq->start - split_frame;
@@ -779,18 +795,18 @@ static Sequence *split_seq_hard(
seq->endstill = 0;
}
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) &&
((split_frame >= seq->start) && (split_frame <= (seq->start + seq->len)))) {
seq->endofs = 0;
seq->endstill = 0;
seq->anim_endofs += (seq->start + seq->len) - split_frame;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seq->start + seq->len) < split_frame) && (seq->endstill))) {
seq->endstill -= seq->enddisp - split_frame;
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
}
@@ -800,7 +816,7 @@ static Sequence *split_seq_hard(
BKE_sequence_calc(scene, seq);
if (!skip_dup) {
- /* Duplicate AFTER the first change */
+ /* Duplicate AFTER the first change. */
seqn = BKE_sequence_dupli_recursive(
scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
@@ -808,12 +824,11 @@ static Sequence *split_seq_hard(
if (seqn) {
seqn->flag |= SELECT;
- /* Important not to re-assign this (unlike soft-split) */
#if 0
is_end_exact = ((seqn->start + seqn->len) == split_frame);
#endif
- /* Second Strip! */
- /* strips with extended stillframes before */
+ /* Second Strip. */
+ /* strips with extended stillframes. */
if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
seqn->start = ts.start;
seqn->startstill = ts.start - split_frame;
@@ -821,7 +836,7 @@ static Sequence *split_seq_hard(
seqn->endstill = ts.endstill;
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) &&
((split_frame >= seqn->start) && (split_frame <= (seqn->start + seqn->len)))) {
seqn->start = split_frame;
@@ -833,7 +848,7 @@ static Sequence *split_seq_hard(
seqn->endstill = ts.endstill;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes after. */
else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
seqn->start = split_frame;
@@ -845,6 +860,7 @@ static Sequence *split_seq_hard(
BKE_sequence_reload_new_file(bmain, scene, seqn, false);
BKE_sequence_calc(scene, seqn);
+ BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
}
return seqn;
}
@@ -858,7 +874,7 @@ static Sequence *split_seq_soft(
bool is_end_exact = ((seq->start + seq->len) == split_frame);
- /* backup values */
+ /* Backup values. */
ts.start = seq->start;
ts.machine = seq->machine;
ts.startstill = seq->startstill;
@@ -871,9 +887,8 @@ static Sequence *split_seq_soft(
ts.anim_endofs = seq->anim_endofs;
ts.len = seq->len;
- /* First Strip! */
- /* strips with extended stillfames before */
-
+ /* First Strip. */
+ /* Strips with extended stillfames. */
/* Important to offset the start when 'split_frame == seq->start'
* because we need at least one frame of content after start/end still have clipped it. */
if ((seq->startstill) && (split_frame <= seq->start)) {
@@ -889,16 +904,16 @@ static Sequence *split_seq_soft(
seq->endstill = 0;
}
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) && (split_frame >= seq->start) &&
(split_frame <= (seq->start + seq->len))) {
seq->endofs = (seq->start + seq->len) - split_frame;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seq->start + seq->len) < split_frame) && (seq->endstill))) {
seq->endstill -= seq->enddisp - split_frame;
- /* don't do funny things with METAs ... */
+ /* Don't do funny things with METAs. */
if (seq->type == SEQ_TYPE_META) {
skip_dup = true;
}
@@ -907,7 +922,7 @@ static Sequence *split_seq_soft(
BKE_sequence_calc(scene, seq);
if (!skip_dup) {
- /* Duplicate AFTER the first change */
+ /* Duplicate AFTER the first change. */
seqn = BKE_sequence_dupli_recursive(
scene, scene, new_seq_list, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
}
@@ -917,8 +932,8 @@ static Sequence *split_seq_soft(
is_end_exact = ((seqn->start + seqn->len) == split_frame);
- /* Second Strip! */
- /* strips with extended stillframes before */
+ /* Second Strip. */
+ /* Strips with extended stillframes. */
if ((seqn->startstill) && (split_frame == seqn->start + 1)) {
seqn->start = ts.start;
seqn->startstill = ts.start - split_frame;
@@ -926,7 +941,7 @@ static Sequence *split_seq_soft(
seqn->endstill = ts.endstill;
}
- /* normal strip */
+ /* Normal strip. */
else if ((is_end_exact == false) && (split_frame >= seqn->start) &&
(split_frame <= (seqn->start + seqn->len))) {
seqn->startstill = 0;
@@ -935,7 +950,7 @@ static Sequence *split_seq_soft(
seqn->endstill = ts.endstill;
}
- /* strips with extended stillframes after */
+ /* Strips with extended stillframes. */
else if ((is_end_exact == true) ||
(((seqn->start + seqn->len) < split_frame) && (seqn->endstill))) {
seqn->start = split_frame - ts.len + 1;
@@ -945,16 +960,17 @@ static Sequence *split_seq_soft(
}
BKE_sequence_calc(scene, seqn);
+ BKE_sequence_invalidate_cache_in_range(scene, seq, seqn, SEQ_CACHE_ALL_TYPES);
}
return seqn;
}
-/* like duplicate, but only duplicate and split overlapping strips,
+/* Like duplicate, but only duplicate and split overlapping strips,
* strips to the left of the split_frame are ignored and strips to the right
- * are moved to the end of slist
- * we have to work on the same slist (not using a separate list), since
+ * are moved to the end of slist.
+ * We have to work on the same slist (not using a separate list), since
* otherwise dupli_seq can't check for duplicate names properly and
- * may generate strips with the same name (which will mess up animdata)
+ * may generate strips with the same name which will mess up animdata.
*/
static bool split_seq_list(
@@ -973,7 +989,7 @@ static bool split_seq_list(
seq = slist->first;
while (seq && seq != seq_first_new) {
- seq_next_iter = seq->next; /* we need this because we may remove seq */
+ seq_next_iter = seq->next; /* We need this because we may remove seq. */
seq->tmp = NULL;
if (use_cursor_position) {
if (seq->machine == channel && seq->startdisp < split_frame && seq->enddisp > split_frame) {
@@ -996,10 +1012,10 @@ static bool split_seq_list(
}
}
else if (seq->enddisp <= split_frame) {
- /* do nothing */
+ /* Pass. */
}
else if (seq->startdisp >= split_frame) {
- /* move to tail */
+ /* Move to tail. */
BLI_remlink(slist, seq);
BLI_addtail(slist, seq);
@@ -1022,7 +1038,7 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
bool done = false;
TimeMarker *marker;
- /* all strips >= cfra are shifted */
+ /* All strips >= cfra are shifted. */
if (ed == NULL) {
return 0;
@@ -1085,12 +1101,12 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
}
BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
- // XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
- // return;
+ /* XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
+ * return; */
BLI_strncpy(to, from, sizeof(to));
- // XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
- // return;
+ /* XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
+ * return; */
if (STREQ(to, from)) {
return;
@@ -1101,11 +1117,11 @@ static void UNUSED_FUNCTION(seq_remap_paths)(Scene *scene)
if (STREQLEN(seq->strip->dir, from, strlen(from))) {
printf("found %s\n", seq->strip->dir);
- /* strip off the beginning */
+ /* Strip off the beginning. */
stripped[0] = 0;
BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
- /* new path */
+ /* New path. */
BLI_snprintf(seq->strip->dir, sizeof(seq->strip->dir), "%s%s", to, stripped);
printf("new %s\n", seq->strip->dir);
}
@@ -1122,12 +1138,12 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
bool first = false, done;
bool do_all = RNA_boolean_get(op->ptr, "all");
- /* get first and last frame */
+ /* Get first and last frame. */
boundbox_seq(scene, &rectf);
sfra = (int)rectf.xmin;
efra = (int)rectf.xmax;
- /* first check if the current frame has a gap already */
+ /* Check if the current frame has a gap already. */
for (cfra = CFRA; cfra >= sfra; cfra--) {
if (BKE_sequencer_evaluate_frame(scene, cfra)) {
first = true;
@@ -1136,7 +1152,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
}
for (; cfra < efra; cfra++) {
- /* first == 0 means there's still no strip to remove a gap for */
+ /* There's still no strip to remove a gap for. */
if (first == false) {
if (BKE_sequencer_evaluate_frame(scene, cfra)) {
first = true;
@@ -1164,19 +1180,19 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Remove Gaps";
ot->idname = "SEQUENCER_OT_gap_remove";
ot->description =
"Remove gap at current frame to first strip at the right, independent of selection or "
"locked state of strips";
- /* api callbacks */
+ /* Api callbacks. */
// ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_gap_remove_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna, "all", 0, "All Gaps", "Do all gaps to right of current frame");
@@ -1196,19 +1212,19 @@ static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Insert Gaps";
ot->idname = "SEQUENCER_OT_gap_insert";
ot->description =
"Insert gap at current frame to first strips at the right, independent of selection or "
"locked state of strips";
- /* api callbacks */
+ /* Api callbacks. */
// ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_gap_insert_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1238,7 +1254,7 @@ static int seq_get_snaplimit(View2D *v2d)
}
#endif
-/* Operator functions */
+/* Operator functions. */
bool sequencer_edit_poll(bContext *C)
{
return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL);
@@ -1282,7 +1298,7 @@ bool sequencer_view_strips_poll(bContext *C)
return 0;
}
-/* snap operator*/
+/* Snap operator. */
static int sequencer_snap_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1293,14 +1309,11 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
snap_frame = RNA_int_get(op->ptr, "frame");
- /* also check metas */
+ /* Check metas. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) &&
BKE_sequence_tx_test(seq)) {
if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
- /* simple but no anim update */
- /* seq->start = snap_frame-seq->startofs+seq->startstill; */
-
BKE_sequence_translate(
scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start);
}
@@ -1318,8 +1331,8 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
}
- /* test for effects and overlap
- * don't use SEQP_BEGIN since that would be recursive */
+ /* Test for effects and overlap.
+ * Don't use SEQP_BEGIN since that would be recursive. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) {
seq->flag &= ~SEQ_OVERLAP;
@@ -1340,7 +1353,6 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
}
- /* as last: */
BKE_sequencer_sort(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
@@ -1363,17 +1375,17 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
void SEQUENCER_OT_snap(struct wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Snap Strips to Playhead";
+ /* Identifiers. */
+ ot->name = "Snap Strips to the Current Frame";
ot->idname = "SEQUENCER_OT_snap";
ot->description = "Frame where selected strips will be snapped";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_snap_invoke;
ot->exec = sequencer_snap_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1395,7 +1407,7 @@ typedef struct SlipData {
bool *trim;
int num_seq;
bool slow;
- int slow_offset; /* offset at the point where offset was turned on */
+ int slow_offset; /* Offset at the point where offset was turned on. */
NumInput num_input;
} SlipData;
@@ -1429,7 +1441,7 @@ static void transseq_restore(TransSeq *ts, Sequence *seq)
seq->len = ts->len;
}
-static int slip_add_sequences_rec(
+static int slip_add_sequences_recursive(
ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool do_trim)
{
Sequence *seq;
@@ -1442,8 +1454,8 @@ static int slip_add_sequences_rec(
num_items++;
if (seq->type == SEQ_TYPE_META) {
- /* trim the sub-sequences */
- num_items += slip_add_sequences_rec(
+ /* Trim the sub-sequences. */
+ num_items += slip_add_sequences_recursive(
&seq->seqbase, seq_array, trim, num_items + offset, false);
}
else if (seq->type & SEQ_TYPE_EFFECT) {
@@ -1455,7 +1467,7 @@ static int slip_add_sequences_rec(
return num_items;
}
-static int slip_count_sequences_rec(ListBase *seqbasep, bool first_level)
+static int slip_count_sequences_recursive(ListBase *seqbasep, bool first_level)
{
Sequence *seq;
int trimmed_sequences = 0;
@@ -1465,8 +1477,8 @@ static int slip_count_sequences_rec(ListBase *seqbasep, bool first_level)
trimmed_sequences++;
if (seq->type == SEQ_TYPE_META) {
- /* trim the sub-sequences */
- trimmed_sequences += slip_count_sequences_rec(&seq->seqbase, false);
+ /* Trim the sub-sequences. */
+ trimmed_sequences += slip_count_sequences_recursive(&seq->seqbase, false);
}
}
}
@@ -1483,8 +1495,8 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
int num_seq, i;
View2D *v2d = UI_view2d_fromcontext(C);
- /* first recursively count the trimmed elements */
- num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+ /* Recursively count the trimmed elements. */
+ num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@@ -1502,7 +1514,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
data->num_input.unit_sys = USER_UNIT_NONE;
data->num_input.unit_type[0] = 0;
- slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+ slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
@@ -1517,7 +1529,7 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
WM_event_add_modal_handler(C, op);
- /* notify so we draw extensions immediately */
+ /* Notify so we draw extensions immediately. */
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_RUNNING_MODAL;
@@ -1529,20 +1541,19 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
Editing *ed = BKE_sequencer_editing_get(scene, false);
bool changed = false;
- /* We iterate in reverse so meta-strips are iterated after their children. */
+ /* Iterate in reverse so meta-strips are iterated after their children. */
for (int i = data->num_seq - 1; i >= 0; i--) {
Sequence *seq = data->seq_array[i];
int endframe;
- /* We have the offset, apply the values to the sequence strips. */
- /* first, do the offset */
+ /* Offset seq start. */
seq->start = data->ts[i].start + offset;
if (data->trim[i]) {
/* Find the end-frame. */
endframe = seq->start + seq->len;
- /* Now compute the sequence offsets. */
+ /* Compute the sequence offsets. */
if (endframe > seq->enddisp) {
seq->endstill = 0;
seq->endofs = endframe - seq->enddisp;
@@ -1566,7 +1577,7 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
}
}
else {
- /* If no real trim, don't change the data, rather transform the strips themselves. */
+ /* No transform data (likely effect strip). Only move start and end. */
seq->startdisp = data->ts[i].startdisp + offset;
seq->enddisp = data->ts[i].enddisp + offset;
changed = true;
@@ -1575,7 +1586,7 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
/* Effects are only added if we they are in a meta-strip.
* In this case, dependent strips will just be transformed and
* we can skip calculating for effects.
- * This way we can avoid an extra loop just for effects*/
+ * This way we can avoid an extra loop just for effects. */
if (!(seq->type & SEQ_TYPE_EFFECT)) {
BKE_sequence_calc(scene, seq);
}
@@ -1586,6 +1597,28 @@ static bool sequencer_slip_recursively(Scene *scene, SlipData *data, int offset)
return changed;
}
+/* Make sure, that each strip contains at least 1 frame of content. */
+static void sequencer_slip_apply_limits(SlipData *data, int *offset)
+{
+ for (int i = 0; i < data->num_seq; i++) {
+ if (data->trim[i]) {
+ Sequence *seq = data->seq_array[i];
+ int seq_content_start = data->ts[i].start + *offset;
+ int seq_content_end = seq_content_start + seq->len + seq->anim_startofs + seq->anim_endofs;
+ int diff = 0;
+
+ if (seq_content_start >= seq->enddisp) {
+ diff = seq->enddisp - seq_content_start - 1;
+ }
+
+ if (seq_content_end <= seq->startdisp) {
+ diff = seq->startdisp - seq_content_end + 1;
+ }
+ *offset += diff;
+ }
+ }
+}
+
static int sequencer_slip_exec(bContext *C, wmOperator *op)
{
SlipData *data;
@@ -1595,8 +1628,8 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
int offset = RNA_int_get(op->ptr, "offset");
bool success = false;
- /* first recursively count the trimmed elements */
- num_seq = slip_count_sequences_rec(ed->seqbasep, true);
+ /* Recursively count the trimmed elements. */
+ num_seq = slip_count_sequences_recursive(ed->seqbasep, true);
if (num_seq == 0) {
return OPERATOR_CANCELLED;
@@ -1608,12 +1641,13 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
data->num_seq = num_seq;
- slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+ slip_add_sequences_recursive(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (i = 0; i < num_seq; i++) {
transseq_backup(data->ts + i, data->seq_array[i]);
}
+ sequencer_slip_apply_limits(data, &offset);
success = sequencer_slip_recursively(scene, data, offset);
MEM_freeN(data->seq_array);
@@ -1631,22 +1665,22 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
}
}
-static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
+static void sequencer_slip_update_header(Scene *scene, ScrArea *area, SlipData *data, int offset)
{
char msg[UI_MAX_DRAW_STR];
- if (sa) {
+ if (area) {
if (hasNumInput(&data->num_input)) {
char num_str[NUM_STR_REP_LEN];
outputNumInput(&data->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %s"), num_str);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %s"), num_str);
}
else {
- BLI_snprintf(msg, sizeof(msg), TIP_("Trim offset: %d"), offset);
+ BLI_snprintf(msg, sizeof(msg), TIP_("Slip offset: %d"), offset);
}
}
- ED_area_status_text(sa, msg);
+ ED_area_status_text(area, msg);
}
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1654,16 +1688,18 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const bool has_numInput = hasNumInput(&data->num_input);
bool handled = true;
- /* Modal numinput active, try to handle numeric inputs first... */
+ /* Modal numinput active, try to handle numeric inputs. */
if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &data->num_input, event)) {
- float offset;
- applyNumInput(&data->num_input, &offset);
+ float offset_fl;
+ applyNumInput(&data->num_input, &offset_fl);
+ int offset = round_fl_to_int(offset_fl);
- sequencer_slip_update_header(scene, sa, data, (int)offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1691,11 +1727,12 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
mouse_x = event->mval[0];
}
- /* choose the side based on which side of the playhead the mouse is on */
+ /* Choose the side based on which side of the current frame the mouse is. */
UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
offset = mouseloc[0] - data->init_mouseloc[0];
- sequencer_slip_update_header(scene, sa, data, offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1714,8 +1751,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
MEM_freeN(data->ts);
MEM_freeN(data);
op->customdata = NULL;
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -1747,8 +1784,8 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
- if (sa) {
- ED_area_status_text(sa, NULL);
+ if (area) {
+ ED_area_status_text(area, NULL);
}
return OPERATOR_CANCELLED;
@@ -1772,12 +1809,14 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
break;
}
- /* Modal numinput inactive, try to handle numeric inputs last... */
+ /* Modal numinput inactive, try to handle numeric inputs. */
if (!handled && event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
- float offset;
- applyNumInput(&data->num_input, &offset);
+ float offset_fl;
+ applyNumInput(&data->num_input, &offset_fl);
+ int offset = round_fl_to_int(offset_fl);
- sequencer_slip_update_header(scene, sa, data, (int)offset);
+ sequencer_slip_apply_limits(data, &offset);
+ sequencer_slip_update_header(scene, area, data, offset);
RNA_int_set(op->ptr, "offset", offset);
@@ -1791,18 +1830,18 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
void SEQUENCER_OT_slip(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Trim Strips";
ot->idname = "SEQUENCER_OT_slip";
ot->description = "Trim the contents of the active strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_slip_invoke;
ot->modal = sequencer_slip_modal;
ot->exec = sequencer_slip_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
@@ -1816,7 +1855,7 @@ void SEQUENCER_OT_slip(struct wmOperatorType *ot)
INT32_MAX);
}
-/* mute operator */
+/* Mute operator. */
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1828,7 +1867,7 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SEQ_LOCK) == 0) {
- if (selected) { /* mute unselected */
+ if (selected) {
if (seq->flag & SELECT) {
seq->flag |= SEQ_MUTE;
BKE_sequence_invalidate_dependent(scene, seq);
@@ -1851,23 +1890,23 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_mute(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Mute Strips";
ot->idname = "SEQUENCER_OT_mute";
ot->description = "Mute (un)selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_mute_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "unselected", 0, "Unselected", "Mute unselected rather than selected strips");
}
-/* unmute operator */
+/* Unmute operator. */
static int sequencer_unmute_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1879,7 +1918,7 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SEQ_LOCK) == 0) {
- if (selected) { /* unmute unselected */
+ if (selected) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_MUTE;
BKE_sequence_invalidate_dependent(scene, seq);
@@ -1902,23 +1941,23 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Unmute Strips";
ot->idname = "SEQUENCER_OT_unmute";
ot->description = "Unmute (un)selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_unmute_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips");
}
-/* lock operator */
+/* Lock operator. */
static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1938,20 +1977,20 @@ static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_lock(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Lock Strips";
ot->idname = "SEQUENCER_OT_lock";
ot->description = "Lock strips so they can't be transformed";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_lock_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* unlock operator */
+/* Unlock operator. */
static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1971,20 +2010,20 @@ static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_unlock(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Unlock Strips";
ot->idname = "SEQUENCER_OT_unlock";
ot->description = "Unlock strips so they can be transformed";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_unlock_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* reload operator */
+/* Reload operator. */
static int sequencer_reload_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -2015,17 +2054,17 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Reload Strips";
ot->idname = "SEQUENCER_OT_reload";
ot->description = "Reload strips in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_reload_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER; /* no undo, the data changed is stored outside 'main' */
+ /* Flags. */
+ ot->flag = OPTYPE_REGISTER; /* No undo, the data changed is stored outside 'main'. */
prop = RNA_def_boolean(ot->srna,
"adjust_length",
@@ -2035,7 +2074,7 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* reload operator */
+/* Reload operator. */
static bool sequencer_refresh_all_poll(bContext *C)
{
if (G.is_rendering) {
@@ -2058,12 +2097,12 @@ static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Refresh Sequencer";
ot->idname = "SEQUENCER_OT_refresh_all";
ot->description = "Refresh the sequencer editor";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_refresh_all_exec;
ot->poll = sequencer_refresh_all_poll;
}
@@ -2079,7 +2118,7 @@ static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, error_msg);
return OPERATOR_CANCELLED;
}
- /* see reassigning would create a cycle */
+ /* Check if reassigning would create recursivity. */
if (seq_is_predecessor(seq1, last_seq) || seq_is_predecessor(seq2, last_seq) ||
seq_is_predecessor(seq3, last_seq)) {
BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: no cycles allowed");
@@ -2114,16 +2153,16 @@ static bool sequencer_effect_poll(bContext *C)
void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Reassign Inputs";
ot->idname = "SEQUENCER_OT_reassign_inputs";
ot->description = "Reassign the inputs for the effect strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_reassign_inputs_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -2149,20 +2188,20 @@ static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op)
}
void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Swap Inputs";
ot->idname = "SEQUENCER_OT_swap_inputs";
ot->description = "Swap the first two inputs for the effect strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_inputs_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* split operator */
+/* Split operator. */
static const EnumPropertyItem prop_split_types[] = {
{SEQ_SPLIT_SOFT, "SOFT", 0, "Soft", ""},
{SEQ_SPLIT_HARD, "HARD", 0, "Hard", ""},
@@ -2203,7 +2242,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
use_cursor_position,
split_seq_soft);
}
- if (changed) { /* got new strips ? */
+ if (changed) { /* Got new strips? */
Sequence *seq;
if (ignore_selection) {
if (use_cursor_position) {
@@ -2246,7 +2285,7 @@ static int sequencer_split_exec(bContext *C, wmOperator *op)
}
}
SEQ_END;
- /* as last: */
+
BKE_sequencer_sort(scene);
}
if (changed) {
@@ -2285,24 +2324,24 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
RNA_int_set(op->ptr, "channel", mouseloc[1]);
RNA_enum_set(op->ptr, "side", split_side);
- /*RNA_enum_set(op->ptr, "type", split_hard); */ /*This type is set from the key
- shortsplit */
+ /*RNA_enum_set(op->ptr, "type", split_hard); */
+
return sequencer_split_exec(C, op);
}
void SEQUENCER_OT_split(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Split Strips";
ot->idname = "SEQUENCER_OT_split";
ot->description = "Split the selected strips in two";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_split_invoke;
ot->exec = sequencer_split_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
@@ -2335,7 +2374,7 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
"use_cursor_position",
0,
"Use Cursor Position",
- "Split at position of the cursor instead of playhead");
+ "Split at position of the cursor instead of current frame");
prop = RNA_def_enum(ot->srna,
"side",
@@ -2358,8 +2397,8 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot)
#undef SEQ_SIDE_MOUSE
-/* duplicate operator */
-static int apply_unique_name_cb(Sequence *seq, void *arg_pt)
+/* Duplicate operator. */
+static int apply_unique_name_fn(Sequence *seq, void *arg_pt)
{
Scene *scene = (Scene *)arg_pt;
char name[sizeof(seq->name) - 2];
@@ -2385,11 +2424,11 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
if (nseqbase.first) {
Sequence *seq = nseqbase.first;
- /* rely on the nseqbase list being added at the end */
+ /* Rely on the nseqbase list being added at the end. */
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (; seq; seq = seq->next) {
- BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
+ BKE_sequencer_recursive_apply(seq, apply_unique_name_fn, scene);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2401,20 +2440,20 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Duplicate Strips";
ot->idname = "SEQUENCER_OT_duplicate";
ot->description = "Duplicate the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_add_duplicate_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* delete operator */
+/* Delete operator. */
static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
@@ -2425,7 +2464,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
bool nothing_selected = true;
seq = BKE_sequencer_active_get(scene);
- if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
+ if (seq && seq->flag & SELECT) { /* Avoid a loop since this is likely to be selected. */
nothing_selected = false;
}
else {
@@ -2441,7 +2480,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
- /* for effects and modifiers, try to find a replacement input */
+ /* For effects and modifiers, try to find a replacement input. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (!(seq->flag & SELECT)) {
if ((seq->type & SEQ_TYPE_EFFECT)) {
@@ -2453,17 +2492,17 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- /* delete all selected strips */
+ /* Delete all selected strips. */
recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0);
- /* updates lengths etc */
+ /* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
BKE_sequence_calc(scene, seq);
seq = seq->next;
}
- /* free parent metas */
+ /* Free parent metas. */
ms = ed->metastack.last;
while (ms) {
BKE_sequence_calc(scene, ms->parseq);
@@ -2482,49 +2521,49 @@ static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *e
ARegion *region = CTX_wm_region(C);
if (region->regiontype == RGN_TYPE_WINDOW) {
- /* bounding box of 30 pixels is used for markers shortcuts,
- * prevent conflict with markers shortcuts here
+ /* Bounding box of 30 pixels is used for markers shortcuts,
+ * prevent conflict with markers shortcuts here.
*/
if (event->mval[1] <= 30) {
return OPERATOR_PASS_THROUGH;
}
}
- return WM_operator_confirm(C, op, event);
+ return sequencer_delete_exec(C, op);
}
void SEQUENCER_OT_delete(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Erase Strips";
ot->idname = "SEQUENCER_OT_delete";
ot->description = "Erase selected strips from the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_delete_invoke;
ot->exec = sequencer_delete_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* offset clear operator */
+/* Offset clear operator. */
static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
- /* for effects, try to find a replacement input */
+ /* For effects, try to find a replacement input. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
}
}
- /* updates lengths etc */
+ /* Update lengths, etc. */
seq = ed->seqbasep->first;
while (seq) {
BKE_sequence_calc(scene, seq);
@@ -2547,20 +2586,20 @@ static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Clear Strip Offset";
ot->idname = "SEQUENCER_OT_offset_clear";
ot->description = "Clear strip offsets from the start and end frames";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_offset_clear_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* separate_images operator */
+/* Separate_images operator. */
static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -2572,13 +2611,13 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
int start_ofs, cfra, frame_end;
int step = RNA_int_get(op->ptr, "length");
- seq = ed->seqbasep->first; /* poll checks this is valid */
+ seq = ed->seqbasep->first; /* Poll checks this is valid. */
while (seq) {
if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) {
Sequence *seq_next;
- /* remove seq so overlap tests don't conflict,
+ /* Remove seq so overlap tests don't conflict,
* see seq_free_sequence below for the real freeing. */
BLI_remlink(ed->seqbasep, seq);
/* if (seq->ipo) id_us_min(&seq->ipo->id); */
@@ -2588,7 +2627,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
frame_end = BKE_sequence_tx_get_final_right(seq, false);
while (cfra < frame_end) {
- /* new seq */
+ /* New seq. */
se = BKE_sequencer_give_stripelem(seq, cfra);
seq_new = BKE_sequence_dupli_recursive(
@@ -2599,11 +2638,11 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
seq_new->len = 1;
seq_new->endstill = step - 1;
- /* new strip */
+ /* New strip. */
strip_new = seq_new->strip;
strip_new->us = 1;
- /* new stripdata (only one element now!) */
+ /* New stripdata, only one element now. */
/* Note this assume all elements (images) have the same dimension,
* since we only copy the name here. */
se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new));
@@ -2626,7 +2665,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
seq_next = seq->next;
- BKE_sequence_free(scene, seq);
+ BKE_sequence_free(scene, seq, true);
seq = seq_next;
}
else {
@@ -2634,7 +2673,6 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
}
}
- /* as last: */
BKE_sequencer_sort(scene);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -2644,25 +2682,25 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_images_separate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Separate Images";
ot->idname = "SEQUENCER_OT_images_separate";
ot->description = "On image sequence strips, it returns a strip for each image";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_separate_images_exec;
ot->invoke = WM_operator_props_popup_confirm;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000);
}
-/* META Operators */
+/* META Operators. */
-/* separate_meta_toggle operator */
+/* Separate_meta_toggle operator. */
static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -2671,7 +2709,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
MetaStack *ms;
if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) {
- /* Enter Metastrip */
+ /* Enter metastrip. */
ms = MEM_mallocN(sizeof(MetaStack), "metastack");
BLI_addtail(&ed->metastack, ms);
ms->parseq = last_seq;
@@ -2683,7 +2721,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
BKE_sequencer_active_set(scene, NULL);
}
else {
- /* Exit Metastrip (if possible) */
+ /* Exit metastrip if possible. */
Sequence *seq;
@@ -2696,18 +2734,18 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ed->seqbasep = ms->oldbasep;
- /* for old files, update from meta */
+ /* For old files, update from meta. */
if (ms->disp_range[0] == ms->disp_range[1]) {
copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
}
- /* recalc all: the meta can have effects connected to it */
+ /* Recalc all: the meta can have effects connected to it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
BKE_sequence_calc(scene, seq);
}
/* 2.73+, keeping endpoints is important!
- * moving them around means you can't usefully use metas in a complex edit. */
+ * Moving them around means you can't usefully use metas in a complex edit. */
#if 1
BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
@@ -2735,20 +2773,20 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Toggle Meta Strip";
ot->idname = "SEQUENCER_OT_meta_toggle";
ot->description = "Toggle a metastrip (to edit enclosed strips)";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_toggle_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* separate_meta_make operator */
+/* Separate_meta_make operator. */
static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -2762,9 +2800,9 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* remove all selected from main list, and put in meta */
+ /* Remove all selected from main list, and put in meta. */
- seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* channel number set later */
+ seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1, SEQ_TYPE_META); /* Channel number set later. */
strcpy(seqm->name + 2, "MetaStrip");
seqm->flag = SELECT;
@@ -2799,16 +2837,16 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_meta_make(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Make Meta Strip";
ot->idname = "SEQUENCER_OT_meta_make";
ot->description = "Group selected strips into a metastrip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_make_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -2831,7 +2869,7 @@ static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
}
}
-/* separate_meta_make operator */
+/* Separate_meta_make operator. */
static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -2852,9 +2890,9 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
BLI_listbase_clear(&last_seq->seqbase);
BLI_remlink(ed->seqbasep, last_seq);
- BKE_sequence_free(scene, last_seq);
+ BKE_sequence_free(scene, last_seq, true);
- /* empty meta strip, delete all effects depending on it */
+ /* Empty meta strip, delete all effects depending on it. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->type & SEQ_TYPE_EFFECT) && seq_depends_on_meta(seq, last_seq)) {
seq->flag |= SEQ_FLAG_DELETE;
@@ -2863,8 +2901,8 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0);
- /* test for effects and overlap
- * don't use SEQP_BEGIN since that would be recursive */
+ /* Test for effects and overlap
+ * don't use SEQP_BEGIN since that would be recursive. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_OVERLAP;
@@ -2884,20 +2922,20 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "UnMeta Strip";
ot->idname = "SEQUENCER_OT_meta_separate";
ot->description = "Put the contents of a metastrip back in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_meta_separate_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_all_exec(bContext *C, wmOperator *op)
{
ARegion *region = CTX_wm_region(C);
@@ -2912,16 +2950,16 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "View All";
+ /* Identifiers. */
+ ot->name = "Frame All";
ot->idname = "SEQUENCER_OT_view_all";
ot->description = "View all the strips in the sequencer";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_all_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -2935,23 +2973,23 @@ static int sequencer_view_frame_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_frame(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Go to Current Frame";
ot->idname = "SEQUENCER_OT_view_frame";
- ot->description = "Move the view to the playhead";
+ ot->description = "Move the view to the current frame";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_frame_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = 0;
}
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
{
- bScreen *sc = CTX_wm_screen(C);
+ bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
#if 0
ARegion *region = CTX_wm_region(C);
@@ -2962,10 +3000,10 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
v2d->cur = v2d->tot;
UI_view2d_curRect_validate(v2d);
- UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY);
+ UI_view2d_sync(screen, area, v2d, V2D_LOCK_COPY);
#if 0
- /* Like zooming on an image view */
+ /* Like zooming on an image view. */
float zoomX, zoomY;
int width, height, imgwidth, imgheight;
@@ -2977,11 +3015,11 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
imgwidth = (scene->r.size * scene->r.xsch) / 100;
imgheight = (scene->r.size * scene->r.ysch) / 100;
- /* Apply aspect, doesn't need to be that accurate */
+ /* Apply aspect, doesn't need to be that accurate. */
imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp));
if (((imgwidth >= width) || (imgheight >= height)) && ((width > 0) && (height > 0))) {
- /* Find the zoom value that will fit the image in the image space */
+ /* Find the zoom value that will fit the image in the image space. */
zoomX = ((float)width) / ((float)imgwidth);
zoomY = ((float)height) / ((float)imgheight);
sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY;
@@ -2999,16 +3037,16 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_view_all_preview(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "View All";
+ /* Identifiers. */
+ ot->name = "Frame All";
ot->idname = "SEQUENCER_OT_view_all_preview";
ot->description = "Zoom preview to fit in the area";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_all_preview_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3034,16 +3072,16 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sequencer View Zoom Ratio";
ot->idname = "SEQUENCER_OT_view_zoom_ratio";
ot->description = "Change zoom ratio of sequencer preview";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_zoom_ratio_exec;
ot->poll = ED_operator_sequencer_active;
- /* properties */
+ /* Properties. */
RNA_def_float(ot->srna,
"ratio",
1.0f,
@@ -3068,7 +3106,7 @@ static const EnumPropertyItem view_type_items[] = {
};
#endif
-/* view_all operator */
+/* View_all operator. */
static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
@@ -3085,20 +3123,20 @@ static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_view_toggle(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "View Toggle";
ot->idname = "SEQUENCER_OT_view_toggle";
ot->description = "Toggle between sequencer views (sequence, preview, both)";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_toggle_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
-/* view_selected operator */
+/* View_selected operator. */
static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3148,7 +3186,7 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
cur_new.ymin = ymin;
cur_new.ymax = ymax;
- /* only zoom out vertically */
+ /* Only zoom out vertically. */
if (orig_height > BLI_rctf_size_y(&cur_new)) {
ymid = BLI_rctf_cent_y(&cur_new);
@@ -3167,16 +3205,16 @@ static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_view_selected(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Frame Selected";
ot->idname = "SEQUENCER_OT_view_selected";
ot->description = "Zoom the sequencer on the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_view_selected_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3199,7 +3237,7 @@ static bool strip_jump_internal(Scene *scene,
static bool sequencer_strip_jump_poll(bContext *C)
{
- /* prevent changes during render */
+ /* Prevent changes during render. */
if (G.is_rendering) {
return 0;
}
@@ -3207,14 +3245,14 @@ static bool sequencer_strip_jump_poll(bContext *C)
return sequencer_edit_poll(C);
}
-/* jump frame to edit point operator */
+/* Jump frame to edit point operator. */
static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const bool next = RNA_boolean_get(op->ptr, "next");
const bool center = RNA_boolean_get(op->ptr, "center");
- /* currently do_skip_mute is always true */
+ /* Currently do_skip_mute is always true. */
if (!strip_jump_internal(scene, next ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT, true, center)) {
return OPERATOR_CANCELLED;
}
@@ -3226,19 +3264,19 @@ static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Jump to Strip";
ot->idname = "SEQUENCER_OT_strip_jump";
ot->description = "Move frame to previous edit point";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_strip_jump_exec;
ot->poll = sequencer_strip_jump_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
RNA_def_boolean(ot->srna, "center", true, "Use strip center", "");
}
@@ -3296,7 +3334,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
if (seq) {
- /* disallow effect strips */
+ /* Disallow effect strips. */
if (BKE_sequence_effect_get_num_inputs(seq->type) >= 1 &&
(seq->effectdata || seq->seq1 || seq->seq2 || seq->seq3)) {
return OPERATOR_CANCELLED;
@@ -3315,7 +3353,7 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
break;
}
- // XXX - should be a generic function
+ /* XXX - Should be a generic function. */
for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
@@ -3323,11 +3361,11 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
}
}
- /* do this in a new loop since both effects need to be calculated first */
+ /* Do this in a new loop since both effects need to be calculated first. */
for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
if ((iseq->type & SEQ_TYPE_EFFECT) &&
(seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
- /* this may now overlap */
+ /* This may now overlap. */
if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) {
BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
}
@@ -3346,19 +3384,19 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_swap(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Swap Strip";
ot->idname = "SEQUENCER_OT_swap";
ot->description = "Swap active strip with strip to the right or left";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(
ot->srna, "side", prop_side_lr_types, SEQ_SIDE_RIGHT, "Side", "Side of the strip to swap");
}
@@ -3392,7 +3430,7 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
}
if (se) {
- // prevent setting the render size if sequence values aren't initialized
+ /* Prevent setting the render size if sequence values aren't initialized. */
if ((se->orig_width > 0) && (se->orig_height > 0)) {
scene->r.xsch = se->orig_width;
scene->r.ysch = se->orig_height;
@@ -3406,19 +3444,17 @@ static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_rendersize(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Render Size";
ot->idname = "SEQUENCER_OT_rendersize";
ot->description = "Set render size and aspect from active sequence";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_rendersize_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
static void seq_copy_del_sound(Scene *scene, Sequence *seq)
@@ -3441,8 +3477,6 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- ListBase nseqbase = {NULL, NULL};
-
BKE_sequencer_free_clipboard();
if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
@@ -3451,33 +3485,12 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
}
BKE_sequence_base_dupli_recursive(
- scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, LIB_ID_CREATE_NO_USER_REFCOUNT);
-
- /* To make sure the copied strips have unique names between each other add
- * them temporarily to the end of the original seqbase. (bug 25932)
- */
- if (nseqbase.first) {
- Sequence *seq, *first_seq = nseqbase.first;
- BLI_movelisttolist(ed->seqbasep, &nseqbase);
-
- for (seq = first_seq; seq; seq = seq->next) {
- BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
- }
-
- seqbase_clipboard.first = first_seq;
- seqbase_clipboard.last = ed->seqbasep->last;
-
- if (first_seq->prev) {
- first_seq->prev->next = NULL;
- ed->seqbasep->last = first_seq->prev;
- first_seq->prev = NULL;
- }
- }
+ scene, scene, &seqbase_clipboard, ed->seqbasep, 0, LIB_ID_CREATE_NO_USER_REFCOUNT);
seqbase_clipboard_frame = scene->r.cfra;
- /* Need to remove anything that references the current scene */
- for (Sequence *seq = seqbase_clipboard.first; seq; seq = seq->next) {
+ /* Remove anything that references the current scene. */
+ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
seq_copy_del_sound(scene, seq);
}
@@ -3490,26 +3503,24 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_copy(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Copy";
ot->idname = "SEQUENCER_OT_copy";
ot->description = "Copy selected strips to clipboard";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_copy_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
-
- /* properties */
}
static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Editing *ed = BKE_sequencer_editing_get(scene, true); /* create if needed */
+ Editing *ed = BKE_sequencer_editing_get(scene, true); /* Create if needed. */
ListBase nseqbase = {NULL, NULL};
int ofs;
Sequence *iseq, *iseq_first;
@@ -3521,28 +3532,19 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
BKE_sequencer_base_clipboard_pointers_restore(&seqbase_clipboard, bmain);
- BKE_sequence_base_dupli_recursive(
- scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0);
- BKE_sequencer_base_clipboard_pointers_store(bmain, &seqbase_clipboard);
-
- /* transform pasted strips before adding */
- if (ofs) {
- for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
- BKE_sequence_translate(scene, iseq, ofs);
- }
- }
+ BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0);
iseq_first = nseqbase.first;
BLI_movelisttolist(ed->seqbasep, &nseqbase);
- /* make sure the pasted strips have unique names between them */
- for (iseq = iseq_first; iseq; iseq = iseq->next) {
- BKE_sequencer_recursive_apply(iseq, apply_unique_name_cb, scene);
- }
-
- /* ensure pasted strips don't overlap */
for (iseq = iseq_first; iseq; iseq = iseq->next) {
+ /* Make sure, that pasted strips have unique names. */
+ BKE_sequencer_recursive_apply(iseq, apply_unique_name_fn, scene);
+ /* Translate after name has been changed, otherwise this will affect animdata of original
+ * strip. */
+ BKE_sequence_translate(scene, iseq, ofs);
+ /* Ensure, that pasted strips don't overlap. */
if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) {
BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
}
@@ -3550,25 +3552,24 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ ED_outliner_select_sync_from_sequence_tag(C);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_paste(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Paste";
ot->idname = "SEQUENCER_OT_paste";
ot->description = "Paste strips from clipboard";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_paste_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
@@ -3619,22 +3620,20 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_swap_data(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sequencer Swap Data";
ot->idname = "SEQUENCER_OT_swap_data";
ot->description = "Swap 2 sequencer strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_swap_data_exec;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* box select operator */
+/* Box select operator. */
static int view_ghost_border_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3642,7 +3641,7 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
rctf rect;
- /* convert coordinates of rect to 'tot' rect coordinates */
+ /* Convert coordinates of rect to 'tot' rect coordinates. */
WM_operator_properties_border_to_rctf(op, &rect);
UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
@@ -3669,30 +3668,28 @@ static int view_ghost_border_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* ****** Box Select ****** */
void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Border Offset View";
ot->idname = "SEQUENCER_OT_view_ghost_border";
ot->description = "Set the boundaries of the border used for offset-view";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = WM_gesture_box_invoke;
ot->exec = view_ghost_border_exec;
ot->modal = WM_gesture_box_modal;
ot->poll = sequencer_view_preview_poll;
ot->cancel = WM_gesture_box_cancel;
- /* flags */
+ /* Flags. */
ot->flag = 0;
- /* rna */
+ /* Properties. */
WM_operator_properties_gesture_box(ot);
}
-/* rebuild_proxy operator */
-
+/* Rebuild_proxy operator. */
static int sequencer_rebuild_proxy_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -3743,16 +3740,16 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Rebuild Proxy and Timecode Indices";
ot->idname = "SEQUENCER_OT_rebuild_proxy";
ot->description = "Rebuild all selected proxies and timecode indices using the job system";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_rebuild_proxy_invoke;
ot->exec = sequencer_rebuild_proxy_exec;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
}
@@ -3781,12 +3778,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
SEQP_BEGIN (ed, seq) {
if ((seq->flag & SELECT)) {
- if (ELEM(seq->type,
- SEQ_TYPE_MOVIE,
- SEQ_TYPE_IMAGE,
- SEQ_TYPE_META,
- SEQ_TYPE_SCENE,
- SEQ_TYPE_MULTICAM)) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META)) {
BKE_sequencer_proxy_set(seq, turnon);
if (seq->strip->proxy == NULL) {
continue;
@@ -3838,16 +3830,16 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Selected Strip Proxies";
ot->idname = "SEQUENCER_OT_enable_proxies";
ot->description = "Enable selected proxies on all selected Movie, Image and Meta strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_enable_proxies_invoke;
ot->exec = sequencer_enable_proxies_exec;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER;
RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
@@ -3857,8 +3849,7 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
}
-/* change ops */
-
+/* Change effect inputs operator. */
static const EnumPropertyItem prop_change_effect_input_types[] = {
{0, "A_B", 0, "A -> B", ""},
{1, "B_C", 0, "B -> C", ""},
@@ -3899,9 +3890,8 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -3909,21 +3899,22 @@ static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Effect Input";
ot->idname = "SEQUENCER_OT_change_effect_input";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_effect_input_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(
ot->srna, "swap", prop_change_effect_input_types, 0, "Swap", "The effect inputs to swap");
}
+/* Change effect type operator. */
static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -3931,14 +3922,14 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
Sequence *seq = BKE_sequencer_active_get(scene);
const int new_type = RNA_enum_get(op->ptr, "type");
- /* free previous effect and init new effect */
+ /* Free previous effect and init new effect. */
struct SeqEffectHandle sh;
if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
return OPERATOR_CANCELLED;
}
- /* can someone explain the logic behind only allowing to increase this,
+ /* Can someone explain the logic behind only allowing to increase this,
* copied from 2.4x - campbell */
if (BKE_sequence_effect_get_num_inputs(seq->type) <
BKE_sequence_effect_get_num_inputs(new_type)) {
@@ -3955,10 +3946,8 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
sh.init(seq);
}
- /* update */
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
-
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -3968,15 +3957,15 @@ static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Effect Type";
ot->idname = "SEQUENCER_OT_change_effect_type";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_effect_type_exec;
ot->poll = sequencer_effect_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_enum(ot->srna,
@@ -3987,6 +3976,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
"Sequencer effect type");
}
+/* Change path operator. */
static int sequencer_change_path_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
@@ -4002,7 +3992,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
int len;
StripElem *se;
- /* need to find min/max frame for placeholders */
+ /* Need to find min/max frame for placeholders. */
if (use_placeholders) {
len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
}
@@ -4040,16 +4030,16 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
RNA_END;
}
- /* reset these else we wont see all the images */
+ /* Reset these else we wont see all the images. */
seq->anim_startofs = seq->anim_endofs = 0;
- /* correct start/end frames so we don't move
- * important not to set seq->len = len; allow the function to handle it */
+ /* Correct start/end frames so we don't move.
+ * Important not to set seq->len = len; allow the function to handle it. */
BKE_sequence_reload_new_file(bmain, scene, seq, true);
BKE_sequence_calc(scene, seq);
- /* important else we don't get the imbuf cache flushed */
+ /* Invalidate cache. */
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
}
else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
@@ -4063,7 +4053,7 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
BKE_sound_load(bmain, sound);
}
else {
- /* lame, set rna filepath */
+ /* Lame, set rna filepath. */
PointerRNA seq_ptr;
PropertyRNA *prop;
char filepath[FILE_MAX];
@@ -4092,7 +4082,7 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
RNA_string_set(op->ptr, "directory", seq->strip->dir);
RNA_string_set(op->ptr, "filepath", filepath);
- /* set default display depending on seq type */
+ /* Set default display depending on seq type. */
if (seq->type == SEQ_TYPE_IMAGE) {
RNA_boolean_set(op->ptr, "filter_movie", false);
}
@@ -4107,16 +4097,16 @@ static int sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEve
void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Change Data/Files";
ot->idname = "SEQUENCER_OT_change_path";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_change_path_exec;
ot->invoke = sequencer_change_path_invoke;
ot->poll = sequencer_strip_has_path_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -4134,6 +4124,7 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
"Use placeholders for missing frames of the strip");
}
+/* Export subtitles operator. */
static int sequencer_export_subtitles_invoke(bContext *C,
wmOperator *op,
const wmEvent *UNUSED(event))
@@ -4176,7 +4167,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", filepath);
BLI_path_extension_ensure(filepath, sizeof(filepath), ".srt");
- /* Avoid File write exceptions */
+ /* Avoid File write exceptions. */
if (!BLI_exists(filepath)) {
BLI_make_existing_file(filepath);
if (!BLI_file_touch(filepath)) {
@@ -4203,7 +4194,7 @@ static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp);
- /* time to open and write! */
+ /* Open and write file. */
file = BLI_fopen(filepath, "w");
for (seq = text_seq.first; seq; seq = seq_next) {
@@ -4246,17 +4237,17 @@ static bool sequencer_strip_is_text_poll(bContext *C)
void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Export Subtitles";
ot->idname = "SEQUENCER_OT_export_subtitles";
ot->description = "Export .srt file containing text strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_export_subtitles_exec;
ot->invoke = sequencer_export_subtitles_invoke;
ot->poll = sequencer_strip_is_text_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
WM_operator_properties_filesel(ot,
@@ -4268,6 +4259,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
FILE_SORT_ALPHA);
}
+/* Set range to strips operator. */
static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -4316,16 +4308,16 @@ void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Set Range to Strips";
ot->idname = "SEQUENCER_OT_set_range_to_strips";
ot->description = "Set the frame range to the selected strips start and end";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_set_range_to_strips_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index f70bc06caf7..0e7e691c748 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -27,7 +27,7 @@
#include "DNA_sequence_types.h"
#include "RNA_access.h"
-/* internal exports only */
+/* Internal exports only. */
struct ARegion;
struct ARegionType;
@@ -57,7 +57,7 @@ void sequencer_special_update_set(Sequence *seq);
float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx);
/* UNUSED */
-// void seq_reset_imageofs(struct SpaceSeq *sseq);
+/* void seq_reset_imageofs(struct SpaceSeq *sseq); */
struct ImBuf *sequencer_ibuf_get(struct Main *bmain,
struct Depsgraph *depsgraph,
@@ -88,19 +88,19 @@ int seq_effect_find_selected(struct Scene *scene,
struct Sequence **r_selseq3,
const char **r_error_str);
-/* operator helpers */
+/* Operator helpers. */
bool sequencer_edit_poll(struct bContext *C);
/* UNUSED */
-// bool sequencer_strip_poll(struct bContext *C);
+/* bool sequencer_strip_poll(struct bContext *C); */
bool sequencer_strip_has_path_poll(struct bContext *C);
bool sequencer_view_preview_poll(struct bContext *C);
bool sequencer_view_strips_poll(struct bContext *C);
-/* externs */
+/* Externs. */
extern EnumPropertyItem sequencer_prop_effect_types[];
extern EnumPropertyItem prop_side_types[];
-/* operators */
+/* Operators. */
struct wmKeyConfig;
struct wmOperatorType;
@@ -152,7 +152,7 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot);
void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot);
-/* preview specific operators */
+/* Preview specific operators. */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
/* sequencer_select.c */
@@ -191,10 +191,11 @@ enum {
SEQ_SELECT_LR_MOUSE,
SEQ_SELECT_LR_LEFT,
SEQ_SELECT_LR_RIGHT,
+ SEQ_SELECT_LR_OVERLAP,
};
-/* defines used internally */
-#define SCE_MARKERS 0 // XXX - dummy
+/* Defines used internally. */
+#define SCE_MARKERS 0 /* XXX - dummy */
/* sequencer_ops.c */
void sequencer_operatortypes(void);
@@ -222,7 +223,7 @@ void SEQUENCER_OT_sample(struct wmOperatorType *ot);
/* sequencer_preview.c */
void sequencer_preview_add_sound(const struct bContext *C, struct Sequence *seq);
-/* sequencer_add */
+/* sequencer_add.c */
int sequencer_image_seq_get_minmax_frame(struct wmOperator *op,
int sfra,
int *r_minframe,
diff --git a/source/blender/editors/space_sequencer/sequencer_modifier.c b/source/blender/editors/space_sequencer/sequencer_modifier.c
index b90dc5e10ff..e0f7179c3f9 100644
--- a/source/blender/editors/space_sequencer/sequencer_modifier.c
+++ b/source/blender/editors/space_sequencer/sequencer_modifier.c
@@ -35,7 +35,7 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/*********************** Add modifier operator *************************/
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 4296701366a..ac00838a079 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -32,7 +32,7 @@
#include "ED_markers.h"
#include "ED_select_utils.h"
#include "ED_sequencer.h"
-#include "ED_transform.h" /* transform keymap */
+#include "ED_transform.h" /* Transform keymap. */
#include "BKE_sequencer.h"
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
index 7c8a5ff5981..7d416884721 100644
--- a/source/blender/editors/space_sequencer/sequencer_preview.c
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -52,9 +52,9 @@ typedef struct PreviewJobAudio {
struct PreviewJobAudio *next, *prev;
struct Main *bmain;
bSound *sound;
- int lr; /* sample left or right */
+ int lr; /* Sample left or right. */
int startframe;
- bool waveform; /* reload sound or waveform */
+ bool waveform; /* Reload sound or waveform. */
} PreviewJobAudio;
static void free_preview_job(void *data)
@@ -66,7 +66,7 @@ static void free_preview_job(void *data)
MEM_freeN(pj);
}
-/* only this runs inside thread */
+/* Only this runs inside thread. */
static void preview_startjob(void *data, short *stop, short *do_update, float *progress)
{
PreviewJob *pj = data;
@@ -89,7 +89,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
while (previewjb) {
sound = previewjb->sound;
- /* make sure we cleanup the loading flag! */
+ /* Make sure we cleanup the loading flag! */
BLI_spin_lock(sound->spinlock);
sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
BLI_spin_unlock(sound->spinlock);
@@ -127,10 +127,9 @@ static void preview_endjob(void *data)
void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
{
- /* first, get the preview job, if it exists */
wmJob *wm_job;
PreviewJob *pj;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio");
wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
@@ -139,6 +138,7 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_JOB_PROGRESS,
WM_JOB_TYPE_SEQ_BUILD_PREVIEW);
+ /* Get the preview job if it exists. */
pj = WM_jobs_customdata_get(wm_job);
if (!pj) {
@@ -152,8 +152,6 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob);
}
- /* attempt to lock mutex of job here */
-
audiojob->bmain = CTX_data_main(C);
audiojob->sound = seq->sound;
@@ -167,5 +165,5 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c
index 309840ea9e3..243a6e193eb 100644
--- a/source/blender/editors/space_sequencer/sequencer_scopes.c
+++ b/source/blender/editors/space_sequencer/sequencer_scopes.c
@@ -42,7 +42,7 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
yuv[1] = 0.492f * (rgb[2] - yuv[0]);
yuv[2] = 0.877f * (rgb[0] - yuv[0]);
- /* Normalize */
+ /* Normalize. */
yuv[1] *= 255.0f / (122 * 2.0f);
yuv[1] += 0.5f;
@@ -50,24 +50,24 @@ static void rgb_to_yuv_normalized(const float rgb[3], float yuv[3])
yuv[2] += 0.5f;
}
-static void scope_put_pixel(unsigned char *table, unsigned char *pos)
+static void scope_put_pixel(uchar *table, uchar *pos)
{
- unsigned char newval = table[*pos];
+ uchar newval = table[*pos];
pos[0] = pos[1] = pos[2] = newval;
pos[3] = 255;
}
-static void scope_put_pixel_single(unsigned char *table, unsigned char *pos, int col)
+static void scope_put_pixel_single(uchar *table, uchar *pos, int col)
{
char newval = table[pos[col]];
pos[col] = newval;
pos[3] = 255;
}
-static void wform_put_line(int w, unsigned char *last_pos, unsigned char *new_pos)
+static void wform_put_line(int w, uchar *last_pos, uchar *new_pos)
{
if (last_pos > new_pos) {
- unsigned char *temp = new_pos;
+ uchar *temp = new_pos;
new_pos = last_pos;
last_pos = temp;
}
@@ -81,10 +81,10 @@ static void wform_put_line(int w, unsigned char *last_pos, unsigned char *new_po
}
}
-static void wform_put_line_single(int w, unsigned char *last_pos, unsigned char *new_pos, int col)
+static void wform_put_line_single(int w, uchar *last_pos, uchar *new_pos, int col)
{
if (last_pos > new_pos) {
- unsigned char *temp = new_pos;
+ uchar *temp = new_pos;
new_pos = last_pos;
last_pos = temp;
}
@@ -98,12 +98,12 @@ static void wform_put_line_single(int w, unsigned char *last_pos, unsigned char
}
}
-static void wform_put_border(unsigned char *tgt, int w, int h)
+static void wform_put_border(uchar *tgt, int w, int h)
{
int x, y;
for (x = 0; x < w; x++) {
- unsigned char *p = tgt + 4 * x;
+ uchar *p = tgt + 4 * x;
p[1] = p[3] = 155;
p[4 * w + 1] = p[4 * w + 3] = 155;
p = tgt + 4 * (w * (h - 1) + x);
@@ -112,7 +112,7 @@ static void wform_put_border(unsigned char *tgt, int w, int h)
}
for (y = 0; y < h; y++) {
- unsigned char *p = tgt + 4 * w * y;
+ uchar *p = tgt + 4 * w * y;
p[1] = p[3] = 155;
p[4 + 1] = p[4 + 3] = 155;
p = tgt + 4 * (w * y + w - 1);
@@ -121,7 +121,7 @@ static void wform_put_border(unsigned char *tgt, int w, int h)
}
}
-static void wform_put_gridrow(unsigned char *tgt, float perc, int w, int h)
+static void wform_put_gridrow(uchar *tgt, float perc, int w, int h)
{
int i;
@@ -134,7 +134,7 @@ static void wform_put_gridrow(unsigned char *tgt, float perc, int w, int h)
}
}
-static void wform_put_grid(unsigned char *tgt, int w, int h)
+static void wform_put_grid(uchar *tgt, int w, int h)
{
wform_put_gridrow(tgt, 90.0, w, h);
wform_put_gridrow(tgt, 70.0, w, h);
@@ -145,27 +145,27 @@ static ImBuf *make_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- const unsigned char *src = (unsigned char *)ibuf->rect;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ const uchar *src = (uchar *)ibuf->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
wform_put_border(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p = NULL;
+ uchar *last_p = NULL;
for (x = 0; x < ibuf->x; x++) {
- const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ const uchar *rgb = src + 4 * (ibuf->x * y + x);
float v = (float)IMB_colormanagement_get_luminance_byte(rgb) / 255.0f;
- unsigned char *p = tgt;
+ uchar *p = tgt;
p += 4 * (w * ((int)(v * (h - 3)) + 1) + x + 1);
scope_put_pixel(wtable, p);
@@ -187,25 +187,25 @@ static ImBuf *make_waveform_view_from_ibuf_float(ImBuf *ibuf)
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
const float *src = ibuf->rect_float;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p = NULL;
+ uchar *last_p = NULL;
for (x = 0; x < ibuf->x; x++) {
const float *rgb = src + 4 * (ibuf->x * y + x);
float v = IMB_colormanagement_get_luminance(rgb);
- unsigned char *p = tgt;
+ uchar *p = tgt;
CLAMP(v, 0.0f, 1.0f);
@@ -241,28 +241,28 @@ static ImBuf *make_sep_waveform_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
- const unsigned char *src = (const unsigned char *)ibuf->rect;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ const uchar *src = (const uchar *)ibuf->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p[3] = {NULL, NULL, NULL};
+ uchar *last_p[3] = {NULL, NULL, NULL};
for (x = 0; x < ibuf->x; x++) {
int c;
- const unsigned char *rgb = src + 4 * (ibuf->x * y + x);
+ const uchar *rgb = src + 4 * (ibuf->x * y + x);
for (c = 0; c < 3; c++) {
- unsigned char *p = tgt;
+ uchar *p = tgt;
p += 4 * (w * ((rgb[c] * (h - 3)) / 255 + 1) + c * sw + x / 3 + 1);
scope_put_pixel_single(wtable, p, c);
@@ -287,27 +287,27 @@ static ImBuf *make_sep_waveform_view_from_ibuf_float(ImBuf *ibuf)
ImBuf *rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect);
int x, y;
const float *src = ibuf->rect_float;
- unsigned char *tgt = (unsigned char *)rval->rect;
+ uchar *tgt = (uchar *)rval->rect;
int w = ibuf->x + 3;
int sw = ibuf->x / 3;
int h = 515;
float waveform_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
wform_put_grid(tgt, w, h);
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, waveform_gamma) * 255);
}
for (y = 0; y < ibuf->y; y++) {
- unsigned char *last_p[3] = {NULL, NULL, NULL};
+ uchar *last_p[3] = {NULL, NULL, NULL};
for (x = 0; x < ibuf->x; x++) {
int c;
const float *rgb = src + 4 * (ibuf->x * y + x);
for (c = 0; c < 3; c++) {
- unsigned char *p = tgt;
+ uchar *p = tgt;
float v = rgb[c];
CLAMP(v, 0.0f, 1.0f);
@@ -343,18 +343,18 @@ ImBuf *make_sep_waveform_view_from_ibuf(ImBuf *ibuf)
static void draw_zebra_byte(ImBuf *src, ImBuf *ibuf, float perc)
{
- unsigned int limit = 255.0f * perc / 100.0f;
- unsigned char *p = (unsigned char *)src->rect;
- unsigned char *o = (unsigned char *)ibuf->rect;
+ uint limit = 255.0f * perc / 100.0f;
+ uchar *p = (uchar *)src->rect;
+ uchar *o = (uchar *)ibuf->rect;
int x;
int y;
for (y = 0; y < ibuf->y; y++) {
for (x = 0; x < ibuf->x; x++) {
- unsigned char r = *p++;
- unsigned char g = *p++;
- unsigned char b = *p++;
- unsigned char a = *p++;
+ uchar r = *p++;
+ uchar g = *p++;
+ uchar b = *p++;
+ uchar a = *p++;
if (r >= limit || g >= limit || b >= limit) {
if (((x + y) & 0x08) != 0) {
@@ -375,7 +375,7 @@ static void draw_zebra_float(ImBuf *src, ImBuf *ibuf, float perc)
{
float limit = perc / 100.0f;
const float *p = src->rect_float;
- unsigned char *o = (unsigned char *)ibuf->rect;
+ uchar *o = (uchar *)ibuf->rect;
int x;
int y;
@@ -417,7 +417,7 @@ ImBuf *make_zebra_view_from_ibuf(ImBuf *src, float perc)
static void draw_histogram_marker(ImBuf *ibuf, int x)
{
- unsigned char *p = (unsigned char *)ibuf->rect;
+ uchar *p = (uchar *)ibuf->rect;
int barh = ibuf->y * 0.1;
int i;
@@ -431,7 +431,7 @@ static void draw_histogram_marker(ImBuf *ibuf, int x)
static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
{
- unsigned char *p = (unsigned char *)ibuf->rect;
+ uchar *p = (uchar *)ibuf->rect;
int barh = ibuf->y * val * 0.9f;
int i;
@@ -447,21 +447,20 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col)
typedef struct MakeHistogramViewData {
const ImBuf *ibuf;
- uint32_t (*bins)[HIS_STEPS];
} MakeHistogramViewData;
-static void make_histogram_view_from_ibuf_byte_cb_ex(void *__restrict userdata,
- const int y,
- const TaskParallelTLS *__restrict tls)
+static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata,
+ const int y,
+ const TaskParallelTLS *__restrict tls)
{
MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
- const unsigned char *src = (unsigned char *)ibuf->rect;
+ const uchar *src = (uchar *)ibuf->rect;
uint32_t(*cur_bins)[HIS_STEPS] = tls->userdata_chunk;
for (int x = 0; x < ibuf->x; x++) {
- const unsigned char *pixel = src + (y * ibuf->x + x) * 4;
+ const uchar *pixel = src + (y * ibuf->x + x) * 4;
for (int j = 3; j--;) {
cur_bins[j][pixel[j]]++;
@@ -469,17 +468,16 @@ static void make_histogram_view_from_ibuf_byte_cb_ex(void *__restrict userdata,
}
}
-static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata,
- void *__restrict userdata_chunk)
+static void make_histogram_view_from_ibuf_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
{
- MakeHistogramViewData *data = userdata;
- uint32_t(*bins)[HIS_STEPS] = data->bins;
-
- uint32_t(*cur_bins)[HIS_STEPS] = userdata_chunk;
+ uint32_t(*join_bins)[HIS_STEPS] = chunk_join;
+ uint32_t(*bins)[HIS_STEPS] = chunk;
for (int j = 3; j--;) {
for (int i = 0; i < HIS_STEPS; i++) {
- bins[j][i] += cur_bins[j][i];
+ join_bins[j][i] += bins[j][i];
}
}
}
@@ -488,23 +486,22 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
{
ImBuf *rval = IMB_allocImBuf(515, 128, 32, IB_rect);
int x;
- unsigned int nr, ng, nb;
+ uint nr, ng, nb;
- unsigned int bins[3][HIS_STEPS];
+ uint bins[3][HIS_STEPS];
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
- BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_cb_ex, &settings);
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
+ BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -534,7 +531,7 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf)
}
}
- wform_put_border((unsigned char *)rval->rect, rval->x, rval->y);
+ wform_put_border((uchar *)rval->rect, rval->x, rval->y);
return rval;
}
@@ -551,9 +548,9 @@ BLI_INLINE int get_bin_float(float f)
return (int)(((f + 0.25f) / 1.5f) * 512);
}
-static void make_histogram_view_from_ibuf_float_cb_ex(void *__restrict userdata,
- const int y,
- const TaskParallelTLS *__restrict tls)
+static void make_histogram_view_from_ibuf_float_fn(void *__restrict userdata,
+ const int y,
+ const TaskParallelTLS *__restrict tls)
{
const MakeHistogramViewData *data = userdata;
const ImBuf *ibuf = data->ibuf;
@@ -576,21 +573,20 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
int nr, ng, nb;
int x;
- unsigned int bins[3][HIS_STEPS];
+ uint bins[3][HIS_STEPS];
memset(bins, 0, sizeof(bins));
MakeHistogramViewData data = {
.ibuf = ibuf,
- .bins = bins,
};
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = (ibuf->y >= 256);
settings.userdata_chunk = bins;
settings.userdata_chunk_size = sizeof(bins);
- settings.func_finalize = make_histogram_view_from_ibuf_finalize;
- BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_cb_ex, &settings);
+ settings.func_reduce = make_histogram_view_from_ibuf_reduce;
+ BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings);
nr = nb = ng = 0;
for (x = 0; x < HIS_STEPS; x++) {
@@ -619,7 +615,7 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf)
draw_histogram_marker(rval, get_bin_float(0.0));
draw_histogram_marker(rval, get_bin_float(1.0));
- wform_put_border((unsigned char *)rval->rect, rval->x, rval->y);
+ wform_put_border((uchar *)rval->rect, rval->x, rval->y);
return rval;
}
@@ -636,8 +632,7 @@ ImBuf *make_histogram_view_from_ibuf(ImBuf *ibuf)
}
}
-static void vectorscope_put_cross(
- unsigned char r, unsigned char g, unsigned char b, char *tgt, int w, int h, int size)
+static void vectorscope_put_cross(uchar r, uchar g, uchar b, char *tgt, int w, int h, int size)
{
float rgb[3], yuv[3];
char *p;
@@ -676,10 +671,10 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
int w = 515;
int h = 515;
float scope_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, scope_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
}
for (x = 0; x < 256; x++) {
@@ -702,7 +697,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_byte(ImBuf *ibuf)
rgb_to_yuv_normalized(rgb, yuv);
p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
- scope_put_pixel(wtable, (unsigned char *)p);
+ scope_put_pixel(wtable, (uchar *)p);
}
}
@@ -721,10 +716,10 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
int w = 515;
int h = 515;
float scope_gamma = 0.2;
- unsigned char wtable[256];
+ uchar wtable[256];
for (x = 0; x < 256; x++) {
- wtable[x] = (unsigned char)(pow(((float)x + 1) / 256, scope_gamma) * 255);
+ wtable[x] = (uchar)(pow(((float)x + 1) / 256, scope_gamma) * 255);
}
for (x = 0; x <= 255; x++) {
@@ -748,7 +743,7 @@ static ImBuf *make_vectorscope_view_from_ibuf_float(ImBuf *ibuf)
rgb_to_yuv_normalized(rgb, yuv);
p = tgt + 4 * (w * (int)((yuv[2] * (h - 3) + 1)) + (int)((yuv[1] * (w - 3) + 1)));
- scope_put_pixel(wtable, (unsigned char *)p);
+ scope_put_pixel(wtable, (uchar *)p);
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index ccb18331c55..2e6cd7f7442 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -40,7 +40,7 @@
#include "RNA_define.h"
-/* for menu/popup icons etc etc*/
+/* For menu, popup, icons, etc. */
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -49,7 +49,7 @@
#include "UI_view2d.h"
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
@@ -147,7 +147,7 @@ static void select_active_side_range(ListBase *seqbase,
}
}
-/* used for mouse selection in SEQUENCER_OT_select */
+/* Used for mouse selection in SEQUENCER_OT_select */
static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
@@ -158,7 +158,7 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
if (left_match && right_match) {
- /* a direct match, copy the selection settinhs */
+ /* Direct match, copy the selection settings. */
seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
@@ -166,7 +166,7 @@ static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
}
else if (seq_link->flag & SELECT && (left_match || right_match)) {
- /* clear for reselection */
+ /* Clear for reselection. */
seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
if (left_match && seq_link->flag & SEQ_LEFTSEL) {
@@ -248,12 +248,11 @@ static void select_neighbor_from_last(Scene *scene, int lr)
}
}
if (changed) {
- /* pass */
+ /* Pass. */
}
}
#endif
-/* (de)select operator */
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
{
int action = RNA_enum_get(op->ptr, "action");
@@ -302,22 +301,21 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "(De)select All";
ot->idname = "SEQUENCER_OT_select_all";
ot->description = "Select or deselect all strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_de_select_all_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
WM_operator_properties_select_all(ot);
}
-/* (de)select operator */
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -343,16 +341,16 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Inverse";
ot->idname = "SEQUENCER_OT_select_inverse";
ot->description = "Select unselected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_inverse_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
}
@@ -385,18 +383,18 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
wait_to_deselect_others = false;
}
- marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now
+ marker = find_nearest_marker(SCE_MARKERS, 1); /* XXX - dummy function for now */
seq = find_nearest_seq(scene, v2d, &hand, mval);
- // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
+ /* XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip */
if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) {
left_right = SEQ_SELECT_LR_NONE;
}
if (marker) {
int oldflag;
- /* select timeline marker */
+ /* Select timeline marker. */
if (extend) {
oldflag = marker->flag;
if (oldflag & SELECT) {
@@ -414,28 +412,44 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
ret_value = OPERATOR_FINISHED;
}
+ /* Select left, right or overlapping the current frame. */
else if (left_right != SEQ_SELECT_LR_NONE) {
- /* use different logic for this */
+ /* Use different logic for this. */
float x;
if (extend == false) {
ED_sequencer_deselect_all(scene);
}
switch (left_right) {
- case SEQ_SELECT_LR_MOUSE:
+ case SEQ_SELECT_LR_MOUSE: {
+ /* 10px margin around current frame to select under the current frame with mouse. */
+ float margin = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask) * 10;
x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ if (x >= CFRA - margin && x <= CFRA + margin) {
+ x = CFRA;
+ }
break;
+ }
case SEQ_SELECT_LR_LEFT:
x = CFRA - 1.0f;
break;
case SEQ_SELECT_LR_RIGHT:
+ x = CFRA + 1.0f;
+ break;
+ case SEQ_SELECT_LR_OVERLAP:
default:
x = CFRA;
break;
}
SEQP_BEGIN (ed, seq) {
- if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) {
+ /* Select overlapping the current frame. */
+ if ((x == CFRA) && (seq->startdisp <= CFRA) && (seq->enddisp >= CFRA)) {
+ seq->flag = SELECT;
+ recurs_sel_seq(seq);
+ }
+ /* Select left or right. */
+ else if ((x < CFRA && seq->enddisp <= CFRA) || (x > CFRA && seq->startdisp >= CFRA)) {
seq->flag |= SELECT;
recurs_sel_seq(seq);
}
@@ -494,7 +508,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
}
}
- /* On Alt selection, select the strip and bordering handles */
+ /* On Alt selection, select the strip and bordering handles. */
if (linked_handle) {
if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
/* First click selects the strip and its adjacent handles (if valid).
@@ -510,7 +524,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
select_surrounding_handles(scene, seq);
}
else {
- /* always select the strip under the cursor */
+ /* Always select the strip under the cursor. */
seq->flag |= SELECT;
/* First click selects adjacent handles on that side.
@@ -629,27 +643,28 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
static const EnumPropertyItem sequencer_select_left_right_types[] = {
{SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"},
{SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"},
- {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"},
- {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
+ {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select to the left of the current frame"},
+ {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select to the right of the current frame"},
+ {SEQ_SELECT_LR_OVERLAP, "OVERLAP", 0, "Overlap", "Select overlapping the current frame"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select";
ot->idname = "SEQUENCER_OT_select";
ot->description = "Select a strip (last selected becomes the \"active strip\")";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_exec;
ot->invoke = WM_generic_select_invoke;
ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
prop = RNA_def_boolean(ot->srna,
@@ -660,7 +675,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
RNA_def_boolean(
ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
- /* for animation this is an enum but atm having an enum isn't useful for us */
+ /* For animation this is enum but atm having an enum isn't useful for us. */
RNA_def_enum(ot->srna,
"left_right",
sequencer_select_left_right_types,
@@ -671,7 +686,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
}
-/* run recursively to select linked */
+/* Run recursively to select linked. */
static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
@@ -693,7 +708,7 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
}
if (!linked) {
- /* if not linked we only want to touch each seq once, newseq */
+ /* If not linked we only want to touch each seq once, newseq. */
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
seq->tmp = NULL;
}
@@ -702,7 +717,7 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
if ((seq->flag & SELECT) == sel) {
if (linked || (seq->tmp == NULL)) {
- /* only get unselected neighbors */
+ /* Only get unselected neighbors. */
neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
if (neighbor) {
if (sel) {
@@ -738,7 +753,6 @@ static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool li
return changed;
}
-/* select more operator */
static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -756,22 +770,19 @@ static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select More";
ot->idname = "SEQUENCER_OT_select_more";
ot->description = "Select more strips adjacent to the current selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_more_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select less operator */
static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -789,22 +800,19 @@ static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Less";
ot->idname = "SEQUENCER_OT_select_less";
ot->description = "Shrink the current selection of adjacent selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_less_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select pick linked operator (uses the mouse) */
static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
@@ -815,10 +823,10 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
Sequence *mouse_seq;
int selected, hand;
- /* this works like UV, not mesh */
+ /* This works like UV, not mesh. */
mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
if (!mouse_seq) {
- return OPERATOR_FINISHED; /* user error as with mesh?? */
+ return OPERATOR_FINISHED; /* User error as with mesh?? */
}
if (extend == 0) {
@@ -842,23 +850,22 @@ static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, cons
void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Pick Linked";
ot->idname = "SEQUENCER_OT_select_linked_pick";
ot->description = "Select a chain of linked strips nearest to the mouse pointer";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_select_linked_pick_invoke;
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
}
-/* select linked operator */
static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -878,22 +885,19 @@ static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Linked";
ot->idname = "SEQUENCER_OT_select_linked";
ot->description = "Select all strips adjacent to the current selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_linked_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* properties */
}
-/* select handles operator */
static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -928,19 +932,19 @@ static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_handles(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Handles";
ot->idname = "SEQUENCER_OT_select_handles";
ot->description = "Select gizmo handles on the sides of the selected strip";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_handles_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(ot->srna,
"side",
prop_side_types,
@@ -949,7 +953,6 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
"The side of the handle that is selected");
}
-/* select side operator */
static int sequencer_select_side_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -962,7 +965,7 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
- for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (UNLIKELY(seq->machine >= MAXSEQ)) {
continue;
}
@@ -993,19 +996,19 @@ static int sequencer_select_side_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_side(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Side";
ot->idname = "SEQUENCER_OT_select_side";
ot->description = "Select strips on the nominated side of the selected strips";
- /* api callbacks */
+ /* Api callbacks. */
ot->exec = sequencer_select_side_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
RNA_def_enum(ot->srna,
"side",
prop_side_types,
@@ -1014,7 +1017,6 @@ void SEQUENCER_OT_select_side(wmOperatorType *ot)
"The side to which the selection is applied");
}
-/* box_select operator */
static int sequencer_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1037,7 +1039,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
- for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
rctf rq;
seq_rectf(seq, &rq);
if (BLI_rctf_isect(&rq, &rectf, NULL)) {
@@ -1089,7 +1091,6 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* ****** Box Select ****** */
static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
@@ -1112,12 +1113,12 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
{
PropertyRNA *prop;
- /* identifiers */
+ /* Identifiers. */
ot->name = "Box Select";
ot->idname = "SEQUENCER_OT_select_box";
ot->description = "Select strips using box selection";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = sequencer_box_select_invoke;
ot->exec = sequencer_box_select_exec;
ot->modal = WM_gesture_box_modal;
@@ -1125,10 +1126,10 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
ot->poll = ED_operator_sequencer_active;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
WM_operator_properties_gesture_box(ot);
WM_operator_properties_select_operation_simple(ot);
@@ -1140,8 +1141,6 @@ void SEQUENCER_OT_select_box(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/* ****** Selected Grouped ****** */
-
enum {
SEQ_SELECT_GROUP_TYPE,
SEQ_SELECT_GROUP_TYPE_BASIC,
@@ -1366,7 +1365,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
BKE_sequence_iterator_next(&iter)) {
seq = iter.seq;
- /* Ignore all seqs already selected! */
+ /* Ignore all seqs already selected. */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
@@ -1375,7 +1374,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
continue;
}
- /* If the seq is an effect one, we need extra checking! */
+ /* If the seq is an effect one, we need extra checking. */
if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
(seq->seq3 && seq->seq3->tmp))) {
if (startdisp > seq->startdisp) {
@@ -1398,7 +1397,7 @@ static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int
BKE_sequence_iterator_begin(ed, &iter, true);
}
- /* Video strips below active one, or any strip for audio (order do no matters here!). */
+ /* Video strips below active one, or any strip for audio (order doesn't matter here). */
else if (seq->machine < machine || is_audio) {
seq->flag |= SELECT;
changed = true;
@@ -1476,20 +1475,20 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Select Grouped";
ot->description = "Select all strips grouped by various properties";
ot->idname = "SEQUENCER_OT_select_grouped";
- /* api callbacks */
+ /* Api callbacks. */
ot->invoke = WM_menu_invoke;
ot->exec = sequencer_select_grouped_exec;
ot->poll = sequencer_edit_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
+ /* Properties. */
ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
RNA_def_boolean(ot->srna,
"extend",
diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c
index 714a634766c..d397c255b03 100644
--- a/source/blender/editors/space_sequencer/sequencer_view.c
+++ b/source/blender/editors/space_sequencer/sequencer_view.c
@@ -21,232 +21,35 @@
* \ingroup spseq
*/
-#include "MEM_guardedalloc.h"
+#include "ED_util_imbuf.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "RNA_define.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_context.h"
-#include "BKE_main.h"
-#include "BKE_screen.h"
-#include "BKE_sequencer.h"
-
-#include "WM_api.h"
#include "WM_types.h"
-#include "ED_image.h"
-#include "ED_screen.h"
-#include "ED_space_api.h"
-
-#include "IMB_colormanagement.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "UI_view2d.h"
-
-/* own include */
+/* Own include. */
#include "sequencer_intern.h"
/******************** sample backdrop operator ********************/
-
-typedef struct ImageSampleInfo {
- ARegionType *art;
- void *draw_handle;
- int x, y;
- int channels;
-
- unsigned char col[4];
- float colf[4];
- float linearcol[4];
-
- unsigned char *colp;
- const float *colfp;
-
- int draw;
- int color_manage;
-} ImageSampleInfo;
-
-static void sample_draw(const bContext *C, ARegion *region, void *arg_info)
-{
- Scene *scene = CTX_data_scene(C);
- ImageSampleInfo *info = arg_info;
-
- if (info->draw) {
- ED_image_draw_info(scene,
- region,
- info->color_manage,
- false,
- info->channels,
- info->x,
- info->y,
- info->colp,
- info->colfp,
- info->linearcol,
- NULL,
- NULL);
- }
-}
-
-static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
-{
- Main *bmain = CTX_data_main(C);
- struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- 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, depsgraph, scene, sseq, CFRA, 0, NULL);
- ImageSampleInfo *info = op->customdata;
- float fx, fy;
-
- if (ibuf == NULL) {
- IMB_freeImBuf(ibuf);
- info->draw = 0;
- return;
- }
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
-
- fx /= scene->r.xasp / scene->r.yasp;
-
- fx += (float)scene->r.xsch / 2.0f;
- fy += (float)scene->r.ysch / 2.0f;
- fx *= (float)ibuf->x / (float)scene->r.xsch;
- fy *= (float)ibuf->y / (float)scene->r.ysch;
-
- if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
- const float *fp;
- unsigned char *cp;
- int x = (int)fx, y = (int)fy;
-
- info->x = x;
- info->y = y;
- info->draw = 1;
- info->channels = ibuf->channels;
-
- info->colp = NULL;
- info->colfp = NULL;
-
- if (ibuf->rect) {
- cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
-
- info->col[0] = cp[0];
- info->col[1] = cp[1];
- info->col[2] = cp[2];
- info->col[3] = cp[3];
- info->colp = info->col;
-
- info->colf[0] = (float)cp[0] / 255.0f;
- info->colf[1] = (float)cp[1] / 255.0f;
- info->colf[2] = (float)cp[2] / 255.0f;
- info->colf[3] = (float)cp[3] / 255.0f;
- info->colfp = info->colf;
-
- copy_v4_v4(info->linearcol, info->colf);
- IMB_colormanagement_colorspace_to_scene_linear_v4(
- info->linearcol, false, ibuf->rect_colorspace);
-
- info->color_manage = true;
- }
- if (ibuf->rect_float) {
- fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
-
- info->colf[0] = fp[0];
- info->colf[1] = fp[1];
- info->colf[2] = fp[2];
- info->colf[3] = fp[3];
- info->colfp = info->colf;
-
- /* sequencer's image buffers are in non-linear space, need to make them linear */
- copy_v4_v4(info->linearcol, info->colf);
- BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol);
-
- info->color_manage = true;
- }
- }
- else {
- info->draw = 0;
- }
-
- IMB_freeImBuf(ibuf);
- ED_area_tag_redraw(CTX_wm_area(C));
-}
-
-static void sample_exit(bContext *C, wmOperator *op)
-{
- ImageSampleInfo *info = op->customdata;
-
- ED_region_draw_cb_exit(info->art, info->draw_handle);
- ED_area_tag_redraw(CTX_wm_area(C));
- MEM_freeN(info);
-}
-
-static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- ImageSampleInfo *info;
-
- if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
- return OPERATOR_CANCELLED;
- }
-
- info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
- info->art = region->type;
- info->draw_handle = ED_region_draw_cb_activate(
- region->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
- op->customdata = info;
-
- sample_apply(C, op, event);
-
- WM_event_add_modal_handler(C, op);
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static int sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- switch (event->type) {
- case LEFTMOUSE:
- case RIGHTMOUSE: /* XXX hardcoded */
- if (event->val == KM_RELEASE) {
- sample_exit(C, op);
- return OPERATOR_CANCELLED;
- }
- break;
- case MOUSEMOVE:
- sample_apply(C, op, event);
- break;
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-static void sample_cancel(bContext *C, wmOperator *op)
-{
- sample_exit(C, op);
-}
-
-static bool sample_poll(bContext *C)
-{
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL;
-}
-
void SEQUENCER_OT_sample(wmOperatorType *ot)
{
- /* identifiers */
+ /* Identifiers. */
ot->name = "Sample Color";
ot->idname = "SEQUENCER_OT_sample";
ot->description = "Use mouse to sample color in current frame";
- /* api callbacks */
- ot->invoke = sample_invoke;
- ot->modal = sample_modal;
- ot->cancel = sample_cancel;
- ot->poll = sample_poll;
+ /* Api callbacks. */
+ ot->invoke = ED_imbuf_sample_invoke;
+ ot->modal = ED_imbuf_sample_modal;
+ ot->cancel = ED_imbuf_sample_cancel;
+ ot->poll = ED_imbuf_sample_poll;
- /* flags */
+ /* Flags. */
ot->flag = OPTYPE_BLOCKING;
+
+ /* Not implemented. */
+ PropertyRNA *prop;
+ prop = RNA_def_int(ot->srna, "size", 1, 1, 128, "Sample Size", "", 1, 64);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index cff5a2c43ec..03871aeb464 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -43,7 +43,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
-#include "ED_view3d_offscreen.h" /* only for sequencer view3d drawing callback */
+#include "ED_view3d_offscreen.h" /* Only for sequencer view3d drawing callback. */
#include "WM_api.h"
#include "WM_message.h"
@@ -57,24 +57,25 @@
#include "IMB_imbuf.h"
-#include "sequencer_intern.h" // own include
+/* Own include. */
+#include "sequencer_intern.h"
/**************************** common state *****************************/
-static void sequencer_scopes_tag_refresh(ScrArea *sa)
+static void sequencer_scopes_tag_refresh(ScrArea *area)
{
- SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
+ SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
sseq->scopes.reference_ibuf = NULL;
}
/* ******************** manage regions ********************* */
-static ARegion *sequencer_find_region(ScrArea *sa, short type)
+static ARegion *sequencer_find_region(ScrArea *area, short type)
{
ARegion *region = NULL;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == type) {
return region;
}
@@ -85,7 +86,7 @@ static ARegion *sequencer_find_region(ScrArea *sa, short type)
/* ******************** default callbacks for sequencer space ***************** */
-static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *sequencer_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
SpaceSeq *sseq;
@@ -95,9 +96,9 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS;
+ sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES;
- /* tool header */
+ /* Tool header. */
region = MEM_callocN(sizeof(ARegion), "tool header for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -105,14 +106,14 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
region->flag = RGN_FLAG_HIDDEN | RGN_FLAG_HIDDEN_BY_USER;
- /* header */
+ /* Header. */
region = MEM_callocN(sizeof(ARegion), "header for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
- /* buttons/list view */
+ /* Buttons/list view. */
region = MEM_callocN(sizeof(ARegion), "buttons for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -120,7 +121,7 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = RGN_ALIGN_RIGHT;
region->flag = RGN_FLAG_HIDDEN;
- /* toolbar */
+ /* Toolbar. */
region = MEM_callocN(sizeof(ARegion), "tools for sequencer");
BLI_addtail(&sseq->regionbase, region);
@@ -128,19 +129,19 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->alignment = RGN_ALIGN_LEFT;
region->flag = RGN_FLAG_HIDDEN;
- /* preview region */
- /* NOTE: if you change values here, also change them in sequencer_init_preview_region */
+ /* Preview region. */
+ /* NOTE: if you change values here, also change them in sequencer_init_preview_region. */
region = MEM_callocN(sizeof(ARegion), "preview region for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_PREVIEW;
region->alignment = RGN_ALIGN_TOP;
region->flag |= RGN_FLAG_HIDDEN;
- /* for now, aspect ratio should be maintained, and zoom is clamped within sane default limits */
+ /* For now, aspect ratio should be maintained, and zoom is clamped within sane default limits. */
region->v2d.keepzoom = V2D_KEEPASPECT | V2D_KEEPZOOM | V2D_LIMITZOOM;
region->v2d.minzoom = 0.001f;
region->v2d.maxzoom = 1000.0f;
- region->v2d.tot.xmin = -960.0f; /* 1920 width centered */
- region->v2d.tot.ymin = -540.0f; /* 1080 height centered */
+ region->v2d.tot.xmin = -960.0f; /* 1920 width centered. */
+ region->v2d.tot.ymin = -540.0f; /* 1080 height centered. */
region->v2d.tot.xmax = 960.0f;
region->v2d.tot.ymax = 540.0f;
region->v2d.min[0] = 0.0f;
@@ -151,14 +152,13 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
region->v2d.align = V2D_ALIGN_FREE;
region->v2d.keeptot = V2D_KEEPTOT_FREE;
- /* main region */
+ /* Main region. */
region = MEM_callocN(sizeof(ARegion), "main region for sequencer");
BLI_addtail(&sseq->regionbase, region);
region->regiontype = RGN_TYPE_WINDOW;
- /* seq space goes from (0,8) to (0, efra) */
-
+ /* Seq space goes from (0,8) to (0, efra). */
region->v2d.tot.xmin = 0.0f;
region->v2d.tot.ymin = 0.0f;
region->v2d.tot.xmax = scene->r.efra;
@@ -184,13 +184,13 @@ static SpaceLink *sequencer_new(const ScrArea *UNUSED(sa), const Scene *scene)
return (SpaceLink *)sseq;
}
-/* not spacelink itself */
+/* Not spacelink itself. */
static void sequencer_free(SpaceLink *sl)
{
SpaceSeq *sseq = (SpaceSeq *)sl;
SequencerScopes *scopes = &sseq->scopes;
- // XXX if (sseq->gpd) BKE_gpencil_free(sseq->gpd);
+ /* XXX if (sseq->gpd) BKE_gpencil_free(sseq->gpd); */
if (scopes->zebra_ibuf) {
IMB_freeImBuf(scopes->zebra_ibuf);
@@ -213,98 +213,98 @@ static void sequencer_free(SpaceLink *sl)
}
}
-/* spacetype; init callback */
-static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+/* Spacetype init callback. */
+static void sequencer_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
-static void sequencer_refresh(const bContext *C, ScrArea *sa)
+static void sequencer_refresh(const bContext *C, ScrArea *area)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *window = CTX_wm_window(C);
- SpaceSeq *sseq = (SpaceSeq *)sa->spacedata.first;
- ARegion *ar_main = sequencer_find_region(sa, RGN_TYPE_WINDOW);
- ARegion *ar_preview = sequencer_find_region(sa, RGN_TYPE_PREVIEW);
+ SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
+ ARegion *region_main = sequencer_find_region(area, RGN_TYPE_WINDOW);
+ ARegion *region_preview = sequencer_find_region(area, RGN_TYPE_PREVIEW);
bool view_changed = false;
switch (sseq->view) {
case SEQ_VIEW_SEQUENCE:
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ if (region_main && (region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
view_changed = true;
}
- if (ar_preview && !(ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag |= RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_preview->handlers);
+ if (region_preview && !(region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag |= RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_preview->handlers);
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
break;
case SEQ_VIEW_PREVIEW:
- if (ar_main && !(ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag |= RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- WM_event_remove_handlers((bContext *)C, &ar_main->handlers);
+ if (region_main && !(region_main->flag & RGN_FLAG_HIDDEN)) {
+ region_main->flag |= RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ WM_event_remove_handlers((bContext *)C, &region_main->handlers);
view_changed = true;
}
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
+ if (region_preview && (region_preview->flag & RGN_FLAG_HIDDEN)) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
view_changed = true;
}
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main && region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_NONE) {
- ar_preview->alignment = RGN_ALIGN_NONE;
+ if (region_preview && region_preview->alignment != RGN_ALIGN_NONE) {
+ region_preview->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
break;
case SEQ_VIEW_SEQUENCE_PREVIEW:
- if (ar_main && ar_preview) {
+ if (region_main && region_preview) {
/* Get available height (without DPI correction). */
- const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
+ const float height = (area->winy - ED_area_headersize()) / UI_DPI_FAC;
/* We reuse hidden region's size, allows to find same layout as before if we just switch
* between one 'full window' view and the combined one. This gets lost if we switch to both
* 'full window' views before, though... Better than nothing. */
- if (ar_main->flag & RGN_FLAG_HIDDEN) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->sizey = (int)(height - ar_main->sizey);
+ if (region_main->flag & RGN_FLAG_HIDDEN) {
+ region_main->flag &= ~RGN_FLAG_HIDDEN;
+ region_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->sizey = (int)(height - region_main->sizey);
view_changed = true;
}
- if (ar_preview->flag & RGN_FLAG_HIDDEN) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
- ar_main->sizey = (int)(height - ar_preview->sizey);
+ if (region_preview->flag & RGN_FLAG_HIDDEN) {
+ region_preview->flag &= ~RGN_FLAG_HIDDEN;
+ region_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ region_preview->v2d.cur = region_preview->v2d.tot;
+ region_main->sizey = (int)(height - region_preview->sizey);
view_changed = true;
}
- if (ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
+ if (region_main->alignment != RGN_ALIGN_NONE) {
+ region_main->alignment = RGN_ALIGN_NONE;
view_changed = true;
}
- if (ar_preview->alignment != RGN_ALIGN_TOP) {
- ar_preview->alignment = RGN_ALIGN_TOP;
+ if (region_preview->alignment != RGN_ALIGN_TOP) {
+ region_preview->alignment = RGN_ALIGN_TOP;
view_changed = true;
}
- /* Final check that both preview and main height are reasonable! */
- if (ar_preview->sizey < 10 || ar_main->sizey < 10 ||
- ar_preview->sizey + ar_main->sizey > height) {
- ar_preview->sizey = (int)(height * 0.4f + 0.5f);
- ar_main->sizey = (int)(height - ar_preview->sizey);
+ /* Final check that both preview and main height are reasonable. */
+ if (region_preview->sizey < 10 || region_main->sizey < 10 ||
+ region_preview->sizey + region_main->sizey > height) {
+ region_preview->sizey = (int)(height * 0.4f + 0.5f);
+ region_main->sizey = (int)(height - region_preview->sizey);
view_changed = true;
}
}
@@ -312,8 +312,8 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa)
}
if (view_changed) {
- ED_area_initialize(wm, window, sa);
- ED_area_tag_redraw(sa);
+ ED_area_initialize(wm, window, area);
+ ED_area_tag_redraw(area);
}
}
@@ -321,8 +321,8 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
{
SpaceSeq *sseqn = MEM_dupallocN(sl);
- /* clear or remove stuff from old */
- // XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false);
+ /* Clear or remove stuff from old. */
+ /* XXX sseq->gpd = gpencil_data_duplicate(sseq->gpd, false); */
memset(&sseqn->scopes, 0, sizeof(sseqn->scopes));
@@ -330,36 +330,36 @@ static SpaceLink *sequencer_duplicate(SpaceLink *sl)
}
static void sequencer_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
case ND_SEQUENCER:
- sequencer_scopes_tag_refresh(sa);
+ sequencer_scopes_tag_refresh(area);
break;
}
break;
case NC_WINDOW:
case NC_SPACE:
if (wmn->data == ND_SPACE_SEQUENCER) {
- sequencer_scopes_tag_refresh(sa);
+ sequencer_scopes_tag_refresh(area);
}
break;
case NC_GPENCIL:
if (wmn->data & ND_GPENCIL_EDITMODE) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
}
/* DO NOT make this static, this hides the symbol and breaks API generation script. */
-extern const char *sequencer_context_dir[]; /* quiet warning. */
+extern const char *sequencer_context_dir[]; /* Quiet warning. */
const char *sequencer_context_dir[] = {"edit_mask", NULL};
static int sequencer_context(const bContext *C, const char *member, bContextDataResult *result)
@@ -396,7 +396,7 @@ static void sequencer_gizmos(void)
}
/* *********************** sequencer (main) region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_main_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -411,31 +411,31 @@ static void sequencer_main_region_init(wmWindowManager *wm, ARegion *region)
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
- /* own keymap */
+ /* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
}
+/* Strip editing timeline. */
static void sequencer_main_region_draw(const bContext *C, ARegion *region)
{
- /* NLE - strip editing timeline interface */
draw_timeline_seq(C, region);
}
static void sequencer_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_SCENE:
switch (wmn->data) {
case ND_FRAME:
case ND_FRAME_RANGE:
case ND_MARKERS:
- case ND_RENDER_OPTIONS: /* for FPS and FPS Base */
+ case ND_RENDER_OPTIONS: /* For FPS and FPS Base. */
case ND_SEQUENCER:
case ND_RENDER_RESULT:
ED_region_tag_redraw(region);
@@ -471,7 +471,7 @@ static void sequencer_main_region_message_subscribe(const struct bContext *UNUSE
struct WorkSpace *UNUSED(workspace),
struct Scene *scene,
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -526,7 +526,7 @@ static void sequencer_main_region_message_subscribe(const struct bContext *UNUSE
}
/* *********************** header region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
{
ED_region_header_init(region);
@@ -538,7 +538,7 @@ static void sequencer_header_region_draw(const bContext *C, ARegion *region)
}
/* *********************** toolbar region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_tools_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -569,15 +569,15 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region)
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
- /* own keymap */
+ /* Own keymap. */
keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
}
static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceSeq *sseq = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ SpaceSeq *sseq = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW));
@@ -618,12 +618,12 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region)
}
static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
@@ -670,7 +670,7 @@ static void sequencer_preview_region_listener(wmWindow *UNUSED(win),
/* *********************** buttons region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
+/* Add handlers, stuff you only do once or on area/region changes. */
static void sequencer_buttons_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@@ -688,12 +688,12 @@ static void sequencer_buttons_region_draw(const bContext *C, ARegion *region)
}
static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
{
- /* context changes */
+ /* Context changes. */
switch (wmn->category) {
case NC_GPENCIL:
if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) {
@@ -721,7 +721,7 @@ static void sequencer_buttons_region_listener(wmWindow *UNUSED(win),
}
}
-static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceSeq *sseq = (SpaceSeq *)slink;
@@ -793,7 +793,7 @@ static void sequencer_drop_target_find(bContext *C,
/* ************************************* */
-/* only called once, from space/spacetypes.c */
+/* Only called once, from space/spacetypes.c. */
void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
@@ -815,7 +815,8 @@ void ED_spacetype_sequencer(void)
st->id_remap = sequencer_id_remap;
st->drop_target_find = sequencer_drop_target_find;
- /* regions: main window */
+ /* Create regions: */
+ /* Main window. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_WINDOW;
art->init = sequencer_main_region_init;
@@ -823,10 +824,9 @@ void ED_spacetype_sequencer(void)
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_ANIMATION;
-
BLI_addhead(&st->regiontypes, art);
- /* preview */
+ /* Preview. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_PREVIEW;
art->init = sequencer_preview_region_init;
@@ -836,7 +836,7 @@ void ED_spacetype_sequencer(void)
ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
- /* regions: listview/buttons */
+ /* Listview/buttons. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_UI;
art->prefsizex = UI_SIDEBAR_PANEL_WIDTH * 1.3f;
@@ -848,7 +848,7 @@ void ED_spacetype_sequencer(void)
BLI_addhead(&st->regiontypes, art);
sequencer_buttons_register(art);
- /* regions: tool(bar) */
+ /* Toolbar. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tools region");
art->regionid = RGN_TYPE_TOOLS;
art->prefsizex = 58; /* XXX */
@@ -860,7 +860,7 @@ void ED_spacetype_sequencer(void)
art->draw = sequencer_tools_region_draw;
BLI_addhead(&st->regiontypes, art);
- /* regions: tool header */
+ /* Tool header. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer tool header region");
art->regionid = RGN_TYPE_TOOL_HEADER;
art->prefsizey = HEADERY;
@@ -871,7 +871,7 @@ void ED_spacetype_sequencer(void)
art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
BLI_addhead(&st->regiontypes, art);
- /* regions: header */
+ /* Header. */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
@@ -880,17 +880,16 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_header_region_init;
art->draw = sequencer_header_region_draw;
art->listener = sequencer_main_region_listener;
-
BLI_addhead(&st->regiontypes, art);
- /* regions: hud */
+ /* Hud. */
art = ED_area_type_hud(st->spaceid);
BLI_addhead(&st->regiontypes, art);
BKE_spacetype_register(st);
- /* set the sequencer callback when not in background mode */
+ /* Set the sequencer callback when not in background mode. */
if (G.background == 0) {
- sequencer_view3d_cb = ED_view3d_draw_offscreen_imbuf_simple;
+ sequencer_view3d_fn = ED_view3d_draw_offscreen_imbuf_simple;
}
}
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
index 1efb18403de..34d7f8b0216 100644
--- a/source/blender/editors/space_statusbar/space_statusbar.c
+++ b/source/blender/editors/space_statusbar/space_statusbar.c
@@ -65,7 +65,7 @@ static void statusbar_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -96,7 +96,7 @@ static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
}
static void statusbar_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -135,7 +135,7 @@ static void statusbar_header_region_message_subscribe(const bContext *UNUSED(C),
WorkSpace *UNUSED(workspace),
Scene *UNUSED(scene),
bScreen *UNUSED(screen),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index c695fdc72e6..11e1d16fdc7 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -107,7 +107,7 @@ static void text_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void text_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void text_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -123,11 +123,11 @@ static SpaceLink *text_duplicate(SpaceLink *sl)
}
static void text_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
wmNotifier *wmn,
Scene *UNUSED(scene))
{
- SpaceText *st = sa->spacedata.first;
+ SpaceText *st = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -141,14 +141,14 @@ static void text_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_DISPLAY:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case ND_CURSOR:
if (st->text && st->text == wmn->reference) {
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
}
@@ -159,15 +159,15 @@ static void text_listener(wmWindow *UNUSED(win),
text_update_edited(st->text);
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
ATTR_FALLTHROUGH; /* fall down to tag redraw */
case NA_ADDED:
case NA_REMOVED:
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
break;
case NA_SELECTED:
if (st->text && st->text == wmn->reference) {
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
break;
@@ -176,7 +176,7 @@ static void text_listener(wmWindow *UNUSED(win),
break;
case NC_SPACE:
if (wmn->data == ND_SPACE_TEXT) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
break;
}
@@ -303,9 +303,9 @@ static void text_main_region_draw(const bContext *C, ARegion *region)
/* scrollers? */
}
-static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+static void text_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- SpaceText *st = sa->spacedata.first;
+ SpaceText *st = area->spacedata.first;
int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text && BLI_rcti_isect_pt(&st->runtime.scroll_region_handle,
@@ -355,14 +355,14 @@ static void text_properties_region_draw(const bContext *C, ARegion *region)
if (st->flags & ST_FIND_ACTIVATE) {
if (UI_textbutton_activate_rna(C, region, st, "find_text")) {
/* if the panel was already open we need to do another redraw */
- ScrArea *sa = CTX_wm_area(C);
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_TEXT, sa);
+ ScrArea *area = CTX_wm_area(C);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_TEXT, area);
}
st->flags &= ~ST_FIND_ACTIVATE;
}
}
-static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id)
+static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id)
{
SpaceText *stext = (SpaceText *)slink;
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index cb1861d8726..1f034bdbd09 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -335,8 +335,8 @@ static int doc_scroll = 0;
static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceText *st = CTX_wm_space_text(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
int draw = 0, tools = 0, swallow = 0, scroll = 1;
Text *text = CTX_data_edit_text(C);
@@ -577,7 +577,7 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e
}
if (draw) {
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
// if (swallow) {
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 777b6b1ef1d..a0339b35c57 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -1812,7 +1812,7 @@ void text_scroll_to_cursor(SpaceText *st, ARegion *region, const bool center)
}
/* takes an area instead of a region, use for listeners */
-void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
+void text_scroll_to_cursor__area(SpaceText *st, ScrArea *area, const bool center)
{
ARegion *region;
@@ -1820,7 +1820,7 @@ void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
return;
}
- region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
if (region) {
text_scroll_to_cursor(st, region, center);
@@ -1829,10 +1829,10 @@ void text_scroll_to_cursor__area(SpaceText *st, ScrArea *sa, const bool center)
void text_update_cursor_moved(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
SpaceText *st = CTX_wm_space_text(C);
- text_scroll_to_cursor__area(st, sa, true);
+ text_scroll_to_cursor__area(st, area, true);
}
/**
diff --git a/source/blender/editors/space_text/text_format.c b/source/blender/editors/space_text/text_format.c
index 2eeb46049d2..bdbf55d9198 100644
--- a/source/blender/editors/space_text/text_format.c
+++ b/source/blender/editors/space_text/text_format.c
@@ -121,7 +121,7 @@ int flatten_string_strlen(FlattenString *fs, const char *str)
/* Ensures the format string for the given line is long enough, reallocating
* as needed. Allocation is done here, alone, to ensure consistency. */
-int text_check_format_len(TextLine *line, unsigned int len)
+int text_check_format_len(TextLine *line, uint len)
{
if (line->format) {
if (strlen(line->format) < len) {
diff --git a/source/blender/editors/space_text/text_header.c b/source/blender/editors/space_text/text_header.c
index da39ba3c5ad..c4052fcef84 100644
--- a/source/blender/editors/space_text/text_header.c
+++ b/source/blender/editors/space_text/text_header.c
@@ -42,17 +42,17 @@
/************************** properties ******************************/
-static ARegion *text_has_properties_region(ScrArea *sa)
+static ARegion *text_has_properties_region(ScrArea *area)
{
ARegion *region, *arnew;
- region = BKE_area_find_region_type(sa, RGN_TYPE_UI);
+ region = BKE_area_find_region_type(area, RGN_TYPE_UI);
if (region) {
return region;
}
/* add subdiv level; after header */
- region = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ region = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
/* is error! */
if (region == NULL) {
@@ -61,7 +61,7 @@ static ARegion *text_has_properties_region(ScrArea *sa)
arnew = MEM_callocN(sizeof(ARegion), "properties region");
- BLI_insertlinkafter(&sa->regionbase, region, arnew);
+ BLI_insertlinkafter(&area->regionbase, region, arnew);
arnew->regiontype = RGN_TYPE_UI;
arnew->alignment = RGN_ALIGN_LEFT;
@@ -77,8 +77,8 @@ static bool text_properties_poll(bContext *C)
static int text_text_search_exec(bContext *C, wmOperator *UNUSED(op))
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *region = text_has_properties_region(sa);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = text_has_properties_region(area);
SpaceText *st = CTX_wm_space_text(C);
if (region) {
diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h
index 5ad6a554188..d6588dda797 100644
--- a/source/blender/editors/space_text/text_intern.h
+++ b/source/blender/editors/space_text/text_intern.h
@@ -41,20 +41,20 @@ void text_update_line_edited(struct TextLine *line);
void text_update_edited(struct Text *text);
void text_update_character_width(struct SpaceText *st);
void text_scroll_to_cursor(struct SpaceText *st, struct ARegion *region, const bool center);
-void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *sa, const bool center);
+void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center);
void text_update_cursor_moved(struct bContext *C);
/* Padding around line numbers in character widths. */
#define TXT_NUMCOL_PAD 1.0f
/* Total width of the optional line numbers column. */
#define TXT_NUMCOL_WIDTH(st) \
- (st->runtime.cwidth_px * (st->runtime.line_number_display_digits + (2 * TXT_NUMCOL_PAD)))
+ ((st)->runtime.cwidth_px * ((st)->runtime.line_number_display_digits + (2 * TXT_NUMCOL_PAD)))
/* Padding on left of body text in character units. */
#define TXT_BODY_LPAD 1.0f
/* Left position of body text. */
#define TXT_BODY_LEFT(st) \
- (st->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * st->runtime.cwidth_px)
+ ((st)->showlinenrs ? TXT_NUMCOL_WIDTH(st) : 0) + (TXT_BODY_LPAD * (st)->runtime.cwidth_px)
#define TXT_SCROLL_WIDTH U.widget_unit
#define TXT_SCROLL_SPACE ((int)(0.1f * U.widget_unit))
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index e0b15d0a9d5..fa378954a30 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2902,7 +2902,6 @@ void TEXT_OT_scroll_bar(wmOperatorType *ot)
* \{ */
typedef struct SetSelection {
- int selecting;
int selc, sell;
short mval_prev[2];
wmTimer *timer; /* needed for scrolling when mouse at region bounds */
@@ -3420,7 +3419,7 @@ static int text_insert_exec(bContext *C, wmOperator *op)
char *str;
bool done = false;
size_t i = 0;
- unsigned int code;
+ uint code;
text_drawcache_tag_update(st, 0);
diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c
index cacf956aa84..d06c567988d 100644
--- a/source/blender/editors/space_topbar/space_topbar.c
+++ b/source/blender/editors/space_topbar/space_topbar.c
@@ -84,7 +84,7 @@ static void topbar_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void topbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -130,7 +130,7 @@ static void topbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *regi
}
static void topbar_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -161,7 +161,7 @@ static void topbar_main_region_listener(wmWindow *UNUSED(win),
}
static void topbar_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -195,7 +195,7 @@ static void topbar_header_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *workspace,
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c
index d3bea4598ff..9eae722d5c8 100644
--- a/source/blender/editors/space_userpref/space_userpref.c
+++ b/source/blender/editors/space_userpref/space_userpref.c
@@ -97,7 +97,7 @@ static void userpref_free(SpaceLink *UNUSED(sl))
}
/* spacetype; init callback */
-static void userpref_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void userpref_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -185,7 +185,7 @@ static void userpref_execute_region_init(wmWindowManager *wm, ARegion *region)
}
static void userpref_main_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -194,7 +194,7 @@ static void userpref_main_region_listener(wmWindow *UNUSED(win),
}
static void userpref_header_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -209,7 +209,7 @@ static void userpref_header_listener(wmWindow *UNUSED(win),
}
static void userpref_navigation_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
@@ -218,7 +218,7 @@ static void userpref_navigation_region_listener(wmWindow *UNUSED(win),
}
static void userpref_execute_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *UNUSED(region),
wmNotifier *UNUSED(wmn),
const Scene *UNUSED(scene))
diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c
index 1ec459ccfca..d823530fd89 100644
--- a/source/blender/editors/space_userpref/userpref_ops.c
+++ b/source/blender/editors/space_userpref/userpref_ops.c
@@ -25,11 +25,15 @@
#include "DNA_screen_types.h"
+#include "BLI_listbase.h"
+
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
#include "RNA_types.h"
#include "UI_interface.h"
@@ -41,11 +45,13 @@
#include "ED_userpref.h"
+#include "MEM_guardedalloc.h"
+
/* -------------------------------------------------------------------- */
-/** \name Reset Default Theme
+/** \name Reset Default Theme Operator
* \{ */
-static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
+static int preferences_reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op))
{
Main *bmain = CTX_data_main(C);
UI_theme_init_default();
@@ -64,7 +70,7 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot)
ot->description = "Reset to the default theme colors";
/* callbacks */
- ot->exec = reset_default_theme_exec;
+ ot->exec = preferences_reset_default_theme_exec;
/* flags */
ot->flag = OPTYPE_REGISTER;
@@ -72,7 +78,64 @@ static void PREFERENCES_OT_reset_default_theme(wmOperatorType *ot)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Add Auto-Execution Path Operator
+ * \{ */
+
+static int preferences_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
+ BLI_addtail(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
+ return OPERATOR_FINISHED;
+}
+
+static void PREFERENCES_OT_autoexec_path_add(wmOperatorType *ot)
+{
+ ot->name = "Add Autoexec Path";
+ ot->idname = "PREFERENCES_OT_autoexec_path_add";
+ ot->description = "Add path to exclude from auto-execution";
+
+ ot->exec = preferences_autoexec_add_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Auto-Execution Path Operator
+ * \{ */
+
+static int preferences_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
+{
+ const int index = RNA_int_get(op->ptr, "index");
+ bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
+ if (path_cmp) {
+ BLI_freelinkN(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
+ }
+ return OPERATOR_FINISHED;
+}
+
+static void PREFERENCES_OT_autoexec_path_remove(wmOperatorType *ot)
+{
+ ot->name = "Remove Autoexec Path";
+ ot->idname = "PREFERENCES_OT_autoexec_path_remove";
+ ot->description = "Remove path to exclude from auto-execution";
+
+ ot->exec = preferences_autoexec_remove_exec;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
+}
+
+/** \} */
+
void ED_operatortypes_userpref(void)
{
WM_operatortype_append(PREFERENCES_OT_reset_default_theme);
+ WM_operatortype_append(PREFERENCES_OT_autoexec_path_add);
+ WM_operatortype_append(PREFERENCES_OT_autoexec_path_remove);
}
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index c7fe82e0cbb..f2536cfac62 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -64,6 +64,7 @@ set(SRC
view3d_header.c
view3d_iterators.c
view3d_ops.c
+ view3d_placement.c
view3d_project.c
view3d_select.c
view3d_snap.c
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index d469faac934..5daba238293 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -88,9 +88,9 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
RegionView3D *rv3d = CTX_wm_region_view3d(C);
if (rv3d == NULL) {
- ScrArea *sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_VIEW3D) {
- ARegion *region = BKE_area_find_region_active_win(sa);
+ ScrArea *area = CTX_wm_area(C);
+ if (area && area->spacetype == SPACE_VIEW3D) {
+ ARegion *region = BKE_area_find_region_active_win(area);
if (region) {
rv3d = region->regiondata;
}
@@ -101,27 +101,27 @@ RegionView3D *ED_view3d_context_rv3d(bContext *C)
/* ideally would return an rv3d but in some cases the region is needed too
* so return that, the caller can then access the region->regiondata */
-bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
+bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_region)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
*r_v3d = NULL;
- *r_ar = NULL;
+ *r_region = NULL;
- if (sa && sa->spacetype == SPACE_VIEW3D) {
+ if (area && area->spacetype == SPACE_VIEW3D) {
ARegion *region = CTX_wm_region(C);
- View3D *v3d = (View3D *)sa->spacedata.first;
+ View3D *v3d = (View3D *)area->spacedata.first;
if (region) {
RegionView3D *rv3d;
if ((region->regiontype == RGN_TYPE_WINDOW) && (rv3d = region->regiondata) &&
(rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
*r_v3d = v3d;
- *r_ar = region;
+ *r_region = region;
return true;
}
else {
- if (ED_view3d_area_user_region(sa, v3d, r_ar)) {
+ if (ED_view3d_area_user_region(area, v3d, r_region)) {
*r_v3d = v3d;
return true;
}
@@ -136,23 +136,24 @@ bool ED_view3d_context_user_region(bContext *C, View3D **r_v3d, ARegion **r_ar)
* Similar to #ED_view3d_context_user_region() but does not use context. Always performs a lookup.
* Also works if \a v3d is not the active space.
*/
-bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **r_ar)
+bool ED_view3d_area_user_region(const ScrArea *area, const View3D *v3d, ARegion **r_region)
{
RegionView3D *rv3d = NULL;
- ARegion *ar_unlock_user = NULL;
- ARegion *ar_unlock = NULL;
- const ListBase *region_list = (v3d == sa->spacedata.first) ? &sa->regionbase : &v3d->regionbase;
+ ARegion *region_unlock_user = NULL;
+ ARegion *region_unlock = NULL;
+ const ListBase *region_list = (v3d == area->spacedata.first) ? &area->regionbase :
+ &v3d->regionbase;
BLI_assert(v3d->spacetype == SPACE_VIEW3D);
- for (ARegion *region = region_list->first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, region_list) {
/* find the first unlocked rv3d */
if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
rv3d = region->regiondata;
if ((rv3d->viewlock & RV3D_LOCK_ROTATION) == 0) {
- ar_unlock = region;
+ region_unlock = region;
if (rv3d->persp == RV3D_PERSP || rv3d->persp == RV3D_CAMOB) {
- ar_unlock_user = region;
+ region_unlock_user = region;
break;
}
}
@@ -160,13 +161,13 @@ bool ED_view3d_area_user_region(const ScrArea *sa, const View3D *v3d, ARegion **
}
/* camera/perspective view get priority when the active region is locked */
- if (ar_unlock_user) {
- *r_ar = ar_unlock_user;
+ if (region_unlock_user) {
+ *r_region = region_unlock_user;
return true;
}
- if (ar_unlock) {
- *r_ar = ar_unlock;
+ if (region_unlock) {
+ *r_region = region_unlock;
return true;
}
@@ -237,16 +238,19 @@ void ED_view3d_stop_render_preview(wmWindowManager *wm, ARegion *region)
RE_engine_free(rv3d->render_engine);
rv3d->render_engine = NULL;
}
+
+ /* A bit overkill but this make sure the viewport is reset completely. (fclem) */
+ WM_draw_region_free(region, false);
}
-void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
+void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *area)
{
wmWindowManager *wm = bmain->wm.first;
if (v3d->shading.type != OB_RENDER) {
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if ((region->regiontype == RGN_TYPE_WINDOW) && region->regiondata) {
ED_view3d_stop_render_preview(wm, region);
break;
@@ -257,7 +261,7 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
/* ******************** default callbacks for view3d space ***************** */
-static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
+static SpaceLink *view3d_new(const ScrArea *UNUSED(area), const Scene *scene)
{
ARegion *region;
View3D *v3d;
@@ -336,7 +340,7 @@ static void view3d_free(SpaceLink *sl)
}
/* spacetype; init callback */
-static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+static void view3d_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area))
{
}
@@ -500,6 +504,8 @@ static void view3d_widgets(void)
WM_gizmogrouptype_append(VIEW3D_GGT_ruler);
WM_gizmotype_append(VIEW3D_GT_ruler_item);
+ WM_gizmogrouptype_append(VIEW3D_GGT_placement);
+
WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_navigate);
WM_gizmotype_append(VIEW3D_GT_navigate_rotate);
}
@@ -561,9 +567,9 @@ static void *view3d_main_region_duplicate(void *poin)
}
static void view3d_main_region_listener(
- wmWindow *UNUSED(win), ScrArea *sa, ARegion *region, wmNotifier *wmn, const Scene *scene)
+ wmWindow *UNUSED(win), ScrArea *area, ARegion *region, wmNotifier *wmn, const Scene *scene)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
wmGizmoMap *gzmap = region->gizmo_map;
@@ -756,7 +762,7 @@ static void view3d_main_region_listener(
}
break;
case NC_LIGHTPROBE:
- ED_area_tag_refresh(sa);
+ ED_area_tag_refresh(area);
break;
case NC_IMAGE:
/* this could be more fine grained checks if we had
@@ -821,7 +827,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *sa,
+ struct ScrArea *area,
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -899,7 +905,7 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
{
wmMsgSubscribeValue msg_sub_value_region_tag_refresh = {
.owner = region,
- .user_data = sa,
+ .user_data = area,
.notify = WM_toolsystem_do_msg_notify_tag_refresh,
};
WM_msg_subscribe_rna_anon_prop(mbus, Object, mode, &msg_sub_value_region_tag_refresh);
@@ -907,9 +913,19 @@ static void view3d_main_region_message_subscribe(const struct bContext *C,
}
}
-static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *region)
+/* concept is to retrieve cursor type context-less */
+static void view3d_main_region_cursor(wmWindow *win, ScrArea *area, ARegion *region)
{
- if (!WM_cursor_set_from_tool(win, sa, region)) {
+ if (WM_cursor_set_from_tool(win, area, region)) {
+ return;
+ }
+
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
+ if (obedit) {
+ WM_cursor_set(win, WM_CURSOR_EDIT);
+ }
+ else {
WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -930,7 +946,7 @@ static void view3d_header_region_draw(const bContext *C, ARegion *region)
}
static void view3d_header_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1003,7 +1019,7 @@ static void view3d_header_region_message_subscribe(const struct bContext *UNUSED
struct WorkSpace *UNUSED(workspace),
struct Scene *UNUSED(scene),
struct bScreen *UNUSED(screen),
- struct ScrArea *UNUSED(sa),
+ struct ScrArea *UNUSED(area),
struct ARegion *region,
struct wmMsgBus *mbus)
{
@@ -1147,7 +1163,7 @@ static void view3d_buttons_region_layout(const bContext *C, ARegion *region)
}
static void view3d_buttons_region_listener(wmWindow *UNUSED(win),
- ScrArea *UNUSED(sa),
+ ScrArea *UNUSED(area),
ARegion *region,
wmNotifier *wmn,
const Scene *UNUSED(scene))
@@ -1270,11 +1286,11 @@ static void view3d_tools_region_draw(const bContext *C, ARegion *region)
/* area (not region) level listener */
static void space_view3d_listener(wmWindow *UNUSED(win),
- ScrArea *sa,
+ ScrArea *area,
struct wmNotifier *wmn,
Scene *UNUSED(scene))
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
/* context changes */
switch (wmn->category) {
@@ -1282,7 +1298,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_WORLD:
if (v3d->flag2 & V3D_HIDE_OVERLAYS) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1292,7 +1308,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
case ND_WORLD_DRAW:
case ND_WORLD:
if (v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1301,7 +1317,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
switch (wmn->data) {
case ND_NODES:
if (v3d->shading.type == OB_TEXTURE) {
- ED_area_tag_redraw_regiontype(sa, RGN_TYPE_WINDOW);
+ ED_area_tag_redraw_regiontype(area, RGN_TYPE_WINDOW);
}
break;
}
@@ -1309,7 +1325,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win),
}
}
-static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa))
+static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(area))
{
Scene *scene = CTX_data_scene(C);
LightCache *lcache = scene->eevee.light_cache_data;
@@ -1367,7 +1383,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
return -1; /* found but not available */
}
-static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id)
+static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id)
{
View3D *v3d;
ARegion *region;
@@ -1382,8 +1398,8 @@ static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_i
v3d->camera = (Object *)new_id;
if (!new_id) {
/* 3D view might be inactive, in that case needs to use slink->regionbase */
- ListBase *regionbase = (slink == sa->spacedata.first) ? &sa->regionbase :
- &slink->regionbase;
+ ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase :
+ &slink->regionbase;
for (region = regionbase->first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd :
diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c
index 80ab18cd3db..cb87ddafea1 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -1005,7 +1005,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
}
BKE_nurb_test_2d(nu);
- BKE_nurb_handles_test(nu, true); /* test for bezier too */
+ BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
nu = nu->next;
}
@@ -1140,9 +1140,9 @@ static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt))
return false;
}
-static void view3d_panel_vgroup(const bContext *C, Panel *pa)
+static void view3d_panel_vgroup(const bContext *C, Panel *panel)
{
- uiBlock *block = uiLayoutAbsoluteBlock(pa->layout);
+ uiBlock *block = uiLayoutAbsoluteBlock(panel->layout);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = view_layer->basact->object;
@@ -1171,7 +1171,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
UI_block_func_handle_set(block, do_view3d_vgroup_buttons, NULL);
- bcol = uiLayoutColumn(pa->layout, true);
+ bcol = uiLayoutColumn(panel->layout, true);
row = uiLayoutRow(bcol, true); /* The filter button row */
RNA_pointer_create(NULL, &RNA_ToolSettings, ts, &tools_ptr);
@@ -1269,7 +1269,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa)
yco -= 2;
- col = uiLayoutColumn(pa->layout, true);
+ col = uiLayoutColumn(panel->layout, true);
row = uiLayoutRow(col, true);
ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", 1);
@@ -1555,7 +1555,7 @@ static bool view3d_panel_transform_poll(const bContext *C, PanelType *UNUSED(pt)
return (view_layer->basact != NULL);
}
-static void view3d_panel_transform(const bContext *C, Panel *pa)
+static void view3d_panel_transform(const bContext *C, Panel *panel)
{
uiBlock *block;
ViewLayer *view_layer = CTX_data_view_layer(C);
@@ -1563,10 +1563,10 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
Object *obedit = OBEDIT_FROM_OBACT(ob);
uiLayout *col;
- block = uiLayoutGetBlock(pa->layout);
+ block = uiLayoutGetBlock(panel->layout);
UI_block_func_handle_set(block, do_view3d_region_buttons, NULL);
- col = uiLayoutColumn(pa->layout, false);
+ col = uiLayoutColumn(panel->layout, false);
if (ob == obedit) {
if (ob->type == OB_ARMATURE) {
@@ -1577,9 +1577,7 @@ static void view3d_panel_transform(const bContext *C, Panel *pa)
}
else {
View3D *v3d = CTX_wm_view3d(C);
- Scene *scene = CTX_data_scene(C);
- const float lim = 10000.0f * max_ff(1.0f, ED_view3d_grid_scale(scene, v3d, NULL));
- v3d_editvertex_buts(col, v3d, ob, lim);
+ v3d_editvertex_buts(col, v3d, ob, FLT_MAX);
}
}
else if (ob->mode & OB_MODE_POSE) {
@@ -1644,7 +1642,7 @@ static int view3d_object_mode_menu(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else if (((ob->mode & OB_MODE_EDIT) == 0) && (ELEM(ob->type, OB_ARMATURE))) {
- ED_object_mode_toggle(C, OB_MODE_POSE);
+ ED_object_mode_set(C, (ob->mode == OB_MODE_OBJECT) ? OB_MODE_POSE : OB_MODE_OBJECT);
return OPERATOR_CANCELLED;
}
else {
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 694cb7ee7d4..fac378ae104 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -63,6 +63,7 @@
#include "ED_armature.h"
#include "ED_gpencil.h"
+#include "ED_info.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
@@ -101,6 +102,8 @@
#define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f
+#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit)
+
/* -------------------------------------------------------------------- */
/** \name General Functions
* \{ */
@@ -1341,7 +1344,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr));
@@ -1473,7 +1476,7 @@ static void draw_selected_name(
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info));
BLF_disable(font_id, BLF_SHADOW);
@@ -1494,7 +1497,7 @@ static void draw_grid_unit_name(
BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
BLF_enable(font_id, BLF_SHADOW);
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
@@ -1515,6 +1518,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C);
+ Main *bmain = CTX_data_main(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
#ifdef WITH_INPUT_NDOF
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) &&
@@ -1550,8 +1555,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
}
- int xoffset = rect->xmin + U.widget_unit;
- int yoffset = rect->ymax;
+ int xoffset = rect->xmin + (0.5f * U.widget_unit);
+ int yoffset = rect->ymax - (0.1f * U.widget_unit);
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) {
@@ -1562,7 +1567,6 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
}
if (U.uiflag & USER_DRAWVIEWINFO) {
- ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
draw_selected_name(scene, view_layer, ob, xoffset, &yoffset);
}
@@ -1571,10 +1575,12 @@ void view3d_draw_region_info(const bContext *C, ARegion *region)
/* draw below the viewport name */
draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset);
}
+
+ DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
- if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) {
- DRW_draw_region_engine_info(xoffset, yoffset);
+ if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) {
+ ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT);
}
BLF_batch_draw_end();
@@ -2217,7 +2223,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(region);
- DRW_draw_depth_object(vc->region, vc->v3d, viewport, obact_eval);
+ DRW_draw_depth_object(vc->scene, vc->region, vc->v3d, viewport, obact_eval);
}
vc->v3d->flag &= ~V3D_INVALID_BACKBUF;
@@ -2396,9 +2402,9 @@ void ED_view3d_screen_datamask(const bContext *C,
CustomData_MeshMasks_update(r_cddata_masks, &CD_MASK_BAREMESH);
/* Check if we need tfaces & mcols due to view mode. */
- for (const ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ED_view3d_datamask(C, scene, sa->spacedata.first, r_cddata_masks);
+ LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
+ if (area->spacetype == SPACE_VIEW3D) {
+ ED_view3d_datamask(C, scene, area->spacedata.first, r_cddata_masks);
}
}
}
@@ -2493,7 +2499,7 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset)
BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f});
BLF_shadow_offset(font_id, 1, -1);
- *yoffset -= U.widget_unit;
+ *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT;
#ifdef WITH_INTERNATIONAL
BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable));
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 67dacca85ba..edd75d8e561 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -175,7 +175,7 @@ typedef struct ViewOpsData {
/** Context pointers (assigned by #viewops_data_alloc). */
Main *bmain;
Scene *scene;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
View3D *v3d;
RegionView3D *rv3d;
@@ -277,9 +277,9 @@ static void viewops_data_alloc(bContext *C, wmOperator *op)
vod->bmain = CTX_data_main(C);
vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
vod->scene = CTX_data_scene(C);
- vod->sa = CTX_wm_area(C);
+ vod->area = CTX_wm_area(C);
vod->region = CTX_wm_region(C);
- vod->v3d = vod->sa->spacedata.first;
+ vod->v3d = vod->area->spacedata.first;
vod->rv3d = vod->region->regiondata;
}
@@ -529,10 +529,10 @@ static void viewops_data_create(bContext *C,
negate_v3_v3(rv3d->ofs, dvec);
}
else {
- const float mval_ar_mid[2] = {(float)vod->region->winx / 2.0f,
- (float)vod->region->winy / 2.0f};
+ const float mval_region_mid[2] = {(float)vod->region->winx / 2.0f,
+ (float)vod->region->winy / 2.0f};
- ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_ar_mid, rv3d->ofs);
+ ED_view3d_win_to_3d(vod->v3d, vod->region, vod->dyn_ofs, mval_region_mid, rv3d->ofs);
negate_v3(rv3d->ofs);
}
negate_v3(vod->dyn_ofs);
@@ -627,14 +627,14 @@ void viewrotate_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Rotate Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Rotate Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -1120,7 +1120,7 @@ static float view3d_ndof_pan_speed_calc(RegionView3D *rv3d)
* often `!rv3d->is_persp` since it doesn't make sense to dolly in ortho.
*/
static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
const bool has_translate,
const bool has_zoom)
@@ -1161,7 +1161,7 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
/* all callers must check */
if (has_translate) {
- BLI_assert(ED_view3d_offset_lock_check((View3D *)sa->spacedata.first, rv3d) == false);
+ BLI_assert(ED_view3d_offset_lock_check((View3D *)area->spacedata.first, rv3d) == false);
}
}
@@ -1178,18 +1178,18 @@ static void view3d_ndof_pan_zoom(const struct wmNDOFMotionData *ndof,
sub_v3_v3(rv3d->ofs, pan_vec);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
}
}
static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
ViewOpsData *vod,
const bool apply_dyn_ofs)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
float view_inv[4];
@@ -1422,12 +1422,12 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool has_zoom = (ndof->tvec[2] != 0.0f) && !rv3d->is_persp;
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
if (has_rotation) {
- view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, true);
+ view3d_ndof_orbit(ndof, vod->area, vod->region, vod, true);
xform_flag |= HAS_ROTATE;
}
}
@@ -1505,7 +1505,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const bool has_zoom = (ndof->tvec[2] != 0.0f) && ED_view3d_offset_lock_check(v3d, rv3d);
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, true);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, true);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1535,7 +1535,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
if (!is_orbit_around_pivot) {
ED_view3d_distance_set(rv3d, 0.0f);
}
- view3d_ndof_orbit(ndof, vod->sa, vod->region, vod, is_orbit_around_pivot);
+ view3d_ndof_orbit(ndof, vod->area, vod->region, vod, is_orbit_around_pivot);
xform_flag |= HAS_ROTATE;
if (!is_orbit_around_pivot) {
ED_view3d_distance_set(rv3d, dist_backup);
@@ -1543,7 +1543,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
}
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, vod->sa, vod->region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, vod->area, vod->region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1607,11 +1607,11 @@ static int ndof_pan_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *e
ED_view3d_camera_lock_init_ex(depsgraph, v3d, rv3d, false);
if (ndof->progress != P_FINISHING) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
if (has_translate || has_zoom) {
- view3d_ndof_pan_zoom(ndof, sa, region, has_translate, has_zoom);
+ view3d_ndof_pan_zoom(ndof, area, region, has_translate, has_zoom);
xform_flag |= HAS_TRANSLATE;
}
}
@@ -1702,14 +1702,14 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Move Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Move Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Move Modal", modal_items);
/* items for modal map */
WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
@@ -1751,7 +1751,7 @@ static void viewmove_apply(ViewOpsData *vod, int x, int y)
add_v3_v3(vod->rv3d->ofs, dvec);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
}
@@ -1901,14 +1901,14 @@ void viewzoom_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Zoom Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Zoom Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -2189,7 +2189,7 @@ static void viewzoom_apply_3d(ViewOpsData *vod,
CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -2280,7 +2280,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
bool use_cam_zoom;
float dist_range[2];
@@ -2291,15 +2291,15 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
if (op->customdata) {
ViewOpsData *vod = op->customdata;
- sa = vod->sa;
+ area = vod->area;
region = vod->region;
}
else {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
region = CTX_wm_region(C);
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
rv3d = region->regiondata;
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
@@ -2342,7 +2342,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
ED_view3d_depth_tag_update(rv3d);
@@ -2472,14 +2472,14 @@ void viewdolly_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Dolly Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Dolly Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Dolly Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Dolly Modal", modal_items);
/* disabled mode switching for now, can re-implement better, later on */
#if 0
@@ -2538,7 +2538,7 @@ static void viewdolly_apply(ViewOpsData *vod, const int xy[2], const short zoom_
}
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -2603,7 +2603,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
RegionView3D *rv3d;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region;
float mousevec[3];
@@ -2612,18 +2612,18 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
if (op->customdata) {
ViewOpsData *vod = op->customdata;
- sa = vod->sa;
+ area = vod->area;
region = vod->region;
copy_v3_v3(mousevec, vod->init.mousevec);
}
else {
- sa = CTX_wm_area(C);
+ area = CTX_wm_area(C);
region = CTX_wm_region(C);
negate_v3_v3(mousevec, ((RegionView3D *)region->regiondata)->viewinv[2]);
normalize_v3(mousevec);
}
- v3d = sa->spacedata.first;
+ v3d = area->spacedata.first;
rv3d = region->regiondata;
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
@@ -2636,7 +2636,7 @@ static int viewdolly_exec(bContext *C, wmOperator *op)
view_dolly_to_vector_3d(region, rv3d->ofs, mousevec, delta < 0 ? 0.2f : 1.8f);
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, region);
+ view3d_boxview_sync(area, region);
}
ED_view3d_depth_tag_update(rv3d);
@@ -2886,9 +2886,9 @@ static void view3d_from_minmax_multi(bContext *C,
const bool ok_dist,
const int smooth_viewtx)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
/* when using all regions, don't jump out of camera view,
@@ -2980,7 +2980,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_view_all(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View All";
+ ot->name = "Frame All";
ot->description = "View all objects in scene";
ot->idname = "VIEW3D_OT_view_all";
@@ -3349,7 +3349,7 @@ void VIEW3D_OT_view_center_pick(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name View Camera Center Operator
+/** \name Frame Camera Bounds Operator
* \{ */
static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op))
@@ -3386,8 +3386,8 @@ static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op))
void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Camera Center";
- ot->description = "Center the camera view";
+ ot->name = "Frame Camera Bounds";
+ ot->description = "Center the camera view, resizing the view to fit its bounds";
ot->idname = "VIEW3D_OT_view_center_camera";
/* api callbacks */
@@ -4376,7 +4376,7 @@ static void viewroll_apply(ViewOpsData *vod, int x, int UNUSED(y))
}
if (RV3D_LOCK_FLAGS(vod->rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(vod->sa, vod->region);
+ view3d_boxview_sync(vod->area, vod->region);
}
ED_view3d_camera_lock_sync(vod->depsgraph, vod->v3d, vod->rv3d);
@@ -5018,7 +5018,6 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float cursor_co[3],
float cursor_quat[4])
{
- Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
@@ -5052,7 +5051,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
float ray_co[3];
struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, scene, 0, region, v3d);
+ scene, 0, region, v3d);
float obmat[4][4];
Object *ob_dummy = NULL;
@@ -5279,7 +5278,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
View3D *v3d = CTX_wm_view3d(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
int type = RNA_enum_get(op->ptr, "type");
if (type == OB_SOLID) {
@@ -5307,7 +5306,7 @@ static int toggle_shading_exec(bContext *C, wmOperator *op)
}
}
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, v3d, area);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
@@ -5340,7 +5339,7 @@ void VIEW3D_OT_toggle_shading(wmOperatorType *ot)
static int toggle_xray_exec(bContext *C, wmOperator *op)
{
View3D *v3d = CTX_wm_view3d(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
Object *obact = CTX_data_active_object(C);
if (obact && ((obact->mode & OB_MODE_POSE) ||
@@ -5362,7 +5361,7 @@ static int toggle_xray_exec(bContext *C, wmOperator *op)
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
return OPERATOR_FINISHED;
}
@@ -5372,6 +5371,7 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot)
/* identifiers */
ot->name = "Toggle X-Ray";
ot->idname = "VIEW3D_OT_toggle_xray";
+ ot->description = "Transparent scene display. Allow selecting through items";
/* api callbacks */
ot->exec = toggle_xray_exec;
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 563e1afa67e..06d1a033a0d 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -125,14 +125,14 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Fly Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Fly Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Fly Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
index cc00037b1fb..533fba3795b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c
@@ -321,14 +321,14 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g
if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
gz = navgroup->gz_array[GZ_INDEX_CAMERA];
- gz->matrix_basis[3][0] = co[0];
- gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][0] = roundf(co[0]);
+ gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
if (navgroup->state.rv3d.is_camera == false) {
gz = navgroup->gz_array[rv3d->is_persp ? GZ_INDEX_PERSP : GZ_INDEX_ORTHO];
- gz->matrix_basis[3][0] = co[0];
- gz->matrix_basis[3][1] = co[1] - (icon_offset_mini * icon_mini_slot++);
+ gz->matrix_basis[3][0] = roundf(co[0]);
+ gz->matrix_basis[3][1] = roundf(co[1] - (icon_offset_mini * icon_mini_slot++));
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
index a8e8d8cee96..3ce4c8dc9a8 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -197,8 +197,8 @@ static void axis_geom_draw(const wmGizmo *gz,
const bool select,
const struct AxisDrawInfo *draw_info)
{
-
- GPU_line_width(gz->line_width);
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
GPUVertFormat *format = immVertexFormat();
const uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
@@ -341,8 +341,13 @@ static void axis_geom_draw(const wmGizmo *gz,
/* Axis Line. */
if (is_pos) {
float v_start[3];
- GPU_line_width(2.0f);
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+ immUniform2fv("viewportSize", &viewport[2]);
+ immUniform1f("lineWidth", 2.0f * U.pixelsize);
immUniformColor4fv(is_pos_color ? color_current : color_current_fade);
+
immBegin(GPU_PRIM_LINES, 2);
if (axis_align == -1) {
zero_v3(v_start);
@@ -358,6 +363,10 @@ static void axis_geom_draw(const wmGizmo *gz,
immVertex3fv(pos_id, v_start);
immVertex3fv(pos_id, v_final);
immEnd();
+
+ immUnbindProgram();
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
}
/* Axis Ball. */
@@ -527,9 +536,12 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
return -1;
}
-static int gizmo_axis_cursor_get(wmGizmo *UNUSED(gz))
+static int gizmo_axis_cursor_get(wmGizmo *gz)
{
- return WM_CURSOR_DEFAULT;
+ if (gz->highlight_part > 0) {
+ return WM_CURSOR_EDIT;
+ }
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_navigate_rotate(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index 4b194d6687d..f3bc0a8a15b 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -40,6 +40,7 @@
#include "DNA_object_types.h"
#include "DNA_view3d_types.h"
+#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@@ -57,10 +58,13 @@
#include "WM_toolsystem.h"
#include "WM_types.h"
+#include "DEG_depsgraph_query.h"
+
#include "view3d_intern.h" /* own include */
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BLF_api.h"
@@ -94,10 +98,6 @@ enum {
RULER_STATE_DRAG,
};
-enum {
- RULER_SNAP_OK = (1 << 0),
-};
-
struct RulerItem;
typedef struct RulerInfo {
@@ -106,19 +106,25 @@ typedef struct RulerInfo {
int snap_flag;
int state;
- struct SnapObjectContext *snap_context;
-
/* wm state */
+ wmWindowManager *wm;
wmWindow *win;
- ScrArea *sa;
+ ScrArea *area;
ARegion *region; /* re-assigned every modal update */
/* Track changes in state. */
struct {
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
bool do_snap;
+#endif
bool do_thickness;
} drag_state_prev;
+ struct {
+ wmGizmo *gizmo;
+ PropertyRNA *prop_prevpoint;
+ } snap_data;
+
} RulerInfo;
/* -------------------------------------------------------------------- */
@@ -269,26 +275,17 @@ static bool view3d_ruler_pick(wmGizmoGroup *gzgroup,
* Ensure the 'snap_context' is only cached while dragging,
* needed since the user may toggle modes between tool use.
*/
-static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
+static void ruler_state_set(RulerInfo *ruler_info, int state)
{
- Main *bmain = CTX_data_main(C);
if (state == ruler_info->state) {
return;
}
- /* always remove */
- if (ruler_info->snap_context) {
- ED_transform_snap_object_context_destroy(ruler_info->snap_context);
- ruler_info->snap_context = NULL;
- }
-
if (state == RULER_STATE_NORMAL) {
/* pass */
}
else if (state == RULER_STATE_DRAG) {
memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev));
- ruler_info->snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, CTX_data_scene(C), 0, ruler_info->region, CTX_wm_view3d(C));
}
else {
BLI_assert(0);
@@ -299,7 +296,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state)
static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2])
{
- ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->region, r_co, xy, r_co);
+ ED_view3d_win_to_3d_int(ruler_info->area->spacedata.first, ruler_info->region, r_co, xy, r_co);
}
/* use for mousemove events */
@@ -307,13 +304,18 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
RulerInfo *ruler_info,
RulerItem *ruler_item,
const int mval[2],
- const bool do_thickness,
- const bool do_snap)
+ const bool do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ const bool do_snap
+#endif
+)
{
+ wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo;
const float eps_bias = 0.0002f;
float dist_px = MVAL_MAX_PX_DIST * U.pixelsize; /* snap dist */
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, true);
if (ruler_item) {
RulerInteraction *inter = ruler_item->gz.interaction_data;
@@ -322,8 +324,10 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
copy_v3_v3(co, inter->drag_start_co);
view3d_ruler_item_project(ruler_info, co, mval);
if (do_thickness && inter->co_index != 1) {
- // Scene *scene = CTX_data_scene(C);
- // View3D *v3d = ruler_info->sa->spacedata.first;
+ Scene *scene = DEG_get_input_scene(depsgraph);
+ View3D *v3d = ruler_info->area->spacedata.first;
+ SnapObjectContext *snap_context = ED_gizmotypes_snap_3d_context_ensure(
+ scene, ruler_info->region, v3d, snap_gizmo);
const float mval_fl[2] = {UNPACK2(mval)};
float ray_normal[3];
float ray_start[3];
@@ -331,7 +335,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
co_other = ruler_item->co[inter->co_index == 0 ? 2 : 0];
- if (ED_transform_snap_object_project_view3d(ruler_info->snap_context,
+ if (ED_transform_snap_object_project_view3d(snap_context,
depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
@@ -346,7 +350,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
negate_v3(ray_normal);
/* add some bias */
madd_v3_v3v3fl(ray_start, co, ray_normal, eps_bias);
- ED_transform_snap_object_project_ray(ruler_info->snap_context,
+ ED_transform_snap_object_project_ray(snap_context,
depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
@@ -359,7 +363,12 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
NULL);
}
}
- else if (do_snap) {
+ else
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (do_snap)
+#endif
+ {
+ View3D *v3d = ruler_info->area->spacedata.first;
const float mval_fl[2] = {UNPACK2(mval)};
float *prev_point = NULL;
@@ -374,23 +383,16 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
prev_point = ruler_item->co[0];
}
}
+ if (prev_point != NULL) {
+ RNA_property_float_set_array(
+ snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
- if (ED_transform_snap_object_project_view3d(
- ruler_info->snap_context,
- depsgraph,
- (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
- SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR),
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
- .use_occlusion_test = true,
- },
- mval_fl,
- prev_point,
- &dist_px,
- co,
- NULL)) {
- ruler_info->snap_flag |= RULER_SNAP_OK;
+ short snap_elem = ED_gizmotypes_snap_3d_update(
+ snap_gizmo, depsgraph, ruler_info->region, v3d, ruler_info->wm, mval_fl, co, NULL);
+
+ if (snap_elem) {
+ WM_gizmo_set_flag(snap_gizmo, WM_GIZMO_HIDDEN, false);
}
}
return true;
@@ -417,6 +419,15 @@ static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
return NULL;
}
+static RulerItem *gzgroup_ruler_item_first_get(wmGizmoGroup *gzgroup)
+{
+#ifndef NDEBUG
+ RulerInfo *ruler_info = gzgroup->customdata;
+ BLI_assert(gzgroup->gizmos.first == ruler_info->snap_data.gizmo);
+#endif
+ return (RulerItem *)((wmGizmo *)gzgroup->gizmos.first)->next;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
{
@@ -448,7 +459,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_NEW);
BKE_gpencil_free_strokes(gpf);
- for (ruler_item = gzgroup->gizmos.first; ruler_item;
+ for (ruler_item = gzgroup_ruler_item_first_get(gzgroup); ruler_item;
ruler_item = (RulerItem *)ruler_item->gz.next) {
bGPDspoint *pt;
int j;
@@ -556,6 +567,12 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
uchar color_wire[3];
float color_back[4] = {1.0f, 1.0f, 1.0f, 0.5f};
+ /* Pixel Space. */
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_identity_set();
+ wmOrtho2_region_pixelspace(region);
+
/* anti-aliased lines for more consistent appearance */
GPU_line_smooth(true);
GPU_line_width(1.0f);
@@ -575,20 +592,30 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
const bool is_act = (ruler_info->item_active == ruler_item);
float dir_ruler[2];
float co_ss[3][2];
+ bool proj_ok[3];
int j;
- /* should these be checked? - ok for now not to */
+ /* Check if each corner is behind the near plane. If it is, we do not draw certain lines. */
for (j = 0; j < 3; j++) {
- ED_view3d_project_float_global(region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP);
+ eV3DProjStatus status = ED_view3d_project_float_global(
+ region, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_CLIP_NEAR);
+ proj_ok[j] = (status == V3D_PROJ_RET_OK);
}
+ /* 3d drawing. */
+
+ GPU_matrix_push_projection();
+ GPU_matrix_push();
+ GPU_matrix_projection_set(rv3d->winmat);
+ GPU_matrix_set(rv3d->viewmat);
+
GPU_blend(true);
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const uint shdr_pos_3d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
if (ruler_item->flag & RULERITEM_USE_ANGLE) {
- 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);
@@ -605,21 +632,20 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, 3);
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[1]);
- immVertex2fv(shdr_pos, co_ss[2]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[1]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
immEnd();
immUnbindProgram();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
/* arc */
{
float dir_tmp[3];
- float co_tmp[3];
- float arc_ss_coord[2];
+ float ar_coord[3];
float dir_a[3];
float dir_b[3];
@@ -648,16 +674,53 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immBegin(GPU_PRIM_LINE_STRIP, arc_steps + 1);
for (j = 0; j <= arc_steps; j++) {
- madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
- ED_view3d_project_float_global(region, co_tmp, arc_ss_coord, V3D_PROJ_TEST_NOP);
+ madd_v3_v3v3fl(ar_coord, ruler_item->co[1], dir_tmp, px_scale);
mul_qt_v3(quat, dir_tmp);
- immVertex2fv(shdr_pos, arc_ss_coord);
+ immVertex3fv(shdr_pos_3d, ar_coord);
}
immEnd();
}
+ immUnbindProgram();
+ }
+ else {
+ 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]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float *col = is_act ? color_act : color_base;
+ immUniformArray4fv(
+ "colors",
+ (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
+ 2);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+
+ immVertex3fv(shdr_pos_3d, ruler_item->co[0]);
+ immVertex3fv(shdr_pos_3d, ruler_item->co[2]);
+
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ /* 2d drawing. */
+
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+
+ const uint shdr_pos_2d = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+
+ if (ruler_item->flag & RULERITEM_USE_ANGLE) {
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* capping */
{
float rot_90_vec_a[2];
@@ -676,15 +739,15 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
GPU_blend(true);
- if (is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
+ if (proj_ok[1] && is_act && (ruler_item->flag & RULERITEM_USE_ANGLE_ACTIVE)) {
GPU_line_width(3.0f);
immUniformColor3fv(color_act);
immBegin(GPU_PRIM_LINES, 4);
/* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
immEnd();
GPU_line_width(1.0f);
@@ -692,25 +755,33 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 8);
+ if (proj_ok[0] || proj_ok[2] || proj_ok[1]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2 + proj_ok[1] * 4);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- /* angle vertex */
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
- immVertex2f(shdr_pos, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ /* angle vertex */
+ if (proj_ok[1]) {
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
+ immVertex2f(shdr_pos_2d, co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -729,10 +800,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);
/* draw text (bg) */
- {
+ if (proj_ok[1]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -743,7 +814,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[1]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_rotation(blf_mono_font, 0.0f);
@@ -751,30 +822,6 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
}
}
else {
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 2); /* "advanced" mode */
- const float *col = is_act ? color_act : color_base;
- immUniformArray4fv(
- "colors",
- (float *)(float[][4]){{0.67f, 0.67f, 0.67f, 1.0f}, {col[0], col[1], col[2], col[3]}},
- 2);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
-
- immVertex2fv(shdr_pos, co_ss[0]);
- immVertex2fv(shdr_pos, co_ss[2]);
-
- immEnd();
-
- immUnbindProgram();
-
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);
@@ -790,19 +837,25 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUniformColor3ubv(color_wire);
- immBegin(GPU_PRIM_LINES, 4);
+ if (proj_ok[0] || proj_ok[2]) {
+ immBegin(GPU_PRIM_LINES, proj_ok[0] * 2 + proj_ok[2] * 2);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[0]) {
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
- immVertex2fv(shdr_pos, cap);
- madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
- immVertex2fv(shdr_pos, cap);
+ if (proj_ok[2]) {
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
+ immVertex2fv(shdr_pos_2d, cap);
+ }
- immEnd();
+ immEnd();
+ }
GPU_blend(false);
}
@@ -824,10 +877,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
posit[1] -= numstr_size[1] / 2.0f;
/* draw text (bg) */
- {
+ if (proj_ok[0] && proj_ok[2]) {
immUniformColor4fv(color_back);
GPU_blend(true);
- immRectf(shdr_pos,
+ immRectf(shdr_pos_2d,
posit[0] - bg_margin,
posit[1] - bg_margin,
posit[0] + bg_margin + numstr_size[0],
@@ -838,7 +891,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
immUnbindProgram();
/* draw text */
- {
+ if (proj_ok[0] && proj_ok[2]) {
BLF_color3ubv(blf_mono_font, color_text);
BLF_position(blf_mono_font, posit[0], posit[1], 0.0f);
BLF_draw(blf_mono_font, numstr, sizeof(numstr));
@@ -849,27 +902,10 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz)
BLF_disable(blf_mono_font, BLF_ROTATION);
-#undef ARC_STEPS
-
- /* draw snap */
- if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG) &&
- (ruler_item->gz.interaction_data != NULL)) {
- RulerInteraction *inter = ruler_item->gz.interaction_data;
- /* size from drawSnapping */
- const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
- float co_ss_snap[3];
- ED_view3d_project_float_global(
- region, ruler_item->co[inter->co_index], co_ss_snap, V3D_PROJ_TEST_NOP);
-
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformThemeColor3(TH_GIZMO_VIEW_ALIGN);
-
- imm_draw_circle_wire_2d(pos, co_ss_snap[0], co_ss_snap[1], size * U.pixelsize, 32);
-
- immUnbindProgram();
- }
+#undef ARC_STEPS
}
static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mval[2])
@@ -902,35 +938,36 @@ static int gizmo_ruler_modal(bContext *C,
RulerInfo *ruler_info = gz->parent_gzgroup->customdata;
RulerItem *ruler_item = (RulerItem *)gz;
ARegion *region = CTX_wm_region(C);
- bool do_cursor_update = false;
+ bool do_cursor_update = (event->val == KM_RELEASE) || (event->type == MOUSEMOVE);
ruler_info->region = region;
- switch (event->type) {
- case MOUSEMOVE: {
- do_cursor_update = true;
- break;
- }
- }
-
- const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP;
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP);
+#endif
const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE;
- if ((ruler_info->drag_state_prev.do_snap != do_snap) ||
- (ruler_info->drag_state_prev.do_thickness != do_thickness)) {
+ if ((ruler_info->drag_state_prev.do_thickness != do_thickness)) {
do_cursor_update = true;
}
if (do_cursor_update) {
if (ruler_info->state == RULER_STATE_DRAG) {
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- if (view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) {
+ if (view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ do_thickness
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ do_snap
+#endif
+ )) {
do_draw = true;
}
}
}
- ruler_info->drag_state_prev.do_snap = do_snap;
ruler_info->drag_state_prev.do_thickness = do_thickness;
if (do_draw) {
@@ -957,7 +994,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* Add Center Point */
ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
inter->co_index = 1;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* find the factor */
{
@@ -978,13 +1015,21 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
/* update the new location */
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- view3d_ruler_item_mousemove(
- depsgraph, ruler_info, ruler_item_pick, event->mval, false, false);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item_pick,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ false
+#endif
+ );
}
}
else {
inter->co_index = gz->highlight_part;
- ruler_state_set(C, ruler_info, RULER_STATE_DRAG);
+ ruler_state_set(ruler_info, RULER_STATE_DRAG);
/* store the initial depth */
copy_v3_v3(inter->drag_start_co, ruler_item_pick->co[inter->co_index]);
@@ -997,6 +1042,28 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event)
ruler_item_pick->flag &= ~RULERITEM_USE_ANGLE_ACTIVE;
}
+ {
+ /* Set Snap prev point. */
+ float *prev_point;
+ if (ruler_item_pick->flag & RULERITEM_USE_ANGLE) {
+ prev_point = (inter->co_index != 1) ? ruler_item_pick->co[1] : NULL;
+ }
+ else if (inter->co_index == 0) {
+ prev_point = ruler_item_pick->co[2];
+ }
+ else {
+ prev_point = ruler_item_pick->co[0];
+ }
+
+ if (prev_point) {
+ RNA_property_float_set_array(
+ ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point);
+ }
+ else {
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ }
+ }
+
ruler_info->item_active = ruler_item_pick;
return OPERATOR_RUNNING_MODAL;
@@ -1009,10 +1076,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
if (!cancel) {
if (ruler_info->state == RULER_STATE_DRAG) {
- if (ruler_info->snap_flag & RULER_SNAP_OK) {
- ruler_info->snap_flag &= ~RULER_SNAP_OK;
- }
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ WM_gizmo_set_flag(ruler_info->snap_data.gizmo, WM_GIZMO_HIDDEN, false);
+ RNA_property_unset(ruler_info->snap_data.gizmo->ptr, ruler_info->snap_data.prop_prevpoint);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
/* We could convert only the current gizmo, for now just re-generate. */
view3d_ruler_to_gpencil(C, gzgroup);
@@ -1022,7 +1088,7 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
MEM_SAFE_FREE(gz->interaction_data);
}
- ruler_state_set(C, ruler_info, RULER_STATE_NORMAL);
+ ruler_state_set(ruler_info, RULER_STATE_NORMAL);
}
static int gizmo_ruler_cursor_get(wmGizmo *gz)
@@ -1059,16 +1125,39 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
{
RulerInfo *ruler_info = MEM_callocN(sizeof(RulerInfo), __func__);
+ wmGizmo *gizmo;
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
+ WM_gizmo_operator_set(gizmo, 0, ot, NULL);
+ }
+
if (view3d_ruler_from_gpencil(C, gzgroup)) {
/* nop */
}
+ wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
+
+ ruler_info->wm = wm;
ruler_info->win = win;
- ruler_info->sa = sa;
+ ruler_info->area = area;
ruler_info->region = region;
+ ruler_info->snap_data.gizmo = gizmo;
+ ruler_info->snap_data.prop_prevpoint = RNA_struct_find_property(gizmo->ptr, "prev_point");
gzgroup->customdata = ruler_info;
}
@@ -1078,7 +1167,7 @@ void VIEW3D_GGT_ruler(wmGizmoGroupType *gzgt)
gzgt->name = "Ruler Widgets";
gzgt->idname = view3d_gzgt_ruler_id;
- gzgt->flag |= WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -1132,8 +1221,20 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e
struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
/* snap the first point added, not essential but handy */
inter->co_index = 0;
- view3d_ruler_item_mousemove(depsgraph, ruler_info, ruler_item, event->mval, false, true);
+ view3d_ruler_item_mousemove(depsgraph,
+ ruler_info,
+ ruler_item,
+ event->mval,
+ false
+#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ ,
+ true
+#endif
+ );
copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]);
+ RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr,
+ ruler_info->snap_data.prop_prevpoint,
+ inter->drag_start_co);
}
else {
negate_v3_v3(inter->drag_start_co, rv3d->ofs);
@@ -1152,6 +1253,7 @@ void VIEW3D_OT_ruler_add(wmOperatorType *ot)
/* identifiers */
ot->name = "Ruler Add";
ot->idname = "VIEW3D_OT_ruler_add";
+ ot->description = "Add ruler";
ot->invoke = view3d_ruler_add_invoke;
ot->poll = view3d_ruler_poll;
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index 57989680705..829d793333e 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -77,7 +77,8 @@ static int toggle_matcap_flip(bContext *C, wmOperator *UNUSED(op))
else {
Scene *scene = CTX_data_scene(C);
scene->display.shading.flag ^= V3D_SHADING_MATCAP_FLIP_X;
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, v3d);
+ 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;
@@ -105,7 +106,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
wmWindow *win = CTX_wm_window(C);
const int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
- /* watch it: if sa->win does not exist, check that when calling direct drawing routines */
+ /* watch it: if area->win does not exist, check that when calling direct drawing routines */
switch (event) {
case B_SEL_VERT:
@@ -138,10 +139,11 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
if (obedit && (obedit->type == OB_MESH)) {
BMEditMesh *em = BKE_editmesh_from_object(obedit);
uiLayout *row;
+ uiBut *but;
row = uiLayoutRow(layout, true);
block = uiLayoutGetBlock(row);
- uiDefIconButBitS(
+ but = uiDefIconButBitS(
block,
UI_BTYPE_TOGGLE,
SCE_SELECT_VERTEX,
@@ -157,23 +159,26 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
0,
0,
TIP_("Vertex select - Shift-Click for multiple modes, Ctrl-Click contracts selection"));
- uiDefIconButBitS(block,
- UI_BTYPE_TOGGLE,
- SCE_SELECT_EDGE,
- B_SEL_EDGE,
- ICON_EDGESEL,
- 0,
- 0,
- ceilf(UI_UNIT_X - U.pixelsize),
- UI_UNIT_Y,
- &em->selectmode,
- 1.0,
- 0.0,
- 0,
- 0,
- TIP_("Edge select - Shift-Click for multiple modes, Ctrl-Click "
- "expands/contracts selection"));
- uiDefIconButBitS(
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ but = uiDefIconButBitS(
+ block,
+ UI_BTYPE_TOGGLE,
+ SCE_SELECT_EDGE,
+ B_SEL_EDGE,
+ ICON_EDGESEL,
+ 0,
+ 0,
+ ceilf(UI_UNIT_X - U.pixelsize),
+ UI_UNIT_Y,
+ &em->selectmode,
+ 1.0,
+ 0.0,
+ 0,
+ 0,
+ TIP_("Edge select - Shift-Click for multiple modes, "
+ "Ctrl-Click expands/contracts selection depending on the current mode"));
+ UI_but_flag_disable(but, UI_BUT_UNDO);
+ but = uiDefIconButBitS(
block,
UI_BTYPE_TOGGLE,
SCE_SELECT_FACE,
@@ -189,6 +194,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
0,
0,
TIP_("Face select - Shift-Click for multiple modes, Ctrl-Click expands selection"));
+ UI_but_flag_disable(but, UI_BUT_UNDO);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 610c40c37eb..50cd71d7edc 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -91,8 +91,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_shading(struct wmOperatorType *ot);
void VIEW3D_OT_toggle_xray(struct wmOperatorType *ot);
-void view3d_boxview_copy(struct ScrArea *sa, struct ARegion *region);
-void view3d_boxview_sync(struct ScrArea *sa, struct ARegion *region);
+void view3d_boxview_copy(struct ScrArea *area, struct ARegion *region);
+void view3d_boxview_sync(struct ScrArea *area, struct ARegion *region);
void view3d_orbit_apply_dyn_ofs(float r_ofs[3],
const float ofs_old[3],
@@ -181,7 +181,7 @@ typedef struct V3D_SmoothParams {
void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph,
struct wmWindowManager *wm,
struct wmWindow *win,
- struct ScrArea *sa,
+ struct ScrArea *area,
struct View3D *v3d,
struct ARegion *region,
const int smooth_viewtx,
@@ -213,6 +213,7 @@ void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
void viewdolly_modal_keymap(struct wmKeyConfig *keyconf);
+void viewplace_modal_keymap(struct wmKeyConfig *keyconf);
/* view3d_buttons.c */
void VIEW3D_OT_object_mode_pie_or_toggle(struct wmOperatorType *ot);
@@ -243,6 +244,9 @@ void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void VIEW3D_OT_snap_cursor_to_active(struct wmOperatorType *ot);
+/* view3d_placement.c */
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot);
+
/* space_view3d.c */
extern const char *view3d_context_dir[]; /* doc access */
@@ -268,6 +272,8 @@ void VIEW3D_OT_ruler_remove(struct wmOperatorType *ot);
void VIEW3D_GT_navigate_rotate(struct wmGizmoType *gzt);
+void VIEW3D_GGT_placement(struct wmGizmoGroupType *gzgt);
+
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
* without this define we get the old behavior which is to try and align them
diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c
index d8e1c8c1c72..91e629147f4 100644
--- a/source/blender/editors/space_view3d/view3d_iterators.c
+++ b/source/blender/editors/space_view3d/view3d_iterators.c
@@ -126,7 +126,7 @@ void meshobject_foreachScreenVert(
Scene *scene_eval = DEG_get_evaluated_scene(vc->depsgraph);
Object *ob_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
- me = mesh_get_eval_deform(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ me = mesh_get_eval_final(vc->depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -388,7 +388,7 @@ void mesh_foreachScreenFace(
BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE);
- if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) {
+ if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) {
BKE_mesh_foreach_mapped_subdiv_face_center(
me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP);
}
@@ -406,6 +406,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co_b[2]),
void *userData,
const eV3DProjTest clip_flag)
@@ -414,6 +415,8 @@ void nurbs_foreachScreenVert(ViewContext *vc,
Nurb *nu;
int i;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+ /* If no point in the triple is selected, the handles are invisible. */
+ const bool only_selected = (vc->v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
ED_view3d_check_mats_rv3d(vc->rv3d);
@@ -427,15 +430,17 @@ void nurbs_foreachScreenVert(ViewContext *vc,
BezTriple *bezt = &nu->bezt[i];
if (bezt->hide == 0) {
+ const bool handles_visible = (vc->v3d->overlay.handle_display != CURVE_HANDLE_NONE) &&
+ (!only_selected || BEZT_ISSEL_ANY(bezt));
float screen_co[2];
- if ((vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (!handles_visible) {
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, false, screen_co);
}
}
else {
@@ -444,21 +449,21 @@ void nurbs_foreachScreenVert(ViewContext *vc,
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 0, screen_co);
+ func(userData, nu, NULL, bezt, 0, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[1],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 1, screen_co);
+ func(userData, nu, NULL, bezt, 1, true, screen_co);
}
if (ED_view3d_project_float_object(vc->region,
bezt->vec[2],
screen_co,
V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, NULL, bezt, 2, screen_co);
+ func(userData, nu, NULL, bezt, 2, true, screen_co);
}
}
}
@@ -473,7 +478,7 @@ void nurbs_foreachScreenVert(ViewContext *vc,
if (ED_view3d_project_float_object(
vc->region, bp->vec, screen_co, V3D_PROJ_RET_CLIP_BB | V3D_PROJ_RET_CLIP_WIN) ==
V3D_PROJ_RET_OK) {
- func(userData, nu, bp, NULL, -1, screen_co);
+ func(userData, nu, bp, NULL, -1, false, screen_co);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index a53262df267..0770bac1313 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -47,6 +47,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_outliner.h"
#include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h"
@@ -117,6 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
+ ED_outliner_select_sync_from_object_tag(C);
BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted);
@@ -209,6 +211,8 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected);
WM_operatortype_append(VIEW3D_OT_snap_cursor_to_active);
+ WM_operatortype_append(VIEW3D_OT_interactive_add);
+
WM_operatortype_append(VIEW3D_OT_toggle_shading);
WM_operatortype_append(VIEW3D_OT_toggle_xray);
WM_operatortype_append(VIEW3D_OT_toggle_matcap_flip);
@@ -232,4 +236,5 @@ void view3d_keymap(wmKeyConfig *keyconf)
viewmove_modal_keymap(keyconf);
viewzoom_modal_keymap(keyconf);
viewdolly_modal_keymap(keyconf);
+ viewplace_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
new file mode 100644
index 00000000000..f2b78bc2aaf
--- /dev/null
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -0,0 +1,1153 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup spview3d
+ *
+ * Operator to interactively place data.
+ *
+ * Currently only adds meshes, but could add other kinds of data
+ * including library assets & non-mesh types.
+ */
+
+#include "BLI_math_vector.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_collection_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "WM_api.h"
+#include "WM_toolsystem.h"
+#include "WM_types.h"
+
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_transform.h"
+#include "ED_transform_snap_object_context.h"
+#include "ED_view3d.h"
+
+#include "UI_resources.h"
+
+#include "GPU_batch.h"
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "view3d_intern.h"
+
+static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
+
+/* -------------------------------------------------------------------- */
+/** \name Local Types
+ * \{ */
+
+enum ePlace_PrimType {
+ PLACE_PRIMITIVE_TYPE_CUBE = 1,
+ PLACE_PRIMITIVE_TYPE_CYLINDER = 2,
+ PLACE_PRIMITIVE_TYPE_CONE = 3,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV = 4,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO = 5,
+};
+
+enum ePlace_Origin {
+ PLACE_ORIGIN_BASE = 1,
+ PLACE_ORIGIN_CENTER = 2,
+};
+
+enum ePlace_Depth {
+ PLACE_DEPTH_SURFACE = 1,
+ PLACE_DEPTH_CURSOR_PLANE = 2,
+ PLACE_DEPTH_CURSOR_VIEW = 3,
+};
+
+struct InteractivePlaceData {
+ /* Window manager variables (set these even when waiting for input). */
+ Scene *scene;
+ ScrArea *area;
+ View3D *v3d;
+ ARegion *region;
+
+ /** Draw object preview region draw callback. */
+ void *draw_handle_view;
+
+ float co_src[3];
+
+ /** Primary & secondary steps. */
+ struct {
+ bool is_centered;
+ bool is_fixed_aspect;
+ float plane[4];
+ float co_dst[3];
+ } step[2];
+
+ float matrix_orient[3][3];
+ int orient_axis;
+
+ /** The tool option, if we start centered, invert toggling behavior. */
+ bool is_centered_init;
+
+ bool use_snap, is_snap_found, is_snap_invert;
+ float snap_co[3];
+
+ /** Can index into #InteractivePlaceData.step. */
+ enum {
+ STEP_BASE = 0,
+ STEP_DEPTH = 1,
+ } step_index;
+
+ enum ePlace_PrimType primitive_type;
+
+ /** Activated from the tool-system. */
+ bool use_tool;
+
+ /** Event used to start the operator. */
+ short launch_event;
+
+ /** When activated without a tool. */
+ bool wait_for_input;
+
+ /** Optional snap gizmo, needed for snapping. */
+ wmGizmo *snap_gizmo;
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+/* On-screen snap distance. */
+#define MVAL_MAX_PX_DIST 12.0f
+
+static bool idp_snap_point_from_gizmo(wmGizmo *gz, float r_location[3])
+{
+ if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
+ PropertyRNA *prop_location = RNA_struct_find_property(gz->ptr, "location");
+ RNA_property_float_get_array(gz->ptr, prop_location, r_location);
+ return true;
+ }
+ return false;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Primitive Drawing (Cube, Cone, Cylinder...)
+ * \{ */
+
+static void draw_line_loop(float coords[][3], int coords_len, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINE_LOOP, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_pairs(float coords_a[][3],
+ float coords_b[][3],
+ int coords_len,
+ const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, coords_len * 2);
+
+ for (int i = 0; i < coords_len; i++) {
+ GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
+ GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static void draw_line_bounds(const BoundBox *bounds, const float color[4])
+{
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ int edges[12][2] = {
+ /* First side. */
+ {0, 1},
+ {1, 2},
+ {2, 3},
+ {3, 0},
+ /* Second side. */
+ {4, 5},
+ {5, 6},
+ {6, 7},
+ {7, 4},
+ /* Edges between. */
+ {0, 4},
+ {1, 5},
+ {2, 6},
+ {3, 7},
+ };
+
+ GPUVertBuf *vert = GPU_vertbuf_create_with_format(format);
+ GPU_vertbuf_data_alloc(vert, ARRAY_SIZE(edges) * 2);
+
+ for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
+ GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
+ }
+
+ GPU_blend(true);
+ GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_LINES, vert, NULL, GPU_BATCH_OWNS_VBO);
+ GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR);
+
+ GPU_batch_bind(batch);
+
+ GPU_batch_uniform_4fv(batch, "color", color);
+
+ float viewport[4];
+ GPU_viewport_size_get_f(viewport);
+ GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
+ GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
+
+ GPU_batch_draw(batch);
+
+ GPU_batch_program_use_end(batch);
+
+ GPU_batch_discard(batch);
+ GPU_blend(false);
+}
+
+static bool calc_bbox(struct InteractivePlaceData *ipd, BoundBox *bounds)
+{
+ memset(bounds, 0x0, sizeof(*bounds));
+
+ if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
+ return false;
+ }
+
+ float matrix_orient_inv[3][3];
+ invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
+
+ const int x_axis = (ipd->orient_axis + 1) % 3;
+ const int y_axis = (ipd->orient_axis + 2) % 3;
+
+ float quad_base[4][3];
+ float quad_secondary[4][3];
+
+ copy_v3_v3(quad_base[0], ipd->co_src);
+ copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
+
+ /* Only set when we have a fixed aspect. */
+ float fixed_aspect_dimension;
+
+ /* *** Primary *** */
+
+ {
+ float delta_local[3];
+ float delta_a[3];
+ float delta_b[3];
+
+ sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
+ mul_m3_v3(matrix_orient_inv, delta_local);
+
+ copy_v3_v3(delta_a, delta_local);
+ copy_v3_v3(delta_b, delta_local);
+ delta_a[ipd->orient_axis] = 0.0f;
+ delta_b[ipd->orient_axis] = 0.0f;
+
+ delta_a[x_axis] = 0.0f;
+ delta_b[y_axis] = 0.0f;
+
+ /* Assign here in case secondary */
+ fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
+
+ if (ipd->step[0].is_fixed_aspect) {
+ delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
+ delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
+ }
+
+ mul_m3_v3(ipd->matrix_orient, delta_a);
+ mul_m3_v3(ipd->matrix_orient, delta_b);
+
+ if (ipd->step[0].is_fixed_aspect) {
+ /* Recalculate the destination point. */
+ copy_v3_v3(quad_base[2], ipd->co_src);
+ add_v3_v3(quad_base[2], delta_a);
+ add_v3_v3(quad_base[2], delta_b);
+ }
+
+ add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
+ add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
+ }
+
+ if (ipd->step[0].is_centered) {
+ /* Use a copy in case aspect was applied to the quad. */
+ float base_co_dst[3];
+ copy_v3_v3(base_co_dst, quad_base[2]);
+ for (int i = 0; i < 4; i++) {
+ sub_v3_v3(quad_base[i], base_co_dst);
+ mul_v3_fl(quad_base[i], 2.0f);
+ add_v3_v3(quad_base[i], base_co_dst);
+ }
+ }
+
+ /* *** Secondary *** */
+
+ float delta_local[3];
+ if (ipd->step_index == STEP_DEPTH) {
+ sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
+ }
+ else {
+ zero_v3(delta_local);
+ }
+
+ if (ipd->step[1].is_fixed_aspect) {
+ if (!is_zero_v3(delta_local)) {
+ normalize_v3_length(delta_local, fixed_aspect_dimension);
+ }
+ }
+
+ if (ipd->step[1].is_centered) {
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ sub_v3_v3(quad_base[i], delta_local);
+ }
+ mul_v3_fl(delta_local, 2.0f);
+ }
+
+ if ((ipd->step_index == STEP_DEPTH) &&
+ (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false)) {
+
+ for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
+ add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
+ }
+ }
+ else {
+ copy_v3_v3(quad_secondary[0], quad_base[0]);
+ copy_v3_v3(quad_secondary[1], quad_base[1]);
+ copy_v3_v3(quad_secondary[2], quad_base[2]);
+ copy_v3_v3(quad_secondary[3], quad_base[3]);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(bounds->vec[i], quad_base[i]);
+ copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
+ }
+
+ return true;
+}
+
+static void draw_circle_in_quad(const float v1[2],
+ const float v2[2],
+ const float v3[2],
+ const float v4[2],
+ const int resolution,
+ const float color[4])
+{
+ /* This isn't so efficient. */
+ const float quad[4][2] = {
+ {-1, -1},
+ {+1, -1},
+ {+1, +1},
+ {-1, +1},
+ };
+
+ float(*coords)[3] = MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__);
+ for (int i = 0; i <= resolution; i++) {
+ float theta = ((2.0f * M_PI) * ((float)i / (float)resolution)) + 0.01f;
+ float x = cosf(theta);
+ float y = sinf(theta);
+ float pt[2] = {x, y};
+ float w[4];
+ barycentric_weights_v2_quad(UNPACK4(quad), pt, w);
+
+ float *co = coords[i];
+ zero_v3(co);
+ madd_v3_v3fl(co, v1, w[0]);
+ madd_v3_v3fl(co, v2, w[1]);
+ madd_v3_v3fl(co, v3, w[2]);
+ madd_v3_v3fl(co, v4, w[3]);
+ }
+ draw_line_loop(coords, resolution + 1, color);
+ MEM_freeN(coords);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Drawing Callbacks
+ * \{ */
+
+static void draw_primitive_view_impl(const struct bContext *C,
+ struct InteractivePlaceData *ipd,
+ const float color[4])
+{
+ UNUSED_VARS(C);
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+ draw_line_bounds(&bounds, color);
+
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ /* pass */
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+ draw_circle_in_quad(UNPACK4((&bounds.vec[4])), 32, color);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
+
+ float center[3];
+ mid_v3_v3v3v3v3(center, UNPACK4((&bounds.vec[4])));
+
+ float coords_a[4][3];
+ float coords_b[4][3];
+
+ for (int i = 0; i < 4; i++) {
+ copy_v3_v3(coords_a[i], center);
+ mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
+ }
+
+ draw_line_pairs(coords_a, coords_b, 4, color);
+ }
+ else if (ELEM(ipd->primitive_type,
+ PLACE_PRIMITIVE_TYPE_SPHERE_UV,
+ PLACE_PRIMITIVE_TYPE_SPHERE_ICO)) {
+ /* See bound-box diagram for reference. */
+
+ /* Primary Side. */
+ float v01[3], v12[3], v23[3], v30[3];
+ mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
+ mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
+ mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
+ mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
+ /* Secondary Side. */
+ float v45[3], v56[3], v67[3], v74[3];
+ mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
+ mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
+ mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
+ mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
+ /* Edges between. */
+ float v04[3], v15[3], v26[3], v37[3];
+ mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
+ mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
+ mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
+ mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
+
+ draw_circle_in_quad(v01, v45, v67, v23, 32, color);
+ draw_circle_in_quad(v30, v12, v56, v74, 32, color);
+ draw_circle_in_quad(v04, v15, v26, v37, 32, color);
+ }
+}
+
+static void draw_primitive_view(const struct bContext *C, ARegion *UNUSED(region), void *arg)
+{
+ struct InteractivePlaceData *ipd = arg;
+ float color[4];
+ UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, color);
+
+ const bool use_depth = !XRAY_ENABLED(ipd->v3d);
+ const bool depth_test_enabled = GPU_depth_test_enabled();
+
+ if (use_depth) {
+ GPU_depth_test(false);
+ color[3] = 0.15f;
+ draw_primitive_view_impl(C, ipd, color);
+ }
+
+ if (use_depth) {
+ GPU_depth_test(true);
+ }
+ color[3] = 1.0f;
+ draw_primitive_view_impl(C, ipd, color);
+
+ if (use_depth) {
+ if (depth_test_enabled == false) {
+ GPU_depth_test(false);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Object Modal Operator
+ * \{ */
+
+/**
+ *
+ * */
+static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
+{
+
+ const int plane_axis = RNA_enum_get(op->ptr, "plane_axis");
+ const enum ePlace_Depth plane_depth = RNA_enum_get(op->ptr, "plane_depth");
+ const enum ePlace_Origin plane_origin = RNA_enum_get(op->ptr, "plane_origin");
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ RegionView3D *rv3d = ipd->region->regiondata;
+
+ ipd->launch_event = WM_userdef_event_type_from_keymap_type(event->type);
+
+ ED_transform_calc_orientation_from_type(C, ipd->matrix_orient);
+
+ ipd->orient_axis = plane_axis;
+ ipd->is_centered_init = (plane_origin == PLACE_ORIGIN_CENTER);
+ ipd->step[0].is_centered = ipd->is_centered_init;
+ ipd->step[1].is_centered = ipd->is_centered_init;
+ ipd->step_index = STEP_BASE;
+
+ /* Assign snap gizmo which is may be used as part of the tool. */
+ {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : NULL;
+ if ((gzgroup != NULL) && gzgroup->gizmos.first) {
+ ipd->snap_gizmo = gzgroup->gizmos.first;
+ }
+ }
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
+ if (RNA_property_is_set(op->ptr, prop)) {
+ ipd->primitive_type = RNA_property_enum_get(op->ptr, prop);
+ ipd->use_tool = false;
+ }
+ else {
+ ipd->use_tool = true;
+
+ /* Get from the tool, a bit of a non-standard way of operating. */
+ const bToolRef *tref = ipd->area->runtime.tool;
+ if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CYLINDER;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CONE;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_UV;
+ }
+ else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_SPHERE_ICO;
+ }
+ else {
+ /* If the user runs this as an operator they should set the 'primitive_type',
+ * however running from operator search will end up at this point. */
+ ipd->primitive_type = PLACE_PRIMITIVE_TYPE_CUBE;
+ ipd->use_tool = false;
+ }
+ }
+ }
+
+ UNUSED_VARS(C, event);
+
+ ipd->draw_handle_view = ED_region_draw_cb_activate(
+ ipd->region->type, draw_primitive_view, ipd, REGION_DRAW_POST_VIEW);
+
+ ED_region_tag_redraw(ipd->region);
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ const bool is_snap_found = ipd->snap_gizmo ?
+ idp_snap_point_from_gizmo(ipd->snap_gizmo, ipd->co_src) :
+ false;
+ ipd->is_snap_invert = ipd->snap_gizmo ? ED_gizmotypes_snap_3d_invert_snap_get(ipd->snap_gizmo) :
+ false;
+ {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ }
+
+ if (is_snap_found) {
+ /* pass */
+ }
+ else {
+ bool use_depth_fallback = true;
+ if (plane_depth == PLACE_DEPTH_CURSOR_VIEW) {
+ /* View plane. */
+ ED_view3d_win_to_3d(
+ ipd->v3d, ipd->region, ipd->scene->cursor.location, mval_fl, ipd->co_src);
+ use_depth_fallback = false;
+ }
+ else if (plane_depth == PLACE_DEPTH_SURFACE) {
+ SnapObjectContext *snap_context =
+ (ipd->snap_gizmo ? ED_gizmotypes_snap_3d_context_ensure(
+ ipd->scene, ipd->region, ipd->v3d, ipd->snap_gizmo) :
+ NULL);
+ if ((snap_context != NULL) &&
+ ED_transform_snap_object_project_view3d(snap_context,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ SCE_SNAP_MODE_FACE,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ .use_object_edit_cage = true,
+ },
+ mval_fl,
+ NULL,
+ NULL,
+ ipd->co_src,
+ NULL)) {
+ use_depth_fallback = false;
+ }
+ }
+
+ /* Use as fallback to surface. */
+ if (use_depth_fallback || (plane_depth == PLACE_DEPTH_CURSOR_PLANE)) {
+ /* Cursor plane. */
+ float plane[4];
+ plane_from_point_normal_v3(
+ plane, ipd->scene->cursor.location, ipd->matrix_orient[ipd->orient_axis]);
+ if (ED_view3d_win_to_3d_on_plane(ipd->region, plane, mval_fl, false, ipd->co_src)) {
+ use_depth_fallback = false;
+ }
+ /* Even if the calculation works, it's possible the point found is behind the view. */
+ if (rv3d->is_persp) {
+ float dir[3];
+ sub_v3_v3v3(dir, rv3d->viewinv[3], ipd->co_src);
+ if (dot_v3v3(dir, rv3d->viewinv[2]) < ipd->v3d->clip_start) {
+ use_depth_fallback = true;
+ }
+ }
+ }
+
+ if (use_depth_fallback) {
+ float co_depth[3];
+ /* Fallback to view center. */
+ negate_v3_v3(co_depth, rv3d->ofs);
+ ED_view3d_win_to_3d(ipd->v3d, ipd->region, co_depth, mval_fl, ipd->co_src);
+ }
+ }
+
+ plane_from_point_normal_v3(
+ ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[ipd->orient_axis]);
+
+ copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
+}
+
+static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
+
+ struct InteractivePlaceData *ipd = MEM_callocN(sizeof(*ipd), __func__);
+ op->customdata = ipd;
+
+ ipd->scene = CTX_data_scene(C);
+ ipd->area = CTX_wm_area(C);
+ ipd->region = CTX_wm_region(C);
+ ipd->v3d = CTX_wm_view3d(C);
+
+ if (wait_for_input) {
+ ipd->wait_for_input = true;
+ /* TODO: support snapping when not using with tool. */
+#if 0
+ WM_gizmo_group_type_ensure(view3d_gzgt_placement_id);
+#endif
+ }
+ else {
+ view3d_interactive_add_begin(C, op, event);
+ }
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
+{
+ UNUSED_VARS(C);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ED_region_draw_cb_exit(ipd->region->type, ipd->draw_handle_view);
+
+ ED_region_tag_redraw(ipd->region);
+
+ MEM_freeN(ipd);
+}
+
+static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
+{
+ view3d_interactive_add_exit(C, op);
+}
+
+enum {
+ PLACE_MODAL_SNAP_ON,
+ PLACE_MODAL_SNAP_OFF,
+ PLACE_MODAL_FIXED_ASPECT_ON,
+ PLACE_MODAL_FIXED_ASPECT_OFF,
+ PLACE_MODAL_PIVOT_CENTER_ON,
+ PLACE_MODAL_PIVOT_CENTER_OFF,
+};
+
+void viewplace_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items[] = {
+ {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
+ {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
+ {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
+ {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
+ {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
+ {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ const char *keymap_name = "View3D Placement Modal Map";
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
+
+ /* This function is called for each space-type, only needs to add map once. */
+ if (keymap && keymap->modal_items) {
+ return;
+ }
+
+ keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
+
+ WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
+}
+
+static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ UNUSED_VARS(C, op);
+
+ struct InteractivePlaceData *ipd = op->customdata;
+
+ ARegion *region = ipd->region;
+ bool do_redraw = false;
+ bool do_cursor_update = false;
+
+ /* Handle modal key-map. */
+ if (event->type == EVT_MODAL_MAP) {
+ bool is_fallthrough = false;
+ switch (event->val) {
+ case PLACE_MODAL_FIXED_ASPECT_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_FIXED_ASPECT_OFF: {
+ ipd->step[ipd->step_index].is_fixed_aspect = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_PIVOT_CENTER_OFF: {
+ ipd->step[ipd->step_index].is_centered = is_fallthrough;
+ do_redraw = true;
+ break;
+ }
+ case PLACE_MODAL_SNAP_ON: {
+ is_fallthrough = true;
+ ATTR_FALLTHROUGH;
+ }
+ case PLACE_MODAL_SNAP_OFF: {
+ const ToolSettings *ts = ipd->scene->toolsettings;
+ ipd->is_snap_invert = is_fallthrough;
+ ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
+ do_cursor_update = true;
+ break;
+ }
+ }
+ }
+
+ if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ else if (event->type == MOUSEMOVE) {
+ do_cursor_update = true;
+ }
+
+ if (ipd->wait_for_input) {
+ if (ELEM(event->type, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ view3d_interactive_add_begin(C, op, event);
+ ipd->wait_for_input = false;
+ return OPERATOR_RUNNING_MODAL;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_RELEASE) {
+ /* Set secondary plane. */
+
+ /* Create normal. */
+ {
+ RegionView3D *rv3d = region->regiondata;
+ float no_temp[3];
+ float no[3];
+ cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
+ cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
+ normalize_v3(no);
+
+ plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
+ }
+
+ copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
+ ipd->step_index = STEP_DEPTH;
+
+ /* Keep these values from the previous step. */
+ ipd->step[1].is_centered = ipd->step[0].is_centered;
+ ipd->step[1].is_fixed_aspect = ipd->step[0].is_fixed_aspect;
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
+ if (event->val == KM_PRESS) {
+
+ BoundBox bounds;
+ calc_bbox(ipd, &bounds);
+
+ float location[3];
+ float rotation[3];
+ float scale[3];
+
+ float matrix_orient_axis[3][3];
+ copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
+ if (ipd->orient_axis != 2) {
+ swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
+ swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
+ }
+ /* Needed for shapes where the sign matters (cone for eg). */
+ {
+ float delta[3];
+ sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
+ if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
+ negate_v3(matrix_orient_axis[2]);
+
+ /* Only flip Y so we don't flip a single axis which causes problems. */
+ negate_v3(matrix_orient_axis[1]);
+ }
+ }
+
+ mat3_to_eul(rotation, matrix_orient_axis);
+
+ mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
+ const int cube_verts[3] = {3, 1, 4};
+ for (int i = 0; i < 3; i++) {
+ scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
+ }
+
+ wmOperatorType *ot = NULL;
+ PointerRNA op_props;
+ if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CUBE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CYLINDER) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
+ ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_UV) {
+ ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
+ }
+ else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_SPHERE_ICO) {
+ ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
+ }
+
+ if (ot != NULL) {
+ WM_operator_properties_create_ptr(&op_props, ot);
+
+ if (ipd->use_tool) {
+ bToolRef *tref = ipd->area->runtime.tool;
+ PointerRNA temp_props;
+ WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
+ SWAP(PointerRNA, temp_props, op_props);
+ WM_operator_properties_free(&temp_props);
+ }
+
+ RNA_float_set_array(&op_props, "rotation", rotation);
+ RNA_float_set_array(&op_props, "location", location);
+ RNA_float_set_array(&op_props, "scale", scale);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ WM_operator_properties_free(&op_props);
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ view3d_interactive_add_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+
+ if (do_cursor_update) {
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+
+ /* Calculate the snap location on mouse-move or when toggling snap. */
+ bool is_snap_found_prev = ipd->is_snap_found;
+ ipd->is_snap_found = false;
+ if (ipd->use_snap) {
+ if (ipd->snap_gizmo != NULL) {
+ ED_gizmotypes_snap_3d_toggle_set(ipd->snap_gizmo, ipd->use_snap);
+ if (ED_gizmotypes_snap_3d_update(ipd->snap_gizmo,
+ CTX_data_ensure_evaluated_depsgraph(C),
+ ipd->region,
+ ipd->v3d,
+ NULL,
+ mval_fl,
+ ipd->snap_co,
+ NULL)) {
+ ipd->is_snap_found = true;
+ }
+ ED_gizmotypes_snap_3d_toggle_clear(ipd->snap_gizmo);
+ }
+ }
+
+ /* Workaround because test_select doesn't run at the same time as the modal operator. */
+ if (is_snap_found_prev != ipd->is_snap_found) {
+ wmGizmoMap *gzmap = ipd->region->gizmo_map;
+ WM_gizmo_highlight_set(gzmap, ipd->is_snap_found ? ipd->snap_gizmo : NULL);
+ }
+
+ if (ipd->step_index == STEP_BASE) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[0].co_dst, ipd->step[0].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[0].plane, mval_fl, false, ipd->step[0].co_dst)) {
+ /* pass */
+ }
+ }
+ }
+ else if (ipd->step_index == STEP_DEPTH) {
+ if (ipd->is_snap_found) {
+ closest_to_plane_normalized_v3(ipd->step[1].co_dst, ipd->step[1].plane, ipd->snap_co);
+ }
+ else {
+ if (ED_view3d_win_to_3d_on_plane(
+ region, ipd->step[1].plane, mval_fl, false, ipd->step[1].co_dst)) {
+ /* pass */
+ }
+ }
+
+ /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
+ float close[3], delta[3];
+ closest_to_plane_normalized_v3(close, ipd->step[0].plane, ipd->step[1].co_dst);
+ sub_v3_v3v3(delta, close, ipd->step[0].co_dst);
+ sub_v3_v3(ipd->step[1].co_dst, delta);
+ }
+ do_redraw = true;
+ }
+
+ if (do_redraw) {
+ ED_region_tag_redraw(region);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool view3d_interactive_add_poll(bContext *C)
+{
+ const enum eContextObjectMode mode = CTX_data_mode_enum(C);
+ return ELEM(mode, CTX_MODE_OBJECT, CTX_MODE_EDIT_MESH);
+}
+
+void VIEW3D_OT_interactive_add(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Primitive Object";
+ ot->description = "Interactively add an object";
+ ot->idname = "VIEW3D_OT_interactive_add";
+
+ /* api callbacks */
+ ot->invoke = view3d_interactive_add_invoke;
+ ot->modal = view3d_interactive_add_modal;
+ ot->cancel = view3d_interactive_add_cancel;
+ ot->poll = view3d_interactive_add_poll;
+
+ /* Note, let the operator we call handle undo and registering it's self. */
+ /* flags */
+ ot->flag = 0;
+
+ /* properties */
+ PropertyRNA *prop;
+
+ /* Normally not accessed directly, leave unset and check the active tool. */
+ static const EnumPropertyItem primitive_type[] = {
+ {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
+ {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
+ {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
+ {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Primitive", "");
+ RNA_def_property_enum_items(prop, primitive_type);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ prop = RNA_def_property(ot->srna, "plane_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Plane Axis", "The axis used for placing the base region");
+ RNA_def_property_enum_default(prop, 2);
+ RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem plane_depth_items[] = {
+ {PLACE_DEPTH_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Start placing on the surface, using the 3D cursor position as a fallback"},
+ {PLACE_DEPTH_CURSOR_PLANE,
+ "CURSOR_PLANE",
+ 0,
+ "3D Cursor Plane",
+ "Start placement using a point projected onto the selected axis at the 3D cursor position"},
+ {PLACE_DEPTH_CURSOR_VIEW,
+ "CURSOR_VIEW",
+ 0,
+ "3D Cursor View",
+ "Start placement using the mouse cursor projected onto the view plane"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_depth", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Position", "The initial depth used when placing the cursor");
+ RNA_def_property_enum_default(prop, PLACE_DEPTH_SURFACE);
+ RNA_def_property_enum_items(prop, plane_depth_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ static const EnumPropertyItem origin_items[] = {
+ {PLACE_ORIGIN_BASE, "BASE", 0, "Base", "Start placing the corner position"},
+ {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
+ {0, NULL, 0, NULL, NULL},
+ };
+ prop = RNA_def_property(ot->srna, "plane_origin", PROP_ENUM, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
+ RNA_def_property_enum_default(prop, PLACE_ORIGIN_BASE);
+ RNA_def_property_enum_items(prop, origin_items);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ /* When not accessed via a tool. */
+ prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Placement Gizmo Group
+ *
+ * This is currently only used for snapping before the tool is initialized,
+ * we could show a placement plane here.
+ * \{ */
+
+static void WIDGETGROUP_placement_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
+{
+ wmGizmo *gizmo;
+
+ {
+ /* The gizmo snap has to be the first gizmo. */
+ const wmGizmoType *gzt_snap;
+ gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
+ gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+ RNA_enum_set(gizmo->ptr,
+ "snap_elements_force",
+ (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
+ /* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
+ SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
+
+ WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
+
+ /* Don't handle any events, this is for display only. */
+ gizmo->flag |= WM_GIZMO_HIDDEN_KEYMAP;
+ }
+}
+
+void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Placement Widget";
+ gzgt->idname = view3d_gzgt_placement_id;
+
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_SCALE | WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
+
+ gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
+ gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
+
+ gzgt->poll = ED_gizmo_poll_or_unlink_delayed_from_tool;
+ gzgt->setup = WIDGETGROUP_placement_setup;
+}
+
+/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 8fdef585fa2..8c60e36a141 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -157,7 +157,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
{
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
if (BASE_SELECTABLE(v3d, base)) {
ED_object_base_select(base, BA_DESELECT);
@@ -172,7 +172,7 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
{
bool changed = false;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
if (b != base) {
ED_object_base_select(base, BA_DESELECT);
@@ -408,9 +408,10 @@ typedef struct LassoSelectUserData {
const rcti *rect;
const rctf *rect_fl;
rctf _rect_fl;
- const int (*mcords)[2];
- int moves;
+ const int (*mcoords)[2];
+ int mcoords_len;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
int pass;
@@ -421,8 +422,8 @@ typedef struct LassoSelectUserData {
static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
ViewContext *vc,
const rcti *rect,
- const int (*mcords)[2],
- const int moves,
+ const int (*mcoords)[2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
r_data->vc = vc;
@@ -431,9 +432,11 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data,
r_data->rect_fl = &r_data->_rect_fl;
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
- r_data->mcords = mcords;
- r_data->moves = moves;
+ r_data->mcoords = mcoords;
+ 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;
/* runtime */
r_data->pass = 0;
@@ -527,7 +530,8 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_point_done = true;
}
}
@@ -536,22 +540,28 @@ static void do_lasso_select_pose__do_tag(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_point_done = true;
}
}
/* if one of points selected, we skip the bone itself */
- if ((is_point_done == true) ||
- ((is_point_done == false) && (points_proj_tot == 2) &&
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) {
+ if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) &&
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX))) {
pchan->bone->flag |= BONE_DONE;
}
data->is_changed |= is_point_done;
}
}
-static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves)
+static void do_lasso_tag_pose(ViewContext *vc,
+ Object *ob,
+ const int mcoords[][2],
+ const int mcoords_len)
{
ViewContext vc_tmp;
LassoSelectUserData data;
@@ -564,9 +574,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
vc_tmp = *vc;
vc_tmp.obact = ob;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0);
ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d);
@@ -574,8 +584,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2]
}
static bool do_lasso_select_objects(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
View3D *v3d = vc->v3d;
@@ -591,7 +601,7 @@ static bool do_lasso_select_objects(ViewContext *vc,
const bool is_select = base->flag & BASE_SELECTED;
const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) &&
BLI_lasso_is_point_inside(
- mcords, moves, base->sx, base->sy, IS_CLIPPED));
+ mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
if (sel_op_result != -1) {
ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT);
@@ -617,7 +627,7 @@ static Base **do_pose_tag_select_op_prepare(ViewContext *vc, uint *r_bases_len)
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;
- for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
Bone *bone = pchan->bone;
bone->flag &= ~BONE_DONE;
}
@@ -659,7 +669,7 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
bool changed = true;
- for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_iter->pose->chanbase) {
Bone *bone = pchan->bone;
if ((bone->flag & BONE_UNSELECTABLE) == 0) {
const bool is_select = bone->flag & BONE_SELECTED;
@@ -685,8 +695,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const
}
static bool do_lasso_select_pose(ViewContext *vc,
- const int mcords[][2],
- const short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
uint bases_len;
@@ -695,7 +705,7 @@ static bool do_lasso_select_pose(ViewContext *vc,
for (int i = 0; i < bases_len; i++) {
Base *base_iter = bases[i];
Object *ob_iter = base_iter->object;
- do_lasso_tag_pose(vc, ob_iter, mcords, moves);
+ 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);
@@ -715,9 +725,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData,
{
LassoSelectUserData *data = 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) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_vert_select_set(data->vc->em->bm, eve, sel_op_result);
@@ -746,8 +757,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data,
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
const bool is_inside =
(is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED));
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
@@ -770,8 +783,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data,
}
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
- const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords,
- data->moves,
+ const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
UNPACK2(screen_co_a),
UNPACK2(screen_co_b),
IS_CLIPPED));
@@ -789,9 +802,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
{
LassoSelectUserData *data = 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) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
BM_face_select_set(data->vc->em->bm, efa, sel_op_result);
@@ -801,8 +815,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData,
static bool do_lasso_select_mesh(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -812,9 +826,9 @@ static bool do_lasso_select_mesh(ViewContext *vc,
/* set editmesh */
vc->em = BKE_editmesh_from_object(vc->obedit);
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (vc->em->bm->totvertsel) {
@@ -836,7 +850,7 @@ static bool do_lasso_select_mesh(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -892,27 +906,28 @@ static void do_lasso_select_curve__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
LassoSelectUserData *data = userData;
const bool is_inside = BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED);
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED);
if (bp) {
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
}
bezt->f1 = bezt->f3 = bezt->f2;
data->is_changed = true;
@@ -922,7 +937,7 @@ static void do_lasso_select_curve__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -930,24 +945,35 @@ static void do_lasso_select_curve__doSelect(void *userData,
}
static bool do_lasso_select_curve(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
if (data.is_changed) {
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
}
@@ -958,9 +984,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
{
LassoSelectUserData *data = userData;
const bool is_select = bp->f1 & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
@@ -968,16 +995,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const
}
}
static bool do_lasso_select_lattice(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_lattice_flags_set(vc->obedit, 0);
@@ -1002,7 +1029,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_a[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) {
is_inside_flag |= BONESEL_ROOT;
}
}
@@ -1012,7 +1040,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (screen_co_b[0] != IS_CLIPPED) {
if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
- BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) {
is_inside_flag |= BONESEL_TIP;
}
}
@@ -1022,8 +1051,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
if (is_ignore_flag == 0) {
if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) ||
- BLI_lasso_is_edge_inside(
- data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) {
+ BLI_lasso_is_edge_inside(data->mcoords,
+ data->mcoords_len,
+ UNPACK2(screen_co_a),
+ UNPACK2(screen_co_b),
+ INT_MAX)) {
is_inside_flag |= BONESEL_BONE;
}
}
@@ -1033,16 +1065,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
}
static bool do_lasso_select_armature(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
rcti rect;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit);
@@ -1071,9 +1103,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = ml->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
@@ -1081,8 +1114,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData,
}
}
static bool do_lasso_select_meta(ViewContext *vc,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
LassoSelectUserData data;
@@ -1090,9 +1123,9 @@ static bool do_lasso_select_meta(ViewContext *vc,
MetaBall *mb = (MetaBall *)vc->obedit->data;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
data.is_changed |= BKE_mball_deselect_all(mb);
@@ -1113,9 +1146,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
{
LassoSelectUserData *data = userData;
const bool is_select = mv->flag & SELECT;
- const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
- BLI_lasso_is_point_inside(
- data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED));
+ const bool is_inside =
+ (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
+ BLI_lasso_is_point_inside(
+ data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED));
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT);
@@ -1124,8 +1158,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData,
}
static bool do_lasso_select_paintvert(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
const bool use_zbuf = !XRAY_ENABLED(vc->v3d);
@@ -1143,7 +1177,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (use_zbuf) {
@@ -1151,7 +1185,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
}
@@ -1163,7 +1197,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
else {
LassoSelectUserData data;
- view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op);
+ view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op);
ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
@@ -1185,8 +1219,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc,
}
static bool do_lasso_select_paintface(ViewContext *vc,
wmGenericUserData *wm_userdata,
- const int mcords[][2],
- short moves,
+ const int mcoords[][2],
+ const int mcoords_len,
const eSelectOp sel_op)
{
Object *ob = vc->obact;
@@ -1203,14 +1237,14 @@ static bool do_lasso_select_paintface(ViewContext *vc,
changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false);
}
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
struct EditSelectBuf_Cache *esel = wm_userdata->data;
if (esel == NULL) {
editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE);
esel = wm_userdata->data;
esel->select_bitmap = DRW_select_buffer_bitmap_from_poly(
- vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL);
+ vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL);
}
if (esel->select_bitmap) {
@@ -1224,9 +1258,9 @@ static bool do_lasso_select_paintface(ViewContext *vc,
}
#if 0
-static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op)
+static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op)
{
- SpaceNode *snode = sa->spacedata.first;
+ SpaceNode *snode = area->spacedata.first;
bNode *node;
rcti rect;
@@ -1234,7 +1268,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
float node_centf[2];
bool changed = false;
- BLI_lasso_boundbox(&rect, mcords, moves);
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
/* store selection in temp test flag */
for (node = snode->edittree->nodes.first; node; node = node->next) {
@@ -1244,7 +1278,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent);
const bool is_select = node->flag & SELECT;
const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) &&
- BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1]));
+ BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1]));
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(node->flag, sel_op_result, SELECT);
@@ -1257,8 +1291,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s
}
#endif
-static bool view3d_lasso_select(
- bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op)
+static bool view3d_lasso_select(bContext *C,
+ ViewContext *vc,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const eSelectOp sel_op)
{
Object *ob = CTX_data_active_object(C);
bool changed_multi = false;
@@ -1268,26 +1305,26 @@ static bool view3d_lasso_select(
if (vc->obedit == NULL) { /* Object Mode */
if (BKE_paint_select_face_test(ob)) {
- changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (BKE_paint_select_vert_test(ob)) {
- changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op);
}
else if (ob &&
(ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
/* pass */
}
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
- changed_multi |= PE_lasso_select(C, mcords, moves, sel_op);
+ changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_pose_bone_tag(C);
}
}
else {
- changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op);
+ changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op);
if (changed_multi) {
ED_outliner_select_sync_from_object_tag(C);
}
@@ -1300,23 +1337,23 @@ static bool view3d_lasso_select(
switch (vc->obedit->type) {
case OB_MESH:
- changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op);
+ changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op);
break;
case OB_CURVE:
case OB_SURF:
- changed = do_lasso_select_curve(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op);
break;
case OB_LATTICE:
- changed = do_lasso_select_lattice(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op);
break;
case OB_ARMATURE:
- changed = do_lasso_select_armature(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op);
if (changed) {
ED_outliner_select_sync_from_edit_bone_tag(C);
}
break;
case OB_MBALL:
- changed = do_lasso_select_meta(vc, mcords, moves, sel_op);
+ changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op);
break;
default:
BLI_assert(!"lasso select on incorrect object type");
@@ -1342,10 +1379,10 @@ static bool view3d_lasso_select(
static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
{
ViewContext vc;
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
- if (mcords) {
+ if (mcoords) {
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
@@ -1354,9 +1391,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
+ bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op);
- MEM_freeN((void *)mcords);
+ MEM_freeN((void *)mcoords);
if (changed_multi) {
return OPERATOR_FINISHED;
@@ -1663,20 +1700,31 @@ static int selectbuffer_ret_hits_5(uint *buffer,
/**
* Populate a select buffer with objects and bones, if there are any.
* Checks three selection levels and compare.
+ *
+ * \param do_nearest_xray_if_supported: When set, read in hits that don't stop
+ * at the nearest surface. The hit's must still be ordered by depth.
+ * Needed so we can step to the next, non-active object when it's already selected, see: T76445.
*/
static int mixed_bones_object_selectbuffer(ViewContext *vc,
uint *buffer,
const int mval[2],
eV3DSelectObjectFilter select_filter,
- bool do_nearest)
+ bool do_nearest,
+ bool do_nearest_xray_if_supported)
{
rcti rect;
int hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
- const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
+ int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
int hits = 0;
+ if (do_nearest_xray_if_supported) {
+ if ((U.gpu_flag & USER_GPU_FLAG_NO_DEPT_PICK) == 0) {
+ select_mode = VIEW3D_SELECT_PICK_ALL;
+ }
+ }
+
/* we _must_ end cache before return, use 'goto finally' */
view3d_opengl_select_cache_begin();
@@ -1780,7 +1828,7 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
- int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest);
+ int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
return hits;
}
@@ -1912,7 +1960,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest);
+ &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
@@ -1971,7 +2019,7 @@ static bool ed_object_select_pick(bContext *C,
/* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc, depsgraph);
- ARegion *region = CTX_wm_region(C);
+ const ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -2526,6 +2574,7 @@ typedef struct BoxSelectUserData {
const rctf *rect_fl;
rctf _rect_fl;
eSelectOp sel_op;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_done;
@@ -2544,6 +2593,8 @@ static void view3d_userdata_boxselect_init(BoxSelectUserData *r_data,
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
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;
/* runtime */
r_data->is_done = false;
@@ -2674,6 +2725,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool handles_visible,
const float screen_co[2])
{
BoxSelectUserData *data = userData;
@@ -2683,17 +2735,17 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = bp->f1 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
+ if (!handles_visible) {
+ /* can only be (beztindex == 1) here since handles are hidden */
const bool is_select = bezt->f2 & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, data->select_flag);
data->is_changed = true;
}
bezt->f1 = bezt->f3 = bezt->f2;
@@ -2703,7 +2755,7 @@ static void do_nurbs_box_select__doSelect(void *userData,
const bool is_select = *flag_p & SELECT;
const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
+ SET_FLAG_FROM_TEST(*flag_p, sel_op_result, data->select_flag);
data->is_changed = true;
}
}
@@ -2711,17 +2763,28 @@ static void do_nurbs_box_select__doSelect(void *userData,
}
static bool do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{
+ const bool deselect_all = (sel_op == SEL_OP_SET);
BoxSelectUserData data;
view3d_userdata_boxselect_init(&data, vc, rect, sel_op);
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = (Curve *)vc->obedit->data;
- data.is_changed |= ED_curve_deselect_all(curve->editnurb);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return data.is_changed;
@@ -3076,7 +3139,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
const int hits = view3d_opengl_select(
vc, vbuffer, 4 * (totobj + MAXPICKELEMS), rect, VIEW3D_SELECT_ALL, select_filter);
- for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &vc->view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
@@ -3092,7 +3155,7 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
goto finally;
}
- for (Base *base = vc->view_layer->object_bases.first; base; base = base->next) {
+ 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);
@@ -3104,9 +3167,9 @@ static bool do_object_box_select(bContext *C, ViewContext *vc, rcti *rect, const
qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp);
for (const uint *col = vbuffer + 3, *col_end = col + (hits * 4); col < col_end; col += 4) {
- Bone *bone;
- Base *base = ED_armature_base_and_bone_from_select_buffer(
- bases, BLI_array_len(bases), *col, &bone);
+ bPoseChannel *pchan_dummy;
+ Base *base = ED_armature_base_and_pchan_from_select_buffer(
+ bases, BLI_array_len(bases), *col, &pchan_dummy);
if (base != NULL) {
base->object->id.tag |= LIB_TAG_DOIT;
}
@@ -3360,6 +3423,7 @@ typedef struct CircleSelectUserData {
float mval_fl[2];
float radius;
float radius_squared;
+ eBezTriple_Flag select_flag;
/* runtime */
bool is_changed;
@@ -3380,6 +3444,9 @@ static void view3d_userdata_circleselect_init(CircleSelectUserData *r_data,
r_data->radius = rad;
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;
+
/* runtime */
r_data->is_changed = false;
}
@@ -3617,29 +3684,24 @@ static void nurbscurve_circle_doSelect(void *userData,
BPoint *bp,
BezTriple *bezt,
int beztindex,
+ bool UNUSED(handles_visible),
const float screen_co[2])
{
CircleSelectUserData *data = userData;
if (len_squared_v2v2(data->mval_fl, screen_co) <= data->radius_squared) {
if (bp) {
- bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT);
+ SET_FLAG_FROM_TEST(bp->f1, data->select, data->select_flag);
}
else {
- if ((data->vc->v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
- /* can only be (beztindex == 0) here since handles are hidden */
- bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
+ if (beztindex == 0) {
+ SET_FLAG_FROM_TEST(bezt->f1, data->select, data->select_flag);
+ }
+ else if (beztindex == 1) {
+ SET_FLAG_FROM_TEST(bezt->f2, data->select, data->select_flag);
}
else {
- if (beztindex == 0) {
- bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT);
- }
- else if (beztindex == 1) {
- bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT);
- }
- else {
- bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT);
- }
+ SET_FLAG_FROM_TEST(bezt->f3, data->select, data->select_flag);
}
}
data->is_changed = true;
@@ -3650,18 +3712,30 @@ static bool nurbscurve_circle_select(ViewContext *vc,
const int mval[2],
float rad)
{
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool deselect_all = (sel_op == SEL_OP_SET);
CircleSelectUserData data;
bool changed = false;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- Curve *curve = vc->obedit->data;
- changed |= ED_curve_deselect_all(curve->editnurb);
- }
- const bool select = (sel_op != SEL_OP_SUB);
view3d_userdata_circleselect_init(&data, vc, select, mval, rad);
+ Curve *curve = (Curve *)vc->obedit->data;
+ ListBase *nurbs = BKE_curve_editNurbs_get(curve);
+
+ /* For deselect all, items to be selected are tagged with temp flag. Clear that first. */
+ if (deselect_all) {
+ BKE_nurbList_flag_set(nurbs, BEZT_FLAG_TEMP_TAG, false);
+ data.select_flag = BEZT_FLAG_TEMP_TAG;
+ }
+
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
+
+ /* Deselect items that were not added to selection (indicated by temp flag). */
+ if (deselect_all) {
+ BKE_nurbList_flag_set_from_flag(nurbs, BEZT_FLAG_TEMP_TAG, SELECT);
+ }
+
BKE_curve_nurb_vert_active_validate(vc->obedit->data);
return changed || data.is_changed;
diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c
index 2637fb6d1db..377e8c58ba3 100644
--- a/source/blender/editors/space_view3d/view3d_utils.c
+++ b/source/blender/editors/space_view3d/view3d_utils.c
@@ -86,6 +86,26 @@ void ED_view3d_background_color_get(const Scene *scene, const View3D *v3d, float
UI_GetThemeColor3fv(TH_BACK, r_color);
}
+bool ED_view3d_has_workbench_in_texture_color(const Scene *scene,
+ const Object *ob,
+ const View3D *v3d)
+{
+ if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ return true;
+ }
+ if (ob->mode == OB_MODE_TEXTURE_PAINT) {
+ return true;
+ }
+ }
+ else if (v3d->shading.type == OB_RENDER) {
+ if (STREQ(scene->r.engine, RE_engine_id_BLENDER_WORKBENCH)) {
+ return scene->display.shading.color_type == V3D_SHADING_TEXTURE_COLOR;
+ }
+ }
+ return false;
+}
+
Camera *ED_view3d_camera_data_get(View3D *v3d, RegionView3D *rv3d)
{
/* establish the camera object,
@@ -228,26 +248,26 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
bool ED_view3d_context_activate(bContext *C)
{
- bScreen *sc = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region;
- /* sa can be NULL when called from python */
- if (sa == NULL || sa->spacetype != SPACE_VIEW3D) {
- sa = BKE_screen_find_big_area(sc, SPACE_VIEW3D, 0);
+ /* area can be NULL when called from python */
+ if (area == NULL || area->spacetype != SPACE_VIEW3D) {
+ area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0);
}
- if (sa == NULL) {
+ if (area == NULL) {
return false;
}
- region = BKE_area_find_region_active_win(sa);
+ region = BKE_area_find_region_active_win(area);
if (region == NULL) {
return false;
}
/* bad context switch .. */
- CTX_wm_area_set(C, sa);
+ CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
return true;
@@ -666,7 +686,7 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d,
* Use with quad-split so each view is clipped by the bounds of each view axis.
* \{ */
-static void view3d_boxview_clip(ScrArea *sa)
+static void view3d_boxview_clip(ScrArea *area)
{
ARegion *region;
BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
@@ -675,7 +695,7 @@ static void view3d_boxview_clip(ScrArea *sa)
int val;
/* create bounding box */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -747,7 +767,7 @@ static void view3d_boxview_clip(ScrArea *sa)
}
/* create bounding box */
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -812,13 +832,13 @@ static void view3d_boxview_sync_axis(RegionView3D *rv3d_dst, RegionView3D *rv3d_
}
/* sync center/zoom view of region to others, for view transforms */
-void view3d_boxview_sync(ScrArea *sa, ARegion *region)
+void view3d_boxview_sync(ScrArea *area, ARegion *region)
{
ARegion *artest;
RegionView3D *rv3d = region->regiondata;
short clip = 0;
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ for (artest = area->regionbase.first; artest; artest = artest->next) {
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3dtest = artest->regiondata;
@@ -833,18 +853,18 @@ void view3d_boxview_sync(ScrArea *sa, ARegion *region)
}
if (clip) {
- view3d_boxview_clip(sa);
+ view3d_boxview_clip(area);
}
}
/* for home, center etc */
-void view3d_boxview_copy(ScrArea *sa, ARegion *region)
+void view3d_boxview_copy(ScrArea *area, ARegion *region)
{
ARegion *artest;
RegionView3D *rv3d = region->regiondata;
bool clip = false;
- for (artest = sa->regionbase.first; artest; artest = artest->next) {
+ for (artest = area->regionbase.first; artest; artest = artest->next) {
if (artest != region && artest->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3dtest = artest->regiondata;
@@ -859,14 +879,14 @@ void view3d_boxview_copy(ScrArea *sa, ARegion *region)
}
if (clip) {
- view3d_boxview_clip(sa);
+ view3d_boxview_clip(area);
}
}
/* 'clip' is used to know if our clip setting has changed */
-void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
+void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip)
{
- ARegion *ar_sync = NULL;
+ ARegion *region_sync = NULL;
RegionView3D *rv3d = region->regiondata;
short viewlock;
/* this function copies flags from the first of the 3 other quadview
@@ -892,21 +912,21 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
rv3d->rflag &= ~RV3D_BOXCLIP;
}
- /* use ar_sync so we sync with one of the aligned views below
+ /* use region_sync so we sync with one of the aligned views below
* else the view jumps on changing view settings like 'clip'
* since it copies from the perspective view */
- ar_sync = region;
+ region_sync = region;
}
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_sync(sa, ar_sync ? ar_sync : sa->regionbase.last);
+ view3d_boxview_sync(area, region_sync ? region_sync : area->regionbase.last);
}
/* ensure locked regions have an axis, locked user views don't make much sense */
if (viewlock & RV3D_LOCK_ROTATION) {
int index_qsplit = 0;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->alignment == RGN_ALIGN_QSPLIT) {
rv3d = region->regiondata;
if (rv3d->viewlock) {
@@ -922,7 +942,7 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *region, bool do_clip)
}
}
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
}
/** \} */
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 30587e6084d..fe77ca05a04 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -128,7 +128,7 @@ void ED_view3d_smooth_view_ex(
const Depsgraph *depsgraph,
wmWindowManager *wm,
wmWindow *win,
- ScrArea *sa,
+ ScrArea *area,
View3D *v3d,
ARegion *region,
const int smooth_viewtx,
@@ -293,7 +293,7 @@ void ED_view3d_smooth_view_ex(
}
if (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW) {
- view3d_boxview_copy(sa, region);
+ view3d_boxview_copy(area, region);
}
ED_region_tag_redraw(region);
@@ -309,9 +309,9 @@ void ED_view3d_smooth_view(bContext *C,
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- ED_view3d_smooth_view_ex(depsgraph, wm, win, sa, v3d, region, smooth_viewtx, sview);
+ ED_view3d_smooth_view_ex(depsgraph, wm, win, area, v3d, region, smooth_viewtx, sview);
}
/* only meant for timer usage */
@@ -615,17 +615,18 @@ static void sync_viewport_camera_smoothview(bContext *C,
if (v3d->scenelock) {
ListBase *lb = (space_link == area->spacedata.first) ? &area->regionbase :
&space_link->regionbase;
- for (ARegion *other_ar = lb->first; other_ar != NULL; other_ar = other_ar->next) {
- if (other_ar->regiontype == RGN_TYPE_WINDOW) {
- if (other_ar->regiondata) {
- RegionView3D *other_rv3d = other_ar->regiondata;
+ for (ARegion *other_region = lb->first; other_region != NULL;
+ other_region = other_region->next) {
+ if (other_region->regiontype == RGN_TYPE_WINDOW) {
+ if (other_region->regiondata) {
+ RegionView3D *other_rv3d = other_region->regiondata;
if (other_rv3d->persp == RV3D_CAMOB) {
Object *other_camera_old = other_v3d->camera;
other_v3d->camera = ob;
ED_view3d_lastview_store(other_rv3d);
ED_view3d_smooth_view(C,
other_v3d,
- other_ar,
+ other_region,
smooth_viewtx,
&(const V3D_SmoothParams){
.camera_old = other_camera_old,
@@ -704,9 +705,9 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
bool ED_operator_rv3d_user_region_poll(bContext *C)
{
View3D *v3d_dummy;
- ARegion *ar_dummy;
+ ARegion *region_dummy;
- return ED_view3d_context_user_region(C, &v3d_dummy, &ar_dummy);
+ return ED_view3d_context_user_region(C, &v3d_dummy, &region_dummy);
}
void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
@@ -1061,7 +1062,7 @@ int view3d_opengl_select(ViewContext *vc,
* the number of items is nearly always 1, maybe 2..3 in rare cases. */
LinkNode *ob_pose_list = NULL;
VirtualModifierData virtualModifierData;
- const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData);
+ const ModifierData *md = BKE_modifiers_get_virtual_modifierlist(obact, &virtualModifierData);
for (; md; md = md->next) {
if (md->type == eModifierType_Armature) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -1199,16 +1200,16 @@ finally:
static uint free_localview_bit(Main *bmain)
{
- ScrArea *sa;
- bScreen *sc;
+ ScrArea *area;
+ bScreen *screen;
ushort local_view_bits = 0;
/* sometimes we loose a localview: when an area is closed */
/* check all areas: which localviews are in use? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
for (; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -1234,12 +1235,12 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
wmWindow *win,
Main *bmain,
ViewLayer *view_layer,
- ScrArea *sa,
+ ScrArea *area,
const bool frame_selected,
const int smooth_viewtx,
ReportList *reports)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Base *base;
float min[3], max[3], box[3];
float size = 0.0f;
@@ -1301,7 +1302,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
memcpy(v3d->localvd, v3d, sizeof(View3D));
v3d->local_view_uuid = local_view_bit;
- for (region = sa->regionbase.first; region; region = region->next) {
+ for (region = area->regionbase.first; region; region = region->next) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
bool ok_dist = true;
@@ -1342,7 +1343,7 @@ static bool view3d_localview_init(const Depsgraph *depsgraph,
ED_view3d_smooth_view_ex(depsgraph,
wm,
win,
- sa,
+ area,
v3d,
region,
smooth_viewtx,
@@ -1364,11 +1365,11 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
wmWindowManager *wm,
wmWindow *win,
ViewLayer *view_layer,
- ScrArea *sa,
+ ScrArea *area,
const bool frame_selected,
const int smooth_viewtx)
{
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
if (v3d->localvd == NULL) {
return;
@@ -1389,7 +1390,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
MEM_freeN(v3d->localvd);
v3d->localvd = NULL;
- for (ARegion *region = sa->regionbase.first; region; region = region->next) {
+ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
if (region->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = region->regiondata;
@@ -1410,7 +1411,7 @@ static void view3d_localview_exit(const Depsgraph *depsgraph,
ED_view3d_smooth_view_ex(depsgraph,
wm,
win,
- sa,
+ area,
v3d,
region,
smooth_viewtx,
@@ -1438,23 +1439,23 @@ static int localview_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);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
View3D *v3d = CTX_wm_view3d(C);
bool frame_selected = RNA_boolean_get(op->ptr, "frame_selected");
bool changed;
if (v3d->localvd) {
- view3d_localview_exit(depsgraph, wm, win, view_layer, sa, frame_selected, smooth_viewtx);
+ view3d_localview_exit(depsgraph, wm, win, view_layer, area, frame_selected, smooth_viewtx);
changed = true;
}
else {
changed = view3d_localview_init(
- depsgraph, wm, win, bmain, view_layer, sa, frame_selected, smooth_viewtx, op->reports);
+ depsgraph, wm, win, bmain, view_layer, area, frame_selected, smooth_viewtx, op->reports);
}
if (changed) {
DEG_id_type_tag(bmain, ID_OB);
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw(area);
/* Unselected objects become selected when exiting. */
if (v3d->localvd == NULL) {
@@ -1555,19 +1556,17 @@ void VIEW3D_OT_localview_remove_from(wmOperatorType *ot)
/** \name Local Collections
* \{ */
-static uint free_localcollection_bit(Main *bmain,
- unsigned short local_collections_uuid,
- bool *r_reset)
+static uint free_localcollection_bit(Main *bmain, ushort local_collections_uuid, bool *r_reset)
{
- ScrArea *sa;
- bScreen *sc;
+ ScrArea *area;
+ bScreen *screen;
ushort local_view_bits = 0;
/* Check all areas: which localviews are in use? */
- for (sc = bmain->screens.first; sc; sc = sc->id.next) {
- for (sa = sc->areabase.first; sa; sa = sa->next) {
- SpaceLink *sl = sa->spacedata.first;
+ for (screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (area = screen->areabase.first; area; area = area->next) {
+ SpaceLink *sl = area->spacedata.first;
for (; sl; sl = sl->next) {
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
@@ -1596,7 +1595,7 @@ static uint free_localcollection_bit(Main *bmain,
}
static void local_collections_reset_uuid(LayerCollection *layer_collection,
- const unsigned short local_view_bit)
+ const ushort local_view_bit)
{
if (layer_collection->flag & LAYER_COLLECTION_HIDE) {
layer_collection->local_collections_bits &= ~local_view_bit;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 89b5618075a..7aefd173953 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -160,14 +160,14 @@ void walk_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Walk Modal");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Walk Modal");
/* this function is called for each spacetype, only needs to add map once */
if (keymap && keymap->modal_items) {
return;
}
- keymap = WM_modalkeymap_add(keyconf, "View3D Walk Modal", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "View3D Walk Modal", modal_items);
/* assign map to operators */
WM_modalkeymap_assign(keymap, "VIEW3D_OT_walk");
@@ -374,16 +374,19 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
mul_v3_v3fl(dvec_tmp, dvec, walk->grid);
add_v3_v3(ray_start, dvec_tmp);
- ret = ED_transform_snap_object_project_ray(walk->snap_context,
- walk->depsgraph,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- },
- ray_start,
- ray_normal,
- r_distance,
- r_location,
- r_normal_dummy);
+ ret = ED_transform_snap_object_project_ray(
+ walk->snap_context,
+ walk->depsgraph,
+ &(const struct SnapObjectParams){
+ .snap_select = SNAP_ALL,
+ /* Avoid having to convert the edit-mesh to a regular mesh. */
+ .use_object_edit_cage = true,
+ },
+ ray_start,
+ ray_normal,
+ r_distance,
+ r_location,
+ r_normal_dummy);
/* artificially scale the distance to the scene size */
*r_distance /= walk->grid;
@@ -449,7 +452,6 @@ static float userdef_speed = -1.f;
static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- Main *bmain = CTX_data_main(C);
wmWindow *win = CTX_wm_window(C);
walk->rv3d = CTX_wm_region_view3d(C);
@@ -553,7 +555,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
walk->snap_context = ED_transform_snap_object_context_create_view3d(
- bmain, walk->scene, 0, walk->region, walk->v3d);
+ walk->scene, 0, walk->region, walk->v3d);
walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->depsgraph,
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index 0ea355e9b6e..79090bd633e 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -49,6 +49,7 @@
#include "ED_space_api.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
#include "UI_interface_icons.h"
@@ -77,7 +78,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3]);
bool transdata_check_local_islands(TransInfo *t, short around)
{
- return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH))));
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH, OB_GPENCIL))));
}
/* ************************** SPACE DEPENDENT CODE **************************** */
@@ -110,7 +111,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
copy_v3_fl(r_aspect, 1.0f);
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
@@ -123,7 +124,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = t->sa->spacedata.first;
+ SpaceClip *sclip = t->area->spacedata.first;
if (t->options & CTX_MOVIECLIP) {
ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
@@ -234,7 +235,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
float v[2];
@@ -265,7 +266,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
else if (t->spacetype == SPACE_ACTION) {
int out[2] = {0, 0};
#if 0
- SpaceAction *sact = t->sa->spacedata.first;
+ SpaceAction *sact = t->area->spacedata.first;
if (sact->flag & SACTION_DRAWTIME) {
//vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
@@ -296,7 +297,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[1] = out[1];
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (t->options & CTX_MASK) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -377,7 +378,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) &&
!(t->options & CTX_PAINT_CURVE)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -401,7 +402,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
void removeAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -453,18 +454,18 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- // SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ // SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_GRAPH) {
- // SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ // SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NLA) {
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NODE) {
- // ED_area_tag_redraw(t->sa);
+ // ED_area_tag_redraw(t->area);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
}
else if (t->spacetype == SPACE_SEQ) {
@@ -483,21 +484,21 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
WM_paint_cursor_tag_redraw(window, t->region);
}
else if (t->flag & T_CURSOR) {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
else {
// XXX how to deal with lock?
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ 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);
}
else {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -517,7 +518,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
static void viewRedrawPost(bContext *C, TransInfo *t)
{
- ED_area_status_text(t->sa, NULL);
+ ED_area_status_text(t->area, NULL);
if (t->spacetype == SPACE_VIEW3D) {
/* if autokeying is enabled, send notifiers that keyframes were added */
@@ -559,7 +560,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
/* ************************** TRANSFORMATIONS **************************** */
-static void view_editmove(unsigned short UNUSED(event))
+static void view_editmove(ushort UNUSED(event))
{
#if 0 // TRANSFORM_FIX_ME
int refresh = 0;
@@ -770,17 +771,18 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Transform Modal Map");
- keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Transform Modal Map", modal_items);
keymap->poll_modal_item = transform_modal_item_poll;
return keymap;
}
-static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
+static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane)
{
if (!(t->flag & T_NO_CONSTRAINT)) {
+ char cmode = constraintModeToChar(t);
int constraint_axis, constraint_plane;
const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
@@ -824,11 +826,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
else if (!edit_2d) {
- if (cmode != axis) {
- /* First press, constraint to an axis. */
- t->orientation.index = 0;
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
+ if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) {
+ /* Successive presses on existing axis, cycle orientation modes. */
+ t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient));
+ transform_orientations_current_set(t, t->orient_curr);
+ }
+
+ if (t->orient_curr == 0) {
+ stopConstraint(t);
+ }
+ else {
+ const short orientation = t->orient[t->orient_curr].type;
if (is_plane == false) {
setUserConstraint(t, orientation, constraint_axis, msg2);
}
@@ -836,24 +844,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
setUserConstraint(t, orientation, constraint_plane, msg3);
}
}
- else {
- /* Successive presses on existing axis, cycle orientation modes. */
- t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
-
- if (t->orientation.index == 0) {
- stopConstraint(t);
- }
- else {
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
- }
- }
}
t->redraw |= TREDRAW_HARD;
}
@@ -861,7 +851,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
int transformEvent(TransInfo *t, const wmEvent *event)
{
- char cmode = constraintModeToChar(t);
bool handled = false;
const int modifiers_prev = t->modifiers;
const int mode_prev = t->mode;
@@ -908,74 +897,59 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_TRANSLATE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
- restoreTransObjects(t);
- resetTransModal(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_SEQ_SLIDE) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else {
- if (t->obedit_type == OB_MESH) {
- if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
- restoreTransObjects(t);
+ if (t->mode == TFM_TRANSLATION) {
+ if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+
+ /* first try edge slide */
+ transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
+ /* if that fails, do vertex slide */
+ if (t->state == TRANS_CANCEL) {
resetTransModal(t);
+ t->state = TRANS_STARTING;
+ transform_mode_init(t, NULL, TFM_VERT_SLIDE);
+ }
+ /* vert slide can fail on unconnected vertices (rare but possible) */
+ if (t->state == TRANS_CANCEL) {
+ resetTransModal(t);
+ t->state = TRANS_STARTING;
+ restoreTransObjects(t);
resetTransRestrictions(t);
-
- /* first try edge slide */
- transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
- /* if that fails, do vertex slide */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- transform_mode_init(t, NULL, TFM_VERT_SLIDE);
- }
- /* vert slide can fail on unconnected vertices (rare but possible) */
- if (t->state == TRANS_CANCEL) {
- resetTransModal(t);
- t->state = TRANS_STARTING;
- restoreTransObjects(t);
- resetTransRestrictions(t);
- transform_mode_init(t, NULL, TFM_TRANSLATION);
- }
- initSnapping(t, NULL); // need to reinit after mode change
- t->redraw |= TREDRAW_HARD;
- handled = true;
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
}
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
- if (t->mode == TFM_TRANSLATION) {
- restoreTransObjects(t);
+ restoreTransObjects(t);
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
}
}
+ else if (t->mode == TFM_SEQ_SLIDE) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
+ restoreTransObjects(t);
+ resetTransModal(t);
+ resetTransRestrictions(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
+ initSnapping(t, NULL); // need to reinit after mode change
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
break;
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_RESIZE,
- TFM_TRACKBALL,
- TFM_TRANSLATION,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -994,15 +968,23 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_RESIZE:
/* only switch when... */
- if (ELEM(t->mode,
- TFM_ROTATION,
- TFM_TRANSLATION,
- TFM_TRACKBALL,
- TFM_EDGE_SLIDE,
- TFM_VERT_SLIDE)) {
+ if (t->mode == TFM_RESIZE) {
+ if (t->options & CTX_MOVIECLIP) {
+ restoreTransObjects(t);
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ }
+ else if (t->mode == TFM_SHRINKFATTEN) {
+ t->flag ^= T_ALT_TRANSFORM;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ }
+ else if (transform_mode_is_changeable(t->mode)) {
/* Scale isn't normally very useful after extrude along normals, see T39756 */
- if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) {
+ if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) {
stopConstraint(t);
}
@@ -1014,20 +996,6 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw |= TREDRAW_HARD;
handled = true;
}
- else if (t->mode == TFM_SHRINKFATTEN) {
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- else if (t->mode == TFM_RESIZE) {
- if (t->options & CTX_MOVIECLIP) {
- restoreTransObjects(t);
-
- t->flag ^= T_ALT_TRANSFORM;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- }
- }
break;
case TFM_MODAL_SNAP_INV_ON:
@@ -1047,42 +1015,42 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_AXIS_X:
if (!(t->flag & T_NO_CONSTRAINT)) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_XKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Y:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_YKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Z:
if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_ZKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_X:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_XKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_XKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Y:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_YKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_YKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Z:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_ZKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
@@ -1160,9 +1128,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
- BLI_assert(t->sa->spacetype == t->spacetype);
+ BLI_assert(t->area->spacetype == t->spacetype);
if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
@@ -1228,17 +1196,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
}
else {
- if (event->shift) {
- /* bit hackish... but it prevents mmb select to print the
- * orientation from menu */
- float mati[3][3];
- strcpy(t->spacename, "global");
- unit_m3(mati);
- initSelectConstraint(t, mati);
- }
- else {
- initSelectConstraint(t, t->spacemtx);
- }
+ initSelectConstraint(t);
postSelectConstraint(t);
}
}
@@ -1251,7 +1209,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1266,7 +1224,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
}
/* only switch when... */
- if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
+ if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1282,7 +1240,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
- if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
+ if (transform_mode_is_changeable(t->mode)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
@@ -1521,9 +1479,9 @@ static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegi
ok = true;
}
else {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
ok = true;
}
@@ -1576,7 +1534,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *region)
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
*/
- unsigned char color[3];
+ uchar color[3];
UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
BLF_color3ubv(font_id, color);
#ifdef WITH_INTERNATIONAL
@@ -1637,6 +1595,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
int proportional = 0;
PropertyRNA *prop;
+ if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) &&
+ ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) {
+ /* When redoing these modes the first time, it's more convenient to save
+ * the Global orientation. */
+ mul_m3_v3(t->spacemtx, t->values_final);
+ unit_m3(t->spacemtx);
+
+ BLI_assert(t->orient_curr == 0);
+ t->orient[0].type = V3D_ORIENT_GLOBAL;
+ }
+
// Save back mode in case we're in the generic operator
if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
RNA_property_enum_set(op->ptr, prop, t->mode);
@@ -1651,11 +1620,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "center_override"))) {
- /* Important for redo operations. */
- RNA_property_float_set_array(op->ptr, prop, t->center_global);
- }
-
if (t->flag & T_PROP_EDIT_ALL) {
if (t->flag & T_PROP_EDIT) {
proportional |= PROP_EDIT_USE;
@@ -1704,28 +1668,19 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
-
- if (t->spacetype == SPACE_VIEW3D) {
- if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- !RNA_property_is_set(op->ptr, prop) &&
- (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- orient_slot->type = t->orientation.user;
- BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
- (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
- orient_slot->index_custom));
- }
- }
}
if (t->flag & T_MODAL) {
/* do we check for parameter? */
if (transformModeUseSnap(t)) {
- if (t->modifiers & MOD_SNAP) {
- ts->snap_flag |= SCE_SNAP;
- }
- else {
- ts->snap_flag &= ~SCE_SNAP;
+ if (!(t->modifiers & MOD_SNAP) != !(ts->snap_flag & SCE_SNAP)) {
+ if (t->modifiers & MOD_SNAP) {
+ ts->snap_flag |= SCE_SNAP;
+ }
+ else {
+ ts->snap_flag &= ~SCE_SNAP;
+ }
+ WM_msg_publish_rna_prop(t->mbus, &t->scene->id, ts, ToolSettings, use_snap);
}
}
}
@@ -1742,33 +1697,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
- /* Orientation used for redo. */
- const bool use_orient_axis = (t->orient_matrix_is_set &&
- (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
- short orientation;
- if (t->con.mode & CON_APPLY) {
- orientation = t->con.orientation;
- if (orientation == V3D_ORIENT_CUSTOM) {
- const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
- t->scene, t->orientation.custom);
- /* Maybe we need a t->con.custom_orientation?
- * Seems like it would always match t->orientation.custom. */
- orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
- BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- }
- }
- else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
- (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
- orientation = RNA_property_enum_get(op->ptr, prop);
- }
- else if (use_orient_axis) {
- /* We're not using an orientation, use the fallback. */
- orientation = t->orientation.unset;
- }
- else {
- orientation = V3D_ORIENT_GLOBAL;
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
if (t->flag & T_MODAL) {
if (t->con.mode & CON_APPLY) {
@@ -1788,56 +1716,41 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
- }
- }
- if (t->con.mode & CON_APPLY) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]);
- }
- else if (use_orient_axis) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]);
- }
- else {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
- }
- }
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
- /* constraint orientation can be global, even if user selects something else
- * so use the orientation in the constraint if set */
+ short orient_type_set, orient_type_curr;
+ orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) :
+ -1;
+ orient_type_curr = t->orient[t->orient_curr].type;
- /* Use 'orient_matrix' instead. */
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- RNA_property_enum_set(op->ptr, prop, orientation);
- }
+ if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+ RNA_property_enum_set(op->ptr, prop, orient_type_curr);
+ orient_type_set = orient_type_curr;
+ }
+
+ if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ !RNA_property_is_set(op->ptr, prop))) {
+ /* Set the first time to register on redo. */
+ RNA_property_enum_set(op->ptr, prop, orient_type_set);
+ RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
}
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
bool constraint_axis[3] = {false, false, false};
- if (t->flag & T_MODAL) {
- /* Only set if needed, so we can hide in the UI when nothing is set.
- * See 'transform_poll_property'. */
- if (t->con.mode & CON_APPLY) {
- if (t->con.mode & CON_AXIS0) {
- constraint_axis[0] = true;
- }
- if (t->con.mode & CON_AXIS1) {
- constraint_axis[1] = true;
- }
- if (t->con.mode & CON_AXIS2) {
- constraint_axis[2] = true;
- }
+ if (t->con.mode & CON_APPLY) {
+ if (t->con.mode & CON_AXIS0) {
+ constraint_axis[0] = true;
}
- if (ELEM(true, UNPACK3(constraint_axis))) {
- RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ if (t->con.mode & CON_AXIS1) {
+ constraint_axis[1] = true;
}
+ if (t->con.mode & CON_AXIS2) {
+ constraint_axis[2] = true;
+ }
+ RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ }
+ else {
+ RNA_property_unset(op->ptr, prop);
}
}
@@ -1870,7 +1783,7 @@ static void initSnapSpatial(TransInfo *t, float r_snap[3])
RegionView3D *rv3d = t->region->regiondata;
if (rv3d) {
- View3D *v3d = t->sa->spacedata.first;
+ View3D *v3d = t->area->spacedata.first;
r_snap[0] = 0.0f;
r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f;
r_snap[2] = r_snap[1] * 0.1f;
@@ -1963,7 +1876,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
- initTransformOrientation(C, t);
+
+ /* Use the custom orientation when it is set. */
+ short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr;
+ transform_orientations_current_set(t, orient_index);
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_apply = ED_region_draw_cb_activate(
@@ -1972,62 +1888,38 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(
t->region->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_NODE) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_GRAPH) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
- t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
- RGN_TYPE_ANY,
- transform_draw_cursor_poll,
- transform_draw_cursor_draw,
- t);
+ t->draw_handle_cursor = WM_paint_cursor_activate(
+ SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
}
createTransData(C, t); // make TransData structs from selection
@@ -2088,33 +1980,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
- /* Overwrite initial values if operator supplied a non-null vector.
- *
- * Run before init functions so 'values_modal_offset' can be applied on mouse input.
- */
- BLI_assert(is_zero_v4(t->values_modal_offset));
- if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
- float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
-
- if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
- }
- else {
- values[0] = RNA_float_get(op->ptr, "value");
- }
-
- copy_v4_v4(t->values, values);
-
- if (t->flag & T_MODAL) {
- copy_v4_v4(t->values_modal_offset, values);
- t->redraw = TREDRAW_HARD;
- }
- else {
- copy_v4_v4(t->values, values);
- t->flag |= T_INPUT_IS_VALUES_FINAL;
- }
- }
-
if (event) {
/* Initialize accurate transform to settings requested by keymap. */
bool use_accurate = false;
@@ -2145,38 +2010,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Constraint init from operator */
- if ((t->flag & T_MODAL) ||
- /* For mirror operator the constraint axes are effectively the values. */
- (RNA_struct_find_property(op->ptr, "value") == NULL)) {
- if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
- RNA_property_is_set(op->ptr, prop)) {
- bool constraint_axis[3];
-
- RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
- if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
- t->con.mode |= CON_APPLY;
-
- if (constraint_axis[0]) {
- t->con.mode |= CON_AXIS0;
- }
- if (constraint_axis[1]) {
- t->con.mode |= CON_AXIS1;
- }
- if (constraint_axis[2]) {
- t->con.mode |= CON_AXIS2;
- }
-
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
- }
- }
- else {
- /* So we can adjust in non global orientation. */
- if (t->orientation.user != V3D_ORIENT_GLOBAL) {
- t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
+ if (t->con.mode & CON_APPLY) {
+ setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s");
}
/* Don't write into the values when non-modal because they are already set from operator redo
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index a2c8caba0f5..192728f63d2 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -113,13 +113,8 @@ typedef struct TransSnap {
} TransSnap;
typedef struct TransCon {
- short orientation;
/** Description of the constraint for header_print. */
char text[50];
- /** Matrix of the constraint space. */
- float mtx[3][3];
- /** Inverse matrix of the constraint space. */
- float imtx[3][3];
/** Projection constraint matrix (same as #imtx with some axis == 0). */
float pmtx[3][3];
/** Initial mouse value for visual calculation
@@ -139,8 +134,7 @@ typedef struct TransCon {
struct TransDataContainer *tc,
struct TransData *td,
const float in[3],
- float out[3],
- float pvec[3]);
+ float out[3]);
/** Apply function pointer for size transformation. */
void (*applySize)(struct TransInfo *t,
struct TransDataContainer *tc,
@@ -520,6 +514,7 @@ typedef struct TransInfo {
/** orientation matrix of the current space. */
float spacemtx[3][3];
+ float spacemtx_inv[3][3];
/** name of the current space, MAX_NAME. */
char spacename[64];
@@ -531,18 +526,11 @@ typedef struct TransInfo {
bool is_launch_event_tweak;
struct {
- /** Orientation type when when we're not constrained.
- * nearly always global except for rotate which defaults to screen-space orientation. */
- short unset;
- /** Orientation to use when a key is pressed. */
- short user;
- /* Used when user is global. */
- short user_alt;
- short index;
- short *types[2];
- /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
- struct TransformOrientation *custom;
- } orientation;
+ short type;
+ float matrix[3][3];
+ } orient[3];
+ short orient_curr;
+
/** backup from view3d, to restore on end. */
short gizmo_flag;
@@ -566,22 +554,14 @@ typedef struct TransInfo {
/** Secondary axis, shear uses this. */
int orient_axis_ortho;
- /** Often this matrix has similar usage to #TransInfo.spacemtx however this
- * is used to define extra axes to operate on, not necessarily a space.
- *
- * For example, by default rotation operates on the view (`orient_matrix[2]`),
- * even when the current space isn't set to the view. */
- float orient_matrix[3][3];
- /** Don't overwrite when set by operator redo defines the orientation axis. */
- bool orient_matrix_is_set;
-
/** remove elements if operator is canceled. */
bool remove_on_cancel;
void *view;
/** Only valid (non null) during an operator called function. */
struct bContext *context;
- struct ScrArea *sa;
+ struct wmMsgBus *mbus;
+ struct ScrArea *area;
struct ARegion *region;
struct Depsgraph *depsgraph;
struct Scene *scene;
@@ -631,52 +611,53 @@ enum {
T_CURSOR = 1 << 5,
/** Transform points, having no rotation/scale. */
T_POINTS = 1 << 6,
-
- /* empty slot - (1 << 7) */
-
/** restrictions flags */
- T_NO_CONSTRAINT = 1 << 8,
- T_NULL_ONE = 1 << 9,
- T_NO_ZERO = 1 << 10,
+ T_NO_CONSTRAINT = 1 << 7,
+ T_NULL_ONE = 1 << 8,
+ T_NO_ZERO = 1 << 9,
T_ALL_RESTRICTIONS = T_NO_CONSTRAINT | T_NULL_ONE | T_NO_ZERO,
- T_PROP_EDIT = 1 << 11,
- T_PROP_CONNECTED = 1 << 12,
- T_PROP_PROJECTED = 1 << 13,
+ T_PROP_EDIT = 1 << 10,
+ T_PROP_CONNECTED = 1 << 11,
+ T_PROP_PROJECTED = 1 << 12,
T_PROP_EDIT_ALL = T_PROP_EDIT | T_PROP_CONNECTED | T_PROP_PROJECTED,
- T_V3D_ALIGN = 1 << 14,
+ T_V3D_ALIGN = 1 << 13,
/** For 2d views like uv or fcurve. */
- T_2D_EDIT = 1 << 15,
- T_CLIP_UV = 1 << 16,
+ T_2D_EDIT = 1 << 14,
+ T_CLIP_UV = 1 << 15,
/** Auto-ik is on. */
- T_AUTOIK = 1 << 18,
+ T_AUTOIK = 1 << 16,
/** Don't use mirror even if the data-block option is set. */
- T_NO_MIRROR = 1 << 19,
+ T_NO_MIRROR = 1 << 17,
/** To indicate that the value set in the `value` parameter is the final
* value of the transformation, modified only by the constrain. */
- T_INPUT_IS_VALUES_FINAL = 1 << 20,
+ T_INPUT_IS_VALUES_FINAL = 1 << 18,
/** To specify if we save back settings at the end. */
- T_MODAL = 1 << 21,
+ T_MODAL = 1 << 19,
/** No retopo. */
- T_NO_PROJECT = 1 << 22,
+ T_NO_PROJECT = 1 << 20,
- T_RELEASE_CONFIRM = 1 << 23,
+ T_RELEASE_CONFIRM = 1 << 21,
/** Alternative transformation. used to add offset to tracking markers. */
- T_ALT_TRANSFORM = 1 << 24,
+ T_ALT_TRANSFORM = 1 << 22,
/** #TransInfo.center has been set, don't change it. */
- T_OVERRIDE_CENTER = 1 << 25,
+ T_OVERRIDE_CENTER = 1 << 23,
- T_MODAL_CURSOR_SET = 1 << 26,
+ T_MODAL_CURSOR_SET = 1 << 24,
- T_CLNOR_REBUILD = 1 << 27,
+ T_CLNOR_REBUILD = 1 << 25,
+
+ /* Special Aftertrans. */
+ T_AUTOMERGE = 1 << 26,
+ T_AUTOSPLIT = 1 << 27,
};
/** #TransInfo.modifiers */
@@ -723,40 +704,39 @@ enum {
/** #TransData.flag */
enum {
TD_SELECTED = 1 << 0,
- TD_NOACTION = 1 << 2,
- TD_USEQUAT = 1 << 3,
- TD_NOTCONNECTED = 1 << 4,
+ TD_USEQUAT = 1 << 1,
+ TD_NOTCONNECTED = 1 << 2,
/** Used for scaling of #MetaElem.rad */
- TD_SINGLESIZE = 1 << 5,
+ TD_SINGLESIZE = 1 << 3,
/** Scale relative to individual element center */
- TD_INDIVIDUAL_SCALE = 1 << 8,
- TD_NOCENTER = 1 << 9,
+ TD_INDIVIDUAL_SCALE = 1 << 4,
+ TD_NOCENTER = 1 << 5,
/** #TransData.ext abused for particle key timing. */
- TD_NO_EXT = 1 << 10,
+ TD_NO_EXT = 1 << 6,
/** don't transform this data */
- TD_SKIP = 1 << 11,
+ TD_SKIP = 1 << 7,
/** if this is a bez triple, we need to restore the handles,
* if this is set #TransData.hdata needs freeing */
- TD_BEZTRIPLE = 1 << 12,
+ TD_BEZTRIPLE = 1 << 8,
/** when this is set, don't apply translation changes to this element */
- TD_NO_LOC = 1 << 13,
+ TD_NO_LOC = 1 << 9,
/** For Graph Editor autosnap, indicates that point should not undergo autosnapping */
- TD_NOTIMESNAP = 1 << 14,
+ TD_NOTIMESNAP = 1 << 10,
/** For Graph Editor - curves that can only have int-values
* need their keyframes tagged with this. */
- TD_INTVALUES = 1 << 15,
+ TD_INTVALUES = 1 << 11,
/** For editmode mirror, clamp axis to 0 */
- TD_MIRROR_EDGE_X = 1 << 16,
- TD_MIRROR_EDGE_Y = 1 << 17,
- TD_MIRROR_EDGE_Z = 1 << 18,
+ TD_MIRROR_EDGE_X = 1 << 12,
+ TD_MIRROR_EDGE_Y = 1 << 13,
+ TD_MIRROR_EDGE_Z = 1 << 14,
/** For fcurve handles, move them along with their keyframes */
- TD_MOVEHANDLE1 = 1 << 19,
- TD_MOVEHANDLE2 = 1 << 20,
+ TD_MOVEHANDLE1 = 1 << 15,
+ TD_MOVEHANDLE2 = 1 << 16,
/** Exceptional case with pose bone rotating when a parent bone has 'Local Location'
* option enabled and rotating also transforms it. */
- TD_PBONE_LOCAL_MTX_P = 1 << 21,
+ TD_PBONE_LOCAL_MTX_P = 1 << 17,
/** Same as above but for a child bone. */
- TD_PBONE_LOCAL_MTX_C = 1 << 22,
+ TD_PBONE_LOCAL_MTX_C = 1 << 18,
};
/** #TransSnap.status */
@@ -921,8 +901,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]);
void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
/*********************** Transform Orientations ******************************/
-
-void initTransformOrientation(struct bContext *C, TransInfo *t);
+short transform_orientation_matrix_get(struct bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3]);
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type);
+void transform_orientations_current_set(struct TransInfo *t, const short orient_index);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
@@ -932,7 +917,7 @@ struct TransformOrientation *addMatrixSpace(struct bContext *C,
float mat[3][3],
const char *name,
const bool overwrite);
-bool applyTransformOrientation(const struct TransformOrientation *ts,
+void applyTransformOrientation(const struct TransformOrientation *ts,
float r_mat[3][3],
char r_name[64]);
@@ -967,14 +952,14 @@ bool checkUseAxisMatrix(TransInfo *t);
(BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0]))
#define FOREACH_TRANS_DATA_CONTAINER(t, th) \
- for (TransDataContainer *tc = t->data_container, \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = (t)->data_container, \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++)
#define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \
- for (TransDataContainer *tc = ((i = 0), t->data_container), \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = ((i = 0), (t)->data_container), \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++, i++)
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 4b6932d977d..0347522b8e8 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -42,6 +42,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "ED_view3d.h"
@@ -57,6 +58,27 @@
static void drawObjectConstraint(TransInfo *t);
+static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3])
+{
+ unit_m3(r_pmtx);
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ zero_v3(r_pmtx[0]);
+ }
+
+ if (!(t->con.mode & CON_AXIS1)) {
+ zero_v3(r_pmtx[1]);
+ }
+
+ if (!(t->con.mode & CON_AXIS2)) {
+ zero_v3(r_pmtx[2]);
+ }
+
+ float mat[3][3];
+ mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv);
+ mul_m3_m3m3(r_pmtx, t->spacemtx, mat);
+}
+
/* ************************** CONSTRAINTS ************************* */
static void constraintValuesFinal(TransInfo *t, float vec[3])
{
@@ -121,11 +143,9 @@ void constraintNumInput(TransInfo *t, float vec[3])
}
}
-static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
+static void postConstraintChecks(TransInfo *t, float vec[3])
{
- int i = 0;
-
- mul_m3_v3(t->con.imtx, vec);
+ mul_m3_v3(t->spacemtx_inv, vec);
snapGridIncrement(t, vec);
@@ -155,23 +175,13 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
/* inverse transformation at the end */
}
- if (t->con.mode & CON_AXIS0) {
- pvec[i++] = vec[0];
- }
- if (t->con.mode & CON_AXIS1) {
- pvec[i++] = vec[1];
- }
- if (t->con.mode & CON_AXIS2) {
- pvec[i++] = vec[2];
- }
-
- mul_m3_v3(t->con.mtx, vec);
+ mul_m3_v3(t->spacemtx, vec);
}
static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
{
if (t->spacetype == SPACE_VIEW3D) {
- // View3D *v3d = t->sa->spacedata.first;
+ // View3D *v3d = t->area->spacedata.first;
const float min_dist = 1.0f; /* v3d->clip_start; */
float dir[3];
float l;
@@ -298,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t)
int n = 0;
for (int i = 0; i < 3; i++) {
if (t->con.mode & (CON_AXIS0 << i)) {
- constraint_vector[n++] = t->con.mtx[i];
+ constraint_vector[n++] = t->spacemtx[i];
if (n == 2) {
break;
}
@@ -346,12 +356,8 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3])
* (in perspective mode, the view vector is relative to the position on screen)
*/
-static void applyAxisConstraintVec(TransInfo *t,
- TransDataContainer *UNUSED(tc),
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyAxisConstraintVec(
+ TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3])
{
copy_v3_v3(out, in);
if (!td && t->con.mode & CON_APPLY) {
@@ -371,25 +377,25 @@ static void applyAxisConstraintVec(TransInfo *t,
float c[3];
if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
+ copy_v3_v3(c, t->spacemtx[0]);
}
else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
+ copy_v3_v3(c, t->spacemtx[1]);
}
else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
+ copy_v3_v3(c, t->spacemtx[2]);
}
axisProjection(t, c, in, out);
}
}
- postConstraintChecks(t, out, pvec);
+ postConstraintChecks(t, out);
}
}
/*
* Generic callback for object based spatial constraints applied to linear motion
*
- * At first, the following is applied to the first data in the array
+ * At first, the following is applied without orientation
* The IN vector in projected into the constrained space and then further
* projected along the view vector.
* (in perspective mode, the view vector is relative to the position on screen)
@@ -397,61 +403,19 @@ static void applyAxisConstraintVec(TransInfo *t,
* Further down, that vector is mapped to each data's space.
*/
-static void applyObjectConstraintVec(TransInfo *t,
- TransDataContainer *tc,
- TransData *td,
- const float in[3],
- float out[3],
- float pvec[3])
+static void applyObjectConstraintVec(
+ TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3])
{
- copy_v3_v3(out, in);
- if (t->con.mode & CON_APPLY) {
- if (!td) {
- mul_m3_v3(t->con.pmtx, out);
-
- const int dims = getConstraintSpaceDimension(t);
- if (dims == 2) {
- if (!is_zero_v3(out)) {
- if (!isPlaneProjectionViewAligned(t)) {
- planeProjection(t, in, out);
- }
- }
- }
- else if (dims == 1) {
- float c[3];
-
- if (t->con.mode & CON_AXIS0) {
- copy_v3_v3(c, t->con.mtx[0]);
- }
- else if (t->con.mode & CON_AXIS1) {
- copy_v3_v3(c, t->con.mtx[1]);
- }
- else if (t->con.mode & CON_AXIS2) {
- copy_v3_v3(c, t->con.mtx[2]);
- }
- axisProjection(t, c, in, out);
- }
- postConstraintChecks(t, out, pvec);
- copy_v3_v3(out, pvec);
- }
- else {
- int i = 0;
-
- out[0] = out[1] = out[2] = 0.0f;
- if (t->con.mode & CON_AXIS0) {
- out[0] = in[i++];
- }
- if (t->con.mode & CON_AXIS1) {
- out[1] = in[i++];
- }
- if (t->con.mode & CON_AXIS2) {
- out[2] = in[i++];
- }
-
- mul_m3_v3(td->axismtx, out);
- if (t->flag & T_EDIT) {
- mul_m3_v3(tc->mat3_unit, out);
- }
+ if (!td) {
+ applyAxisConstraintVec(t, tc, td, in, out);
+ }
+ else {
+ /* Specific TransData's space. */
+ copy_v3_v3(out, in);
+ mul_m3_v3(t->spacemtx_inv, out);
+ mul_m3_v3(td->axismtx, out);
+ if (t->flag & T_EDIT) {
+ mul_m3_v3(tc->mat3_unit, out);
}
}
}
@@ -478,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t,
smat[2][2] = 1.0f;
}
- mul_m3_m3m3(tmat, smat, t->con.imtx);
- mul_m3_m3m3(smat, t->con.mtx, tmat);
+ mul_m3_m3m3(tmat, smat, t->spacemtx_inv);
+ mul_m3_m3m3(smat, t->spacemtx, tmat);
}
}
@@ -539,15 +503,15 @@ static void applyAxisConstraintRot(
switch (mode) {
case CON_AXIS0:
case (CON_AXIS1 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[0]);
+ copy_v3_v3(vec, t->spacemtx[0]);
break;
case CON_AXIS1:
case (CON_AXIS0 | CON_AXIS2):
- copy_v3_v3(vec, t->con.mtx[1]);
+ copy_v3_v3(vec, t->spacemtx[1]);
break;
case CON_AXIS2:
case (CON_AXIS0 | CON_AXIS1):
- copy_v3_v3(vec, t->con.mtx[2]);
+ copy_v3_v3(vec, t->spacemtx[2]);
break;
}
/* don't flip axis if asked to or if num input */
@@ -620,12 +584,11 @@ static void applyObjectConstraintRot(
/*--------------------- INTERNAL SETUP CALLS ------------------*/
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
+void setConstraint(TransInfo *t, int mode, const char text[])
{
BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, space);
t->con.mode = mode;
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
startConstraint(t);
@@ -639,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[])
/* applies individual td->axismtx constraints */
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[])
{
- TransDataContainer *tc = t->data_container;
- if (t->data_len_all == 1) {
- float axismtx[3][3];
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx);
- }
- else {
- copy_m3_m3(axismtx, tc->data->axismtx);
- }
-
- setConstraint(t, axismtx, mode, text);
- }
- else {
- BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
- copy_m3_m3(t->con.mtx, tc->data->axismtx);
- t->con.mode = mode;
- getConstraintMatrix(t);
+ BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1);
+ t->con.mode = mode;
+ projection_matrix_calc(t, t->con.pmtx);
- startConstraint(t);
+ startConstraint(t);
- t->con.drawExtra = drawObjectConstraint;
- t->con.applyVec = applyObjectConstraintVec;
- t->con.applySize = applyObjectConstraintSize;
- t->con.applyRot = applyObjectConstraintRot;
- t->redraw = TREDRAW_HARD;
- }
+ t->con.drawExtra = drawObjectConstraint;
+ t->con.applyVec = applyObjectConstraintVec;
+ t->con.applySize = applyObjectConstraintSize;
+ t->con.applyRot = applyObjectConstraintRot;
+ t->redraw = TREDRAW_HARD;
}
void setLocalConstraint(TransInfo *t, int mode, const char text[])
{
- /* edit-mode now allows local transforms too */
if (t->flag & T_EDIT) {
- /* Use the active (first) edit object. */
- TransDataContainer *tc = t->data_container;
- setConstraint(t, tc->mat3_unit, mode, text);
+ /* Although in edit-mode each object has its local space, use the
+ * orientation of the active object. */
+ setConstraint(t, mode, text);
}
else {
setAxisMatrixConstraint(t, mode, text);
@@ -689,59 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[])
void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[])
{
char text[256];
+ const char *spacename = transform_orientations_spacename_get(t, orientation);
+ BLI_snprintf(text, sizeof(text), ftext, spacename);
switch (orientation) {
- case V3D_ORIENT_GLOBAL: {
- float mtx[3][3];
- BLI_snprintf(text, sizeof(text), ftext, TIP_("global"));
- unit_m3(mtx);
- setConstraint(t, mtx, mode, text);
- break;
- }
case V3D_ORIENT_LOCAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("local"));
setLocalConstraint(t, mode, text);
break;
case V3D_ORIENT_NORMAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("normal"));
if (checkUseAxisMatrix(t)) {
setAxisMatrixConstraint(t, mode, text);
+ break;
}
- else {
- setConstraint(t, t->spacemtx, mode, text);
- }
- break;
+ ATTR_FALLTHROUGH;
+ case V3D_ORIENT_GLOBAL:
case V3D_ORIENT_VIEW:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CURSOR:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_GIMBAL:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
case V3D_ORIENT_CUSTOM_MATRIX:
- BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix"));
- setConstraint(t, t->spacemtx, mode, text);
- break;
- case V3D_ORIENT_CUSTOM: {
- char orientation_str[128];
- BLI_snprintf(orientation_str,
- sizeof(orientation_str),
- "%s \"%s\"",
- TIP_("custom orientation"),
- t->orientation.custom->name);
- BLI_snprintf(text, sizeof(text), ftext, orientation_str);
- setConstraint(t, t->spacemtx, mode, text);
+ case V3D_ORIENT_CUSTOM:
+ default: {
+ setConstraint(t, mode, text);
break;
}
}
-
- t->con.orientation = orientation;
-
t->con.mode |= CON_USER;
}
@@ -772,9 +690,9 @@ void drawConstraint(TransInfo *t)
convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1]));
add_v3_v3(vec, t->center_global);
- drawLine(t, t->center_global, tc->mtx[0], 'X', 0);
- drawLine(t, t->center_global, tc->mtx[1], 'Y', 0);
- drawLine(t, t->center_global, tc->mtx[2], 'Z', 0);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', 0);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0);
depth_test_enabled = GPU_depth_test_enabled();
if (depth_test_enabled) {
@@ -808,13 +726,13 @@ void drawConstraint(TransInfo *t)
}
if (tc->mode & CON_AXIS0) {
- drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT);
}
if (tc->mode & CON_AXIS1) {
- drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT);
}
if (tc->mode & CON_AXIS2) {
- drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT);
+ drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT);
}
}
}
@@ -911,11 +829,7 @@ static void drawObjectConstraint(TransInfo *t)
}
}
- if (t->flag & T_OBJECT) {
- copy_v3_v3(co, td->ob->obmat[3]);
- axismtx = td->axismtx;
- }
- else if (t->flag & T_EDIT) {
+ if (t->flag & T_EDIT) {
mul_v3_m4v3(co, tc->mat, td->center);
mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx);
@@ -960,41 +874,18 @@ void stopConstraint(TransInfo *t)
t->num.idx_max = t->idx_max;
}
-void getConstraintMatrix(TransInfo *t)
-{
- float mat[3][3];
- invert_m3_m3(t->con.imtx, t->con.mtx);
- unit_m3(t->con.pmtx);
-
- if (!(t->con.mode & CON_AXIS0)) {
- zero_v3(t->con.pmtx[0]);
- }
-
- if (!(t->con.mode & CON_AXIS1)) {
- zero_v3(t->con.pmtx[1]);
- }
-
- if (!(t->con.mode & CON_AXIS2)) {
- zero_v3(t->con.pmtx[2]);
- }
-
- mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx);
- mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat);
-}
-
/*------------------------- MMB Select -------------------------------*/
-void initSelectConstraint(TransInfo *t, float mtx[3][3])
+void initSelectConstraint(TransInfo *t)
{
- copy_m3_m3(t->con.mtx, mtx);
- t->con.mode |= CON_APPLY;
- t->con.mode |= CON_SELECT;
+ if (t->orient_curr == 0) {
+ t->orient_curr = 1;
+ transform_orientations_current_set(t, t->orient_curr);
+ }
+ short orientation = t->orient[t->orient_curr].type;
+ setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "%s");
setNearestAxis(t);
- t->con.drawExtra = NULL;
- t->con.applyVec = applyAxisConstraintVec;
- t->con.applySize = applyAxisConstraintSize;
- t->con.applyRot = applyAxisConstraintRot;
}
void selectConstraint(TransInfo *t)
@@ -1060,7 +951,7 @@ static void setNearestAxis3d(TransInfo *t)
for (i = 0; i < 3; i++) {
float axis[3], axis_2d[2];
- copy_v3_v3(axis, t->con.mtx[i]);
+ copy_v3_v3(axis, t->spacemtx[i]);
mul_v3_fl(axis, zfac);
/* now we can project to get window coordinate */
@@ -1129,7 +1020,7 @@ void setNearestAxis(TransInfo *t)
setNearestAxis2d(t);
}
- getConstraintMatrix(t);
+ projection_matrix_calc(t, t->con.pmtx);
}
/*-------------- HELPER FUNCTIONS ----------------*/
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
index 8938ca93ad8..c41b9361ca4 100644
--- a/source/blender/editors/transform/transform_constraints.h
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -27,7 +27,7 @@
struct TransInfo;
void constraintNumInput(TransInfo *t, float vec[3]);
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setConstraint(TransInfo *t, int mode, const char text[]);
void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
void setLocalConstraint(TransInfo *t, int mode, const char text[]);
void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
@@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t);
void drawPropCircle(const struct bContext *C, TransInfo *t);
void startConstraint(TransInfo *t);
void stopConstraint(TransInfo *t);
-void getConstraintMatrix(TransInfo *t);
-void initSelectConstraint(TransInfo *t, float mtx[3][3]);
+void initSelectConstraint(TransInfo *t);
void selectConstraint(TransInfo *t);
void postSelectConstraint(TransInfo *t);
void setNearestAxis(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index c3949899dff..cf60990d09c 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -83,16 +83,47 @@
#include "transform_convert.h"
#include "transform_mode.h"
+bool transform_mode_use_local_origins(const TransInfo *t)
+{
+ return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
+}
+
/**
* Transforming around ourselves is no use, fallback to individual origins,
* useful for curve/armatures.
*/
void transform_around_single_fallback(TransInfo *t)
{
- if ((t->data_len_all == 1) &&
- (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
- (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
- t->around = V3D_AROUND_LOCAL_ORIGINS;
+ if ((ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
+ transform_mode_use_local_origins(t)) {
+
+ bool is_data_single = false;
+ if (t->data_len_all == 1) {
+ is_data_single = true;
+ }
+ else if (t->data_len_all == 3) {
+ if (t->obedit_type == OB_CURVE) {
+ /* Special case check for curve, if we have a single curve bezier triple selected
+ * treat */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (!tc->data_len) {
+ continue;
+ }
+ if (tc->data_len == 3) {
+ const TransData *td = tc->data;
+ if ((td[0].flag | td[1].flag | td[2].flag) & TD_BEZTRIPLE) {
+ if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) {
+ is_data_single = true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (is_data_single) {
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
+ }
}
}
@@ -377,23 +408,25 @@ static short apply_targetless_ik(Object *ob)
}
for (; segcount; segcount--) {
Bone *bone;
- float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
+ float mat[4][4];
/* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
- /* we put in channel the entire result of rmat = (channel * constraint * IK) */
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
- /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
+ /* we put in channel the entire result of mat = (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */
+ /* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
parchan = chanlist[segcount - 1];
bone = parchan->bone;
bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
- BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
-
+ BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat);
/* apply and decompose, doesn't work for constraints or non-uniform scale well */
{
float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
- copy_m3_m4(rmat3, rmat);
+
+ copy_m3_m4(rmat3, mat);
+ /* Make sure that our rotation matrix only contains rotation and not scale. */
+ normalize_m3(rmat3);
/* rotation */
/* [#22409] is partially caused by this, as slight numeric error introduced during
@@ -413,7 +446,7 @@ static short apply_targetless_ik(Object *ob)
/* causes problems with some constraints (e.g. childof), so disable this */
/* as it is IK shouldn't affect location directly */
- /* copy_v3_v3(parchan->loc, rmat[3]); */
+ /* copy_v3_v3(parchan->loc, mat[3]); */
}
}
@@ -445,12 +478,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
+/* Sets transform flags in the bones.
+ * Returns total number of bones with `BONE_TRANSFORM`. */
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
@@ -459,15 +492,20 @@ int count_set_pose_transflags(Object *ob,
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
if (PBONE_VISIBLE(arm, bone)) {
if ((bone->flag & BONE_SELECTED)) {
bone->flag |= BONE_TRANSFORM;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
}
/* make sure no bone can be transformed when a parent is transformed */
@@ -791,10 +829,6 @@ void clipUVData(TransInfo *t)
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (int a = 0; a < tc->data_len; a++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if ((td->flag & TD_SKIP) || (!td->loc)) {
continue;
}
@@ -812,25 +846,28 @@ void clipUVData(TransInfo *t)
* \{ */
/**
- * For modal operation: `t->center_global` may not have been set yet.
+ * Used for `TFM_TIME_EXTEND`.
*/
-void transform_convert_center_global_v2(TransInfo *t, float r_center[2])
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
{
+ char r_dir;
+ float center[2];
if (t->flag & T_MODAL) {
UI_view2d_region_to_view(
- (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], &r_center[0], &r_center[1]);
+ (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], &center[0], &center[1]);
+ r_dir = (center[0] > cframe) ? 'R' : 'L';
+ {
+ /* XXX: This saves the direction in the "mirror" property to be used for redo! */
+ if (r_dir == 'R') {
+ t->flag |= T_NO_MIRROR;
+ }
+ }
}
else {
- copy_v2_v2(r_center, t->center_global);
+ r_dir = (t->flag & T_NO_MIRROR) ? 'R' : 'L';
}
-}
-void transform_convert_center_global_v2_int(TransInfo *t, int r_center[2])
-{
- float center[2];
- transform_convert_center_global_v2(t, center);
- r_center[0] = round_fl_to_int(center[0]);
- r_center[1] = round_fl_to_int(center[1]);
+ return r_dir;
}
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
@@ -1021,7 +1058,7 @@ static void posttrans_fcurve_clean(FCurve *fcu,
}
else {
/* Compute the average values for each retained keyframe */
- for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) {
rk->val = rk->val / (float)rk->tot_count;
}
}
@@ -1123,10 +1160,10 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
/* struct for use in re-sorting BezTriples during Graph Editor transform */
typedef struct BeztMap {
BezTriple *bezt;
- unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
- unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
- short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
- char pipo, cipo; /* interpolation of current and next segments */
+ uint oldIndex; /* index of bezt in fcu->bezt array before sorting */
+ uint newIndex; /* index of bezt in fcu->bezt array after sorting */
+ short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
+ char pipo, cipo; /* interpolation of current and next segments */
} BeztMap;
/* This function converts an FCurve's BezTriple array to a BeztMap array
@@ -1304,7 +1341,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
*/
void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimListElem *ale;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -1581,145 +1618,148 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
FCurve *fcu;
// TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase nla_cache = {NULL, NULL};
- float cfra = (float)CFRA;
- eInsertKeyFlags flag = 0;
+ if (!autokeyframe_cfra_can_key(scene, id)) {
+ /* tag channels that should have unkeyed data */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ return;
+ }
- /* flag is initialized from UserPref keyframing settings
- * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
- * visual keyframes even if flag not set, as it's not that useful otherwise
- * (for quick animation recording)
- */
- flag = ANIM_get_keyframing_flags(scene, true);
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase nla_cache = {NULL, NULL};
+ float cfra = (float)CFRA;
+ eInsertKeyFlags flag = 0;
+
+ /* flag is initialized from UserPref keyframing settings
+ * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
+ * visual keyframes even if flag not set, as it's not that useful otherwise
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, true);
- if (targetless_ik) {
- flag |= INSERTKEY_MATRIX;
+ if (targetless_ik) {
+ flag |= INSERTKEY_MATRIX;
+ }
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) == 0 &&
+ !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
+ continue;
}
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) ||
- ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
- ListBase dsources = {NULL, NULL};
-
- /* clear any 'unkeyed' flag it may have */
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
-
- /* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* run the active Keying Set on the current datasource */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- /* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones")) {
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
-
- /* only if bone name matches too...
- * NOTE: this will do constraints too, but those are ok to do here too?
- */
- if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- }
- }
- }
- }
- /* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
+ ListBase dsources = {NULL, NULL};
- /* Filter the conditions when this happens
- * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
- if (tmode == TFM_TRANSLATION) {
- if (targetless_ik) {
- do_rot = true;
- }
- else {
- do_loc = true;
- }
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
+ /* only insert into active keyingset? */
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* run the active Keying Set on the current datasource */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ /* only insert into available channels? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones") == NULL) {
+ continue;
}
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
}
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+
+ if (pchanName) {
+ MEM_freeN(pchanName);
}
}
- /* insert keyframe in all (transform) channels */
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* Filter the conditions when this happens
+ * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
+ if (tmode == TFM_TRANSLATION) {
+ if (targetless_ik) {
+ do_rot = true;
+ }
else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ do_loc = true;
+ }
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
}
- /* free temp info */
- BLI_freelistN(&dsources);
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
}
- }
+ else if (tmode == TFM_RESIZE) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- else {
- /* tag channels that should have unkeyed data */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- /* tag this channel */
- pchan->bone->flag |= BONE_UNKEYED;
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
}
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
}
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
}
/** \} */
@@ -1741,13 +1781,12 @@ bool motionpath_need_update_pose(Scene *scene, Object *ob)
static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
const int framenr = ED_space_clip_get_clip_frame_number(sc);
/* Update coordinates of modified plane tracks. */
- for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
- plane_track = plane_track->next) {
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
bool do_update = false;
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
continue;
@@ -1783,11 +1822,11 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
Mask *mask = NULL;
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
mask = ED_space_clip_get_mask(sc);
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
mask = ED_space_image_get_mask(sima);
}
else {
@@ -1807,7 +1846,10 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
if (IS_AUTOKEY_ON(t->scene)) {
Scene *scene = t->scene;
- ED_mask_layer_shape_auto_key_select(mask, CFRA);
+ if (ED_mask_layer_shape_auto_key_select(mask, CFRA)) {
+ WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id);
+ DEG_id_tag_update(&mask->id, 0);
+ }
}
}
@@ -1818,7 +1860,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
if (canceled && t->remove_on_cancel) {
/* remove selected nodes on cancel */
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
bNodeTree *ntree = snode->edittree;
if (ntree) {
bNode *node, *node_next;
@@ -1828,14 +1870,15 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
nodeRemoveNode(bmain, ntree, node, true);
}
}
+ ntreeUpdateTree(bmain, ntree);
}
}
}
static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
+ if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1861,14 +1904,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
hflag = BM_ELEM_SELECT;
}
- if (t->scene->toolsettings->automerge & AUTO_MERGE) {
- if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
- EDBM_automerge_and_split(
- tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
- }
- else {
- EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
- }
+ if (t->flag & T_AUTOSPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
}
/* Special case, this is needed or faces won't re-select.
@@ -1941,7 +1982,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* freeSeqData in transform_conversions.c does this
* keep here so the else at the end wont run... */
- SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
+ SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
/* Marker transform, not especially nice but we may want to move markers
* at the same time as strips in the Video Sequencer. */
@@ -1967,16 +2008,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
special_aftertrans_update__node(C, t);
if (canceled == 0) {
ED_node_post_apply_transform(C, snode->edittree);
- ED_node_link_insert(bmain, t->sa);
+ ED_node_link_insert(bmain, t->area);
}
/* clear link line */
- ED_node_link_intersect_test(t->sa, 0);
+ ED_node_link_intersect_test(t->area, 0);
}
else if (t->spacetype == SPACE_CLIP) {
if (t->options & CTX_MOVIECLIP) {
@@ -1987,7 +2028,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac;
/* initialize relevant anim-context 'context' data */
@@ -2070,12 +2111,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const int filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
ale->id->tag |= LIB_TAG_DOIT;
}
}
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_GPFRAME) {
if (ale->id->tag & LIB_TAG_DOIT) {
ale->id->tag &= ~LIB_TAG_DOIT;
@@ -2101,12 +2142,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
const int filter = ANIMFILTER_DATA_VISIBLE;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
ale->id->tag |= LIB_TAG_DOIT;
}
}
- for (bAnimListElem *ale = anim_data.first; ale; ale = ale->next) {
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype == ALE_MASKLAY) {
if (ale->id->tag & LIB_TAG_DOIT) {
ale->id->tag &= ~LIB_TAG_DOIT;
@@ -2151,7 +2192,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
saction->flag &= ~SACTION_MOVING;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimContext ac;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -2240,9 +2281,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->flag & T_EDIT) {
if (t->obedit_type == OB_MESH) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
/* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(tc->obedit);
/* TODO(campbell): xform: We need support for many mirror objects at once! */
break;
}
@@ -2277,7 +2317,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
}
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
@@ -2348,10 +2388,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
PTCacheID *pid;
ob = td->ob;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -2732,7 +2768,7 @@ void createTransData(bContext *C, TransInfo *t)
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
has_transform_context = false;
- Object *ob_armature = modifiers_isDeformedByArmature(ob);
+ Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob);
if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
if (base_arm) {
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index d616f24ba86..e5d758135e2 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -37,10 +37,10 @@ struct bKinematicConstraint;
struct bPoseChannel;
/* transform_convert.c */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
void transform_autoik_update(TransInfo *t, short mode);
void autokeyframe_object(struct bContext *C,
struct Scene *scene,
@@ -100,12 +100,12 @@ void flushTransTracking(TransInfo *t);
/********************* intern **********************/
/* transform_convert.c */
+bool transform_mode_use_local_origins(const TransInfo *t);
void transform_around_single_fallback(TransInfo *t);
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail);
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
-void transform_convert_center_global_v2(TransInfo *t, float r_center[2]);
-void transform_convert_center_global_v2_int(TransInfo *t, int r_center[2]);
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
/* transform_convert_action.c */
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index c9273121df5..21ef1539911 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -331,10 +331,7 @@ void createTransActionData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 4e8e0cc2369..35bb7e3f0d8 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_action.h"
@@ -57,6 +58,37 @@ typedef struct BoneInitData {
float zwidth;
} BoneInitData;
+static bConstraint *add_temporary_ik_constraint(bPoseChannel *pchan,
+ bKinematicConstraint *targetless_con)
+{
+ bConstraint *con = BKE_constraint_add_for_pose(
+ NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+
+ /* for draw, but also for detecting while pose solving */
+ pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
+
+ bKinematicConstraint *temp_con_data = con->data;
+
+ if (targetless_con) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *temp_con_data = *targetless_con;
+ }
+ else {
+ temp_con_data->flag = CONSTRAINT_IK_TIP;
+ }
+
+ temp_con_data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
+
+ return con;
+}
+
+static void update_deg_with_temporary_ik(Main *bmain, Object *ob)
+{
+ BIK_clear_data(ob->pose);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
+}
+
static void add_pose_transdata(
TransInfo *t, bPoseChannel *pchan, Object *ob, TransDataContainer *tc, TransData *td)
{
@@ -199,8 +231,16 @@ static void add_pose_transdata(
}
td->loc = data->grabtarget;
copy_v3_v3(td->iloc, td->loc);
+
data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * targetless bone during transform. (Targetless IK constraints are treated as if they are
+ * disabled unless they are transformed). */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
+
/* only object matrix correction */
copy_m3_m3(td->mtx, omat);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
@@ -220,7 +260,8 @@ bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
bConstraint *con = pchan->constraints.first;
for (; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0 &&
+ (con->enforce != 0.0f)) {
bKinematicConstraint *data = con->data;
if (data->tar == NULL) {
@@ -248,7 +289,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* Rule: not if there's already an IK on this channel */
for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0) {
data = con->data;
if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
@@ -263,22 +304,20 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* if no chain length has been specified,
* just make things obey standard rotation locks too */
if (data->rootbone == 0) {
- for (; pchan; pchan = pchan->parent) {
+ for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) {
/* here, we set ik-settings for bone from pchan->protectflag */
// XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTX) {
+ pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTY) {
+ pchan_iter->ikflag |= BONE_IK_NO_YDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTZ) {
+ pchan_iter->ikflag |= BONE_IK_NO_ZDOF_TEMP;
}
}
}
-
- return 0;
}
}
@@ -288,20 +327,8 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
}
}
- con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+ data = add_temporary_ik_constraint(pchan, targetless)->data;
- /* for draw, but also for detecting while pose solving */
- pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- data = con->data;
- if (targetless) {
- /* if exists, use values from last targetless (but disabled) IK-constraint as base */
- *data = *targetless;
- }
- else {
- data->flag = CONSTRAINT_IK_TIP;
- }
- data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
copy_v3_v3(data->grabtarget, pchan->pose_tail);
/* watch-it! has to be 0 here, since we're still on the
@@ -414,9 +441,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* iTaSC needs clear for new IK constraints */
if (tot_ik) {
- BIK_clear_data(ob->pose);
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
+ update_deg_with_temporary_ik(bmain, ob);
}
return (tot_ik) ? 1 : 0;
@@ -530,6 +555,11 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
unit_m4(flip_mtx);
flip_mtx[0][0] = -1;
+ LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
bPose *pose = ob->pose;
PoseInitData_Mirror *pid = NULL;
if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) {
@@ -565,6 +595,9 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
}
BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+ /* Set flag to let autokeyframe know to keyframe the mirrred bone. */
+ pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+
/* In this case we can do target-less IK grabbing. */
if (t->mode == TFM_TRANSLATION) {
bKinematicConstraint *data = has_targetless_ik(pchan);
@@ -576,6 +609,12 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *
/* TODO(germano): Realitve Mirror support */
}
data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * target-less bone during transform. (Target-less IK constraints are treated as if they are
+ * disabled unless they are transformed) */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
}
if (pid) {
@@ -630,7 +669,9 @@ void createTransPose(TransInfo *t)
const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
/* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ tc->data_len = transform_convert_pose_transflags_update(
+ ob, t->mode, t->around, has_translate_rotate);
+
if (tc->data_len == 0) {
continue;
}
@@ -645,7 +686,10 @@ void createTransPose(TransInfo *t)
if (mirror) {
int total_mirrored = 0;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+
if ((pchan->bone->flag & BONE_TRANSFORM) &&
BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
total_mirrored++;
@@ -695,7 +739,7 @@ void createTransPose(TransInfo *t)
}
if (mirror) {
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
if (pchan_mirror) {
@@ -717,7 +761,7 @@ void createTransPose(TransInfo *t)
/* use pose channels to fill trans data */
td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
add_pose_transdata(t, pchan, ob, tc, td);
td++;
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 621f9dd63e2..e6a972bfc7c 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -44,7 +44,7 @@
void createTransCursor_image(TransInfo *t)
{
TransData *td;
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
float *cursor_location = sima->cursor;
{
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 24f0491c86c..1f113a36a89 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -25,6 +25,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
@@ -92,13 +93,12 @@ void createTransCurveVerts(TransInfo *t)
int count = 0, countsel = 0;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
/* count total of vertices, check identical as in 2nd loop for making transdata! */
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
@@ -162,10 +162,11 @@ void createTransCurveVerts(TransInfo *t)
int a;
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
View3D *v3d = t->view;
- short hide_handles = (v3d != NULL) ?
- ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
- false;
+ short hide_handles = (v3d != NULL) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
+ false;
+ bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ transform_mode_use_local_origins(t));
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc->obedit->obmat);
@@ -173,7 +174,7 @@ void createTransCurveVerts(TransInfo *t)
TransData *td = tc->data;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
TransData *head, *tail;
head = tail = td;
@@ -341,7 +342,7 @@ void createTransCurveVerts(TransInfo *t)
if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection,
* do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
+ BKE_nurb_handles_test(nu, !hide_handles, use_around_origins_for_handles_test);
}
}
else {
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 95a385a5a50..f6f0dd3c491 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -167,7 +167,7 @@ static void graph_bezt_get_transform_selection(const TransInfo *t,
bool *r_key,
bool *r_right_handle)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bool key = (bezt->f2 & SELECT) != 0;
bool left = use_handle ? ((bezt->f1 & SELECT) != 0) : key;
bool right = use_handle ? ((bezt->f3 & SELECT) != 0) : key;
@@ -224,7 +224,7 @@ static void graph_key_shortest_dist(
*/
void createTransGraphEditData(bContext *C, TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
ARegion *region = t->region;
View2D *v2d = &region->v2d;
@@ -261,10 +261,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
/* 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) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -642,7 +639,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
*/
void flushTransGraphData(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataGraph *tdg;
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 65244a09b73..6c743da3e65 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -280,7 +280,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
}
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
if (!clip) {
return;
@@ -333,7 +333,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
return;
}
- ED_mask_get_aspect(t->sa, t->region, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
tc->data_len = (is_prop_edit) ? count : countsel;
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
@@ -409,7 +409,7 @@ void flushTransMasking(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- ED_mask_get_aspect(t->sa, t->region, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
inv[0] = 1.0f / asp[0];
inv[1] = 1.0f / asp[1];
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 29a74be8e2b..07b2f07bf2c 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -61,8 +61,10 @@
/* when transforming islands */
struct TransIslandData {
- float co[3];
- float axismtx[3][3];
+ float (*center)[3];
+ float (*axismtx)[3][3];
+ int island_tot;
+ int *island_vert_map;
};
/* -------------------------------------------------------------------- */
@@ -247,18 +249,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm,
}
}
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
- int *r_island_tot,
- int **r_island_vert_map,
- bool calc_single_islands)
+static void editmesh_islands_info_calc(BMEditMesh *em,
+ const bool calc_single_islands,
+ const bool calc_island_axismtx,
+ struct TransIslandData *r_island_data)
{
BMesh *bm = em->bm;
- struct TransIslandData *trans_islands;
char htype;
char itype;
int i;
/* group vars */
+ float(*center)[3];
+ float(*axismtx)[3][3] = NULL;
int *groups_array;
int(*group_index)[2];
int group_tot;
@@ -283,7 +286,11 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
itype = BM_VERTS_OF_FACE;
}
- trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
+ center = MEM_mallocN(sizeof(*center) * group_tot, __func__);
+
+ if (calc_island_axismtx) {
+ axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__);
+ }
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
@@ -311,7 +318,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.htype = htype;
- /* loop on each face in this group:
+ /* loop on each face or edge in this group:
* - assign r_vert_map
* - calculate (co, no)
*/
@@ -321,12 +328,14 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.ele = ele_array[groups_array[fg_sta + j]];
BM_editselection_center(&ese, tmp_co);
- BM_editselection_normal(&ese, tmp_no);
- BM_editselection_plane(&ese, tmp_tangent);
-
add_v3_v3(co, tmp_co);
- add_v3_v3(no, tmp_no);
- add_v3_v3(tangent, tmp_tangent);
+
+ if (axismtx) {
+ BM_editselection_normal(&ese, tmp_no);
+ BM_editselection_plane(&ese, tmp_tangent);
+ add_v3_v3(no, tmp_no);
+ add_v3_v3(tangent, tmp_tangent);
+ }
{
/* setup vertex map */
@@ -340,18 +349,20 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
+ mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len);
- if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
- /* pass */
- }
- else {
- if (normalize_v3(no) != 0.0f) {
- axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
- invert_m3(trans_islands[i].axismtx);
+ if (axismtx) {
+ if (createSpaceNormalTangent(axismtx[i], no, tangent)) {
+ /* pass */
}
else {
- unit_m3(trans_islands[i].axismtx);
+ if (normalize_v3(no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[i], no);
+ invert_m3(axismtx[i]);
+ }
+ else {
+ unit_m3(axismtx[i]);
+ }
}
}
}
@@ -372,22 +383,24 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
if (group_tot_single != 0) {
- trans_islands = MEM_reallocN(trans_islands,
- sizeof(*trans_islands) * (group_tot + group_tot_single));
+ center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single));
+ if (axismtx) {
+ axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single));
+ }
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- struct TransIslandData *v_island = &trans_islands[group_tot];
vert_map[i] = group_tot;
+ copy_v3_v3(center[group_tot], v->co);
- copy_v3_v3(v_island->co, v->co);
-
- if (is_zero_v3(v->no) != 0.0f) {
- axis_dominant_v3_to_m3(v_island->axismtx, v->no);
- invert_m3(v_island->axismtx);
- }
- else {
- unit_m3(v_island->axismtx);
+ if (axismtx) {
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[group_tot], v->no);
+ invert_m3(axismtx[group_tot]);
+ }
+ else {
+ unit_m3(axismtx[group_tot]);
+ }
}
group_tot += 1;
@@ -396,10 +409,10 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- *r_island_tot = group_tot;
- *r_island_vert_map = vert_map;
-
- return trans_islands;
+ r_island_data->axismtx = axismtx;
+ r_island_data->center = center;
+ r_island_data->island_tot = group_tot;
+ r_island_data->island_vert_map = vert_map;
}
static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
@@ -567,7 +580,8 @@ static void VertsToTransData(TransInfo *t,
BMEditMesh *em,
BMVert *eve,
float *bweight,
- struct TransIslandData *v_island,
+ const struct TransIslandData *island_data,
+ const int island_index,
const bool no_island_center)
{
float *no, _no[3];
@@ -589,14 +603,17 @@ static void VertsToTransData(TransInfo *t,
no = eve->no;
}
- if (v_island) {
+ if (island_index != -1) {
if (no_island_center) {
copy_v3_v3(td->center, td->loc);
}
else {
- copy_v3_v3(td->center, v_island->co);
+ copy_v3_v3(td->center, island_data->center[island_index]);
}
- copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+
+ if ((island_index != -1) && island_data->axismtx) {
+ copy_m3_m3(td->axismtx, island_data->axismtx[island_index]);
}
else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_v3_v3(td->center, td->loc);
@@ -654,9 +671,7 @@ void createTransEditVerts(TransInfo *t)
const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int cd_vert_bweight_offset = -1;
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
+ struct TransIslandData island_data = {NULL};
/* Snap rotation along normal needs a common axis for whole islands,
* otherwise one get random crazy results, see T59104.
@@ -758,14 +773,17 @@ void createTransEditVerts(TransInfo *t)
(t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(em->selectmode & SCE_SELECT_VERTEX));
- island_info = editmesh_islands_info_calc(
- em, &island_info_tot, &island_vert_map, calc_single_islands);
+ /* The island axismtx is only necessary in some modes.
+ * TODO(Germano): Extend the list to exclude other modes. */
+ const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN);
+
+ editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data);
}
/* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) {
int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) {
BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
/* Use evaluated state because we need b-bone cache. */
@@ -809,21 +827,19 @@ void createTransEditVerts(TransInfo *t)
continue;
}
if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
NULL;
- if (island_info) {
+ int island_index = -1;
+ if (island_data.island_vert_map) {
const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
+ island_index = island_data.island_vert_map[connected_index];
}
/* 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, v_island, is_snap_rotate);
+ VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate);
if (tx) {
tx++;
}
@@ -889,9 +905,16 @@ void createTransEditVerts(TransInfo *t)
}
}
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
+ if (island_data.center) {
+ MEM_freeN(island_data.center);
+ }
+
+ if (island_data.axismtx) {
+ MEM_freeN(island_data.axismtx);
+ }
+
+ if (island_data.island_vert_map) {
+ MEM_freeN(island_data.island_vert_map);
}
cleanup:
@@ -1427,7 +1450,6 @@ static void UVsToTransData(const float aspect[2],
void createTransUVs(bContext *C, TransInfo *t)
{
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
Scene *scene = t->scene;
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1477,7 +1499,7 @@ void createTransUVs(bContext *C, TransInfo *t)
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BMLoop *l;
- if (!uvedit_face_visible_test(scene, tc->obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
continue;
}
@@ -1608,7 +1630,7 @@ void createTransUVs(bContext *C, TransInfo *t)
void flushTransUVs(TransInfo *t)
{
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
(t->state != TRANS_CANCEL));
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 580a8d79d7a..2978c36b15f 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -71,10 +71,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which center is gets transformed */
- float center[2];
- transform_convert_center_global_v2(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index ee4aa053444..d783bfdf40e 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -109,7 +109,7 @@ void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
const float dpi_fac = UI_DPI_FAC;
TransData *td;
TransData2D *td2d;
- SpaceNode *snode = t->sa->spacedata.first;
+ SpaceNode *snode = t->area->spacedata.first;
bNode *node;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -188,7 +188,7 @@ void flushTransNodes(TransInfo *t)
/* handle intersection with noodles */
if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->sa, 1);
+ ED_node_link_intersect_test(t->area, 1);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 4973b1cb268..8deba0f7ad0 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -197,7 +197,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* NOTE: This is not really following copy-on-write design and we should not
* be re-evaluating the evaluated object. But as the comment above mentioned
* this is part of a hack.
- * More proper solution would be to make a shallow copy of the object and
+ * More proper solution would be to make a shallow copy of the object and
* evaluate that, and access matrix of that evaluated copy of the object.
* Might be more tricky than it sounds, if some logic later on accesses the
* object matrix via td->ob->obmat. */
@@ -290,7 +290,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
}
@@ -324,7 +324,7 @@ static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *vi
{
if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.tag & LIB_TAG_DOIT) {
base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
}
@@ -355,7 +355,7 @@ static void set_trans_object_base_flags(TransInfo *t)
/* Clear all flags we need. It will be used to detect dependencies. */
trans_object_base_deps_flag_prepare(view_layer);
/* Traverse all bases and set all possible flags. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
if (BASE_SELECTED_EDITABLE(v3d, base)) {
Object *ob = base->object;
@@ -422,7 +422,7 @@ static int count_proportional_objects(TransInfo *t)
if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
/* Mark all parents. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
Object *parent = base->object->parent;
/* flag all parents */
@@ -433,7 +433,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Mark all children. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
/* all base not already selected or marked that is editable */
if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
(base->flag & BASE_SELECTED) == 0 &&
@@ -443,7 +443,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Flush changed flags to all dependencies. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* If base is not selected, not a parent of selection or not a child of
* selection and it is editable and selectable.
@@ -592,7 +592,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* if base is not selected, not a parent of selection
@@ -639,7 +639,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->parent != NULL) {
if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
@@ -669,7 +669,7 @@ void createTransObject(bContext *C, TransInfo *t)
}
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index f2d0f4dfc43..0175bf6e673 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -31,6 +31,8 @@
#include "BKE_report.h"
#include "BKE_sequencer.h"
+#include "UI_view2d.h"
+
#include "transform.h"
#include "transform_convert.h"
@@ -379,7 +381,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
if (overlap) {
- const bool use_sync_markers = (((SpaceSeq *)t->sa->spacedata.first)->flag &
+ const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
ListBase *markers = &t->scene->markers;
@@ -541,10 +543,7 @@ void createTransSeqData(TransInfo *t)
}
tc->custom.type.free_cb = freeSeqData;
- /* only side on which center is gets transformed */
- int center[2];
- transform_convert_center_global_v2_int(t, center);
- t->frame_side = (center[0] > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
#ifdef XXX_DURIAN_ANIM_TX_HACK
{
@@ -586,9 +585,12 @@ void createTransSeqData(TransInfo *t)
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
SeqTransDataBounds(t, ed->seqbasep, ts);
- /* set the snap mode based on how close the mouse is at the end/start points */
- if (abs(center[0] - ts->max) > abs(center[0] - ts->min)) {
- ts->snap_left = true;
+ if (t->flag & T_MODAL) {
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ int xmouse = (int)UI_view2d_region_to_view_x((View2D *)t->view, t->mouse.imval[0]);
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
+ ts->snap_left = true;
+ }
}
#undef XXX_DURIAN_ANIM_TX_HACK
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index a8bde661342..6704567a76b 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -549,7 +549,7 @@ void createTransTrackingData(bContext *C, TransInfo *t)
void cancelTransTracking(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
TransDataTracking *tdt_array = tc->custom.type.data;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index f3105c8eb36..95ca5ae0c30 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -313,7 +313,7 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
break;
}
case HLP_TRACKBALL: {
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
GPU_matrix_translate_3fv(mval);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 7a787b77a62..6de962a3ed1 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -64,7 +64,7 @@
#include "BIK_api.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -174,9 +174,6 @@ static void clipMirrorModifier(TransInfo *t)
int clip;
float loc[3], iloc[3];
- if (td->flag & TD_NOACTION) {
- break;
- }
if (td->loc == NULL) {
break;
}
@@ -337,7 +334,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
static bool fcu_test_selected(FCurve *fcu)
{
BezTriple *bezt = fcu->bezt;
- unsigned int i;
+ uint i;
if (bezt == NULL) { /* ignore baked */
return 0;
@@ -356,7 +353,7 @@ static bool fcu_test_selected(FCurve *fcu)
static void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -369,10 +366,10 @@ static void recalcData_actedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
+ ac.area = t->area;
ac.region = t->region;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -406,7 +403,7 @@ static void recalcData_actedit(TransInfo *t)
/* helper for recalcData() - for Graph Editor transforms */
static void recalcData_graphedit(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
ViewLayer *view_layer = t->view_layer;
ListBase anim_data = {NULL, NULL};
@@ -422,10 +419,10 @@ static void recalcData_graphedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
+ ac.area = t->area;
ac.region = t->region;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -474,7 +471,7 @@ static void recalcData_graphedit(TransInfo *t)
/* helper for recalcData() - for NLA Editor transforms */
static void recalcData_nla(TransInfo *t)
{
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
Scene *scene = t->scene;
double secf = FPS;
int i;
@@ -718,7 +715,7 @@ static void recalcData_image(TransInfo *t)
flushTransPaintCurve(t);
}
else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
flushTransUVs(t);
if (sima->flag & SI_LIVE_UNWRAP) {
@@ -736,7 +733,7 @@ static void recalcData_image(TransInfo *t)
/* helper for recalcData() - for Movie Clip transforms */
static void recalcData_spaceclip(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -1068,11 +1065,6 @@ static void recalcData_objects(TransInfo *t)
for (int i = 0; i < tc->data_len; i++, td++) {
Object *ob = td->ob;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -1187,7 +1179,6 @@ void recalcData(TransInfo *t)
flushTransPaintCurve(t);
}
else if (t->options & CTX_GPENCIL_STROKES) {
- /* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
else if (t->options & CTX_SCULPT) {
@@ -1222,7 +1213,7 @@ void recalcData(TransInfo *t)
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
float v1[3], v2[3], v3[3];
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
@@ -1375,15 +1366,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
ToolSettings *ts = CTX_data_tool_settings(C);
ARegion *region = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
PropertyRNA *prop;
+ t->mbus = CTX_wm_message_bus(C);
t->depsgraph = CTX_data_depsgraph_pointer(C);
t->scene = sce;
t->view_layer = view_layer;
- t->sa = sa;
+ t->area = area;
t->region = region;
t->settings = ts;
t->reports = op ? op->reports : NULL;
@@ -1431,11 +1423,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->mat);
- unit_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- /* Leave 't->orient_matrix_is_set' to false,
- * so we overwrite it when we have a useful value. */
-
/* Default to rotate on the Z axis. */
t->orient_axis = 2;
t->orient_axis_ortho = 1;
@@ -1465,17 +1452,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Assign the space type, some exceptions for running in different mode */
- if (sa == NULL) {
+ if (area == NULL) {
/* background mode */
t->spacetype = SPACE_EMPTY;
}
- else if ((region == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
+ else if ((region == NULL) && (area->spacetype == SPACE_VIEW3D)) {
/* running in the text editor */
t->spacetype = SPACE_EMPTY;
}
else {
/* normal operation */
- t->spacetype = sa->spacetype;
+ t->spacetype = area->spacetype;
}
/* handle T_ALT_TRANSFORM initialization, we may use for different operators */
@@ -1491,7 +1478,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
t->view = v3d;
@@ -1513,22 +1500,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CURSOR;
}
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- t->orientation.unset = V3D_ORIENT_GLOBAL;
- t->orientation.user = orient_slot->type;
- t->orientation.custom = BKE_scene_transform_orientation_find(t->scene,
- orient_slot->index_custom);
-
- t->orientation.index = 0;
- ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL);
-
- /* Make second orientation local if both are global. */
- if (t->orientation.user == V3D_ORIENT_GLOBAL) {
- t->orientation.user_alt = V3D_ORIENT_LOCAL;
- t->orientation.types[0] = &t->orientation.user_alt;
- SWAP(short *, t->orientation.types[0], t->orientation.types[1]);
- }
-
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
@@ -1564,7 +1535,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
// XXX for now, get View2D from the active region
t->view = &region->v2d;
t->around = sima->around;
@@ -1589,12 +1560,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = sa->spacedata.first;
+ SpaceGraph *sipo = area->spacedata.first;
t->view = &region->v2d;
t->around = sipo->around;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = sa->spacedata.first;
+ SpaceClip *sclip = area->spacedata.first;
t->view = &region->v2d;
t->around = sclip->around;
@@ -1617,48 +1588,152 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
- t->orient_axis = RNA_property_enum_get(op->ptr, prop);
- }
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
- t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
- }
+ BLI_assert(is_zero_v4(t->values_modal_offset));
+ bool t_values_set_is_array = false;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "value")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
+ if (RNA_property_array_check(prop)) {
+ RNA_float_get_array(op->ptr, "value", values);
+ t_values_set_is_array = true;
+ }
+ else {
+ values[0] = RNA_float_get(op->ptr, "value");
+ }
- if (op &&
- ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
- RNA_property_is_set(op->ptr, prop)) &&
- ((t->flag & T_MODAL) ||
- /* When using redo, don't use the custom constraint matrix
- * if the user selects a different orientation. */
- (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) {
- RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]);
- copy_m3_m3(t->spacemtx, t->orient_matrix);
- /* Some transform modes use this to operate on an axis. */
- t->orient_matrix_is_set = true;
- t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
- t->orientation.custom = 0;
+ copy_v4_v4(t->values, values);
if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type"));
+ /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */
+ copy_v4_v4(t->values_modal_offset, values);
+ }
+ else {
+ copy_v4_v4(t->values, values);
+ t->flag |= T_INPUT_IS_VALUES_FINAL;
}
}
- else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- RNA_property_is_set(op->ptr, prop))) {
- short orientation = RNA_property_enum_get(op->ptr, prop);
- TransformOrientation *custom_orientation = NULL;
- if (orientation >= V3D_ORIENT_CUSTOM) {
- if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orientation = V3D_ORIENT_GLOBAL;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
+ bool constraint_axis[3] = {false, false, false};
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+ }
+
+ if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) {
+ /* For operators whose `t->values` is array, set constraint so that the
+ * orientation is more intuitive in the Redo Panel. */
+ for (int i = 3; i--;) {
+ constraint_axis[i] |= t->values[i] != 0.0f;
+ }
+ }
+
+ if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+ t->con.mode |= CON_APPLY;
+
+ if (constraint_axis[0]) {
+ t->con.mode |= CON_AXIS0;
+ }
+ if (constraint_axis[1]) {
+ t->con.mode |= CON_AXIS1;
+ }
+ if (constraint_axis[2]) {
+ t->con.mode |= CON_AXIS2;
+ }
+ }
+ }
+
+ {
+ short orient_type_set = -1;
+ short orient_type_matrix_set = -1;
+ short orient_type_scene = V3D_ORIENT_GLOBAL;
+
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
+ orient_type_scene = orient_slot->type;
+ if (orient_type_scene == V3D_ORIENT_CUSTOM) {
+ const int index_custom = orient_slot->index_custom;
+ orient_type_scene += index_custom;
+ }
+ }
+
+ short orient_types[3];
+ float custom_matrix[3][3];
+ bool use_orient_axis = false;
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
+ t->orient_axis = RNA_property_enum_get(op->ptr, prop);
+ use_orient_axis = true;
+ }
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
+ t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ orient_type_set = RNA_property_enum_get(op->ptr, prop);
+ if (orient_type_set >= V3D_ORIENT_CUSTOM) {
+ if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+ orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+ }
+
+ /* Change the default orientation to be used when redoing. */
+ orient_types[0] = orient_type_set;
+ orient_types[1] = orient_type_set;
+ orient_types[2] = orient_type_scene;
+ }
+ else {
+ if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) {
+ orient_types[0] = V3D_ORIENT_VIEW;
+ }
+ else {
+ orient_types[0] = orient_type_scene;
+ }
+ orient_types[1] = orient_type_scene;
+ orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+ V3D_ORIENT_LOCAL;
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]);
+
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
+ }
+ else if (orient_type_set != -1) {
+ orient_type_matrix_set = orient_type_set;
}
else {
- custom_orientation = BKE_scene_transform_orientation_find(t->scene,
- orientation - V3D_ORIENT_CUSTOM);
- orientation = V3D_ORIENT_CUSTOM;
+ orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+
+ if (orient_type_matrix_set == orient_type_set) {
+ /* Constraints are forced to use the custom matrix when redoing. */
+ orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX;
}
}
- t->orientation.user = orientation;
- t->orientation.custom = custom_orientation;
+ if (t->con.mode & CON_APPLY) {
+ t->orient_curr = 1;
+ }
+
+ /* For efficiency, avoid calculating the same orientation twice. */
+ for (int i = 1; i < 3; i++) {
+ t->orient[i].type = transform_orientation_matrix_get(
+ C, t, orient_types[i], custom_matrix, t->orient[i].matrix);
+ }
+
+ if (orient_types[0] != orient_types[1]) {
+ t->orient[0].type = transform_orientation_matrix_get(
+ C, t, orient_types[0], custom_matrix, t->orient[0].matrix);
+ }
+ else {
+ memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0]));
+ }
+
+ const char *spacename = transform_orientations_spacename_get(t, orient_types[0]);
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1763,6 +1838,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->options |= CTX_NO_PET;
}
+ if (t->obedit_type == OB_MESH) {
+ if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ t->flag |= T_AUTOMERGE | T_AUTOSPLIT;
+ }
+ }
+ else {
+ char automerge = t->scene->toolsettings->automerge;
+ if (automerge & AUTO_MERGE) {
+ t->flag |= T_AUTOMERGE;
+ if (automerge & AUTO_MERGE_AND_SPLIT) {
+ t->flag |= T_AUTOSPLIT;
+ }
+ }
+ }
+ }
+
// Mirror is not supported with PET, turn it off.
#if 0
if (t->flag & T_PROP_EDIT) {
@@ -1833,7 +1926,7 @@ void postTrans(bContext *C, TransInfo *t)
ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel);
}
if (t->draw_handle_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
+ WM_paint_cursor_end(t->draw_handle_cursor);
}
if (t->flag & T_MODAL_CURSOR_SET) {
@@ -1876,14 +1969,14 @@ void postTrans(bContext *C, TransInfo *t)
/* pass */
}
else {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (sima->flag & SI_LIVE_UNWRAP) {
ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
}
}
}
else if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = t->sa->spacedata.first;
+ View3D *v3d = t->area->spacedata.first;
/* restore gizmo */
if (t->flag & T_MODAL) {
v3d->gizmo_flag = t->gizmo_flag;
@@ -2023,11 +2116,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
cursor = sima->cursor;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
cursor = space_clip->cursor;
}
@@ -2036,11 +2129,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
float co[2];
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
}
else {
@@ -2065,7 +2158,7 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
/* cursor is combination of current frame, and graph-editor cursor value */
@@ -2312,19 +2405,11 @@ void calculatePropRatio(TransInfo *t)
}
else if ((connected && (td->flag & TD_NOTCONNECTED || td->dist > t->prop_size)) ||
(connected == 0 && td->rdist > t->prop_size)) {
- /*
- * The elements are sorted according to their dist member in the array,
- * that means we can stop when it finds one element outside of the propsize.
- * do not set 'td->flag |= TD_NOACTION', the prop circle is being changed.
- */
-
td->factor = 0.0f;
restoreElement(td);
}
else {
/* Use rdist for falloff calculations, it is the real distance */
- td->flag &= ~TD_NOACTION;
-
if (connected) {
dist = (t->prop_size - td->dist) / t->prop_size;
}
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index e85b9f0bee1..c63e90ac2b7 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -68,10 +68,10 @@ static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
if (!ED_space_image_show_uvedit(sima, obedit)) {
return false;
@@ -86,7 +86,7 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
/* Additional args. */
bScreen *screen,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region)
{
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
@@ -95,9 +95,9 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
.notify = WM_gizmo_do_msg_notify_tag_refresh,
};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr);
{
@@ -214,17 +214,15 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
r_max = max_buf;
}
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool changed = false;
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = ED_space_image(sima);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
view_layer, NULL, &objects_len);
- if (ED_uvedit_minmax_multi(scene, ima, objects, objects_len, r_min, r_max)) {
+ if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
changed = true;
}
MEM_freeN(objects);
@@ -241,11 +239,11 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool has_select = false;
zero_v2(r_center);
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
@@ -509,9 +507,9 @@ static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
@@ -671,9 +669,9 @@ static void gizmo2d_resize_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
@@ -791,9 +789,9 @@ static void gizmo2d_rotate_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, region);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index de7b2ec02de..ebc021cd983 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -347,7 +347,7 @@ static void gizmo_get_axis_color(const int axis_idx,
if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
/* Never fade rotation rings. */
/* trackball rotation axis is a special case, we only draw a slight overlay */
- alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
+ alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f;
}
else {
bool is_plane = false;
@@ -635,113 +635,20 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
return 0;
}
-void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3])
-{
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *obedit = CTX_data_edit_object(C);
- RegionView3D *rv3d = region->regiondata;
- Object *ob = OBACT(view_layer);
- const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
- const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
- const int pivot_point = scene->toolsettings->transform_pivot_point;
-
- ED_transform_calc_orientation_from_type_ex(
- C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
-}
-
-void ED_transform_calc_orientation_from_type_ex(const bContext *C,
- float r_mat[3][3],
- /* extra args (can be accessed from context) */
- Scene *scene,
- RegionView3D *rv3d,
- Object *ob,
- Object *obedit,
- const short orientation_type,
- int orientation_index_custom,
- const int pivot_point)
-{
- bool ok = false;
-
- switch (orientation_type) {
- case V3D_ORIENT_GLOBAL: {
- break; /* nothing to do */
- }
- case V3D_ORIENT_GIMBAL: {
- if (gimbal_axis(ob, r_mat)) {
- ok = true;
- break;
- }
- /* if not gimbal, fall through to normal */
- ATTR_FALLTHROUGH;
- }
- case V3D_ORIENT_NORMAL: {
- if (obedit || ob->mode & OB_MODE_POSE) {
- ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
- ok = true;
- break;
- }
- /* no break we define 'normal' as 'local' in Object mode */
- ATTR_FALLTHROUGH;
- }
- case V3D_ORIENT_LOCAL: {
- if (ob->mode & OB_MODE_POSE) {
- /* each bone moves on its own local axis, but to avoid confusion,
- * use the active pones axis for display [#33575], this works as expected on a single bone
- * and users who select many bones will understand what's going on and what local means
- * when they start transforming */
- ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
- ok = true;
- break;
- }
- copy_m3_m4(r_mat, ob->obmat);
- normalize_m3(r_mat);
- ok = true;
- break;
- }
- case V3D_ORIENT_VIEW: {
- if (rv3d != NULL) {
- copy_m3_m4(r_mat, rv3d->viewinv);
- normalize_m3(r_mat);
- ok = true;
- }
- break;
- }
- case V3D_ORIENT_CURSOR: {
- BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
- ok = true;
- break;
- }
- case V3D_ORIENT_CUSTOM: {
- TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
- scene, orientation_index_custom);
- if (applyTransformOrientation(custom_orientation, r_mat, NULL)) {
- ok = true;
- }
- break;
- }
- }
-
- if (!ok) {
- unit_m3(r_mat);
- }
-}
-
/* centroid, boundbox, of selection */
/* returns total items selected */
int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
/* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh().
* Is it fine to possibly evaluate dependency graph here? */
Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
RegionView3D *rv3d = region->regiondata;
Base *base;
@@ -800,7 +707,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* calculate difference matrix */
BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
- for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -883,7 +790,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (use_mat_local) {
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (EBONE_VISIBLE(arm, ebo)) {
if (ebo->flag & BONE_TIPSEL) {
calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local);
@@ -927,7 +834,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
* if handles are hidden then only check the center points.
* If the center knot is selected then only use this as the center point.
*/
- if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) {
+ if (v3d->overlay.handle_display == CURVE_HANDLE_NONE) {
if (bezt->f2 & SELECT) {
calc_tw_center_with_matrix(tbounds, bezt->vec[1], use_mat_local, mat_local);
totsel++;
@@ -977,7 +884,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (ml->flag & SELECT) {
calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local);
totsel++;
@@ -1033,7 +940,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */
const int mode = TFM_ROTATION;
- const int totsel_iter = count_set_pose_transflags(
+ const int totsel_iter = transform_convert_pose_transflags_update(
ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
if (totsel_iter) {
@@ -1244,7 +1151,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
- ScrArea *sa,
+ ScrArea *area,
ARegion *region,
const void *type_fn)
{
@@ -1334,7 +1241,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
PointerRNA view3d_ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceView3D, area->spacedata.first, &view3d_ptr);
if (type_fn == VIEW3D_GGT_xform_gizmo) {
GizmoGroup *ggd = gzgroup->customdata;
@@ -1388,21 +1295,21 @@ void drawDial3d(const TransInfo *t)
if (tc->mode & CON_APPLY) {
if (tc->mode & CON_AXIS0) {
axis_idx = MAN_AXIS_ROT_X;
- negate_v3_v3(mat_basis[2], tc->mtx[0]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[0]);
}
else if (tc->mode & CON_AXIS1) {
axis_idx = MAN_AXIS_ROT_Y;
- negate_v3_v3(mat_basis[2], tc->mtx[1]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[1]);
}
else {
BLI_assert((tc->mode & CON_AXIS2) != 0);
axis_idx = MAN_AXIS_ROT_Z;
- negate_v3_v3(mat_basis[2], tc->mtx[2]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[2]);
}
}
else {
axis_idx = MAN_AXIS_ROT_C;
- negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
scale *= 1.2f;
line_with -= 1.0f;
}
@@ -1701,8 +1608,8 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzgroup->customdata = ggd;
{
- ScrArea *sa = CTX_wm_area(C);
- const bToolRef *tref = sa->runtime.tool;
+ ScrArea *area = CTX_wm_area(C);
+ const bToolRef *tref = area->runtime.tool;
ggd->twtype = 0;
if (tref && STREQ(tref->idname, "builtin.move")) {
@@ -1737,8 +1644,8 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
ARegion *region = CTX_wm_region(C);
RegionView3D *rv3d = region->regiondata;
struct TransformBounds tbounds;
@@ -1844,17 +1751,18 @@ static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_gizmo);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo);
}
static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
- // ScrArea *sa = CTX_wm_area(C);
+ // ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- // View3D *v3d = sa->spacedata.first;
+ // View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
@@ -1997,13 +1905,13 @@ static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
static bool WIDGETGROUP_gizmo_poll_context(const struct bContext *C,
struct wmGizmoGroupType *UNUSED(gzgt))
{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
- const bToolRef *tref = sa->runtime.tool;
+ const bToolRef *tref = area->runtime.tool;
if (v3d->gizmo_flag & V3D_GIZMO_HIDE_CONTEXT) {
return false;
}
@@ -2025,8 +1933,8 @@ static bool WIDGETGROUP_gizmo_poll_tool(const struct bContext *C, struct wmGizmo
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
@@ -2198,6 +2106,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true);
}
else {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = OBACT(view_layer);
+ if (ob && ob->mode & OB_MODE_EDIT) {
+ copy_m4_m4(gz->matrix_space, ob->obmat);
+ }
+ else {
+ unit_m4(gz->matrix_space);
+ }
+
gizmo_prepare_mat(C, rv3d, &tbounds);
WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false);
@@ -2247,23 +2164,14 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_cage);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
- wmGizmo *gz = xgzgroup->gizmo;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = OBACT(view_layer);
- if (ob && ob->mode & OB_MODE_EDIT) {
- copy_m4_m4(gz->matrix_space, ob->obmat);
- }
- else {
- unit_m4(gz->matrix_space);
- }
RegionView3D *rv3d = CTX_wm_region_view3d(C);
{
@@ -2460,9 +2368,10 @@ static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, region, VIEW3D_GGT_xform_shear);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
index 31aae4f5b05..c2c880b03ff 100644
--- a/source/blender/editors/transform/transform_mode.c
+++ b/source/blender/editors/transform/transform_mode.c
@@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around)
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
}
+/* Informs if the mode can be switched during modal. */
+bool transform_mode_is_changeable(const int mode)
+{
+ return ELEM(mode,
+ TFM_ROTATION,
+ TFM_RESIZE,
+ TFM_TRACKBALL,
+ TFM_TRANSLATION,
+ TFM_EDGE_SLIDE,
+ TFM_VERT_SLIDE);
+}
+
/* -------------------------------------------------------------------- */
/** \name Transform Locks
* \{ */
@@ -529,7 +541,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
void postInputRotation(TransInfo *t, float values[3])
{
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, values);
}
@@ -1028,21 +1040,21 @@ short getAnimEdit_SnapMode(TransInfo *t)
short autosnap = SACTSNAP_OFF;
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
if (saction) {
autosnap = saction->autosnap;
}
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
if (sipo) {
autosnap = sipo->autosnap;
}
}
else if (t->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
if (snla) {
autosnap = snla->autosnap;
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
index 6180f6d3477..074e89390c2 100644
--- a/source/blender/editors/transform/transform_mode.h
+++ b/source/blender/editors/transform/transform_mode.h
@@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert {
/* transform_mode.c */
bool transdata_check_local_center(TransInfo *t, short around);
+bool transform_mode_is_changeable(const int mode);
void protectedTransBits(short protectflag, float vec[3]);
void constraintTransLim(TransInfo *t, TransData *td);
void postInputRotation(TransInfo *t, float values[3]);
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
index fbd5e87f034..4fd4599b940 100644
--- a/source/blender/editors/transform/transform_mode_align.c
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -52,10 +52,6 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
for (i = 0; i < tc->data_len; i++, td++) {
float mat[3][3], invmat[3][3];
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -82,7 +78,7 @@ static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, TIP_("Align"));
+ ED_area_status_text(t->area, TIP_("Align"));
}
void initAlign(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
index 0feaa27d4ce..4e7fc3578ce 100644
--- a/source/blender/editors/transform/transform_mode_baketime.c
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -97,10 +97,6 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -119,7 +115,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBakeTime(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
index 1a32a550cb0..77850e74785 100644
--- a/source/blender/editors/transform/transform_mode_bbone_resize.c
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -141,10 +141,6 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -155,7 +151,7 @@ static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneSize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
index bf80673fbb4..3b51626b170 100644
--- a/source/blender/editors/transform/transform_mode_bend.c
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -186,10 +186,6 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
float delta[3];
float fac, fac_scaled;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -246,7 +242,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBend(TransInfo *t)
@@ -289,7 +285,8 @@ void initBend(TransInfo *t)
curs = t->scene->cursor.location;
copy_v3_v3(data->warp_sta, curs);
- ED_view3d_win_to_3d((View3D *)t->sa->spacedata.first, t->region, curs, mval_fl, data->warp_end);
+ ED_view3d_win_to_3d(
+ (View3D *)t->area->spacedata.first, t->region, curs, mval_fl, data->warp_end);
copy_v3_v3(data->warp_nor, t->viewinv[2]);
normalize_v3(data->warp_nor);
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
index 0886d4e01ef..7045d190478 100644
--- a/source/blender/editors/transform/transform_mode_boneenvelope.c
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -73,10 +73,6 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -95,7 +91,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneEnvelope(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
index 8e9d680f269..1503519c519 100644
--- a/source/blender/editors/transform/transform_mode_boneroll.c
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -75,10 +75,6 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -89,7 +85,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBoneRoll(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
index 6ccb0e757c3..84e4e950804 100644
--- a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -73,10 +73,6 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -94,7 +90,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initCurveShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
index 15a9e7384b1..399cec2d62c 100644
--- a/source/blender/editors/transform/transform_mode_edge_bevelweight.c
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -87,10 +87,6 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->val) {
*td->val = td->ival + weight * td->factor;
if (*td->val < 0.0f) {
@@ -105,7 +101,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initBevelWeight(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
index 8865721bc7e..53c948c742b 100644
--- a/source/blender/editors/transform/transform_mode_edge_crease.c
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -87,10 +87,6 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -109,7 +105,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initCrease(TransInfo *t)
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 69cd909cff9..fde0d5b187e 100644
--- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
char str[UI_MAX_DRAW_STR];
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
@@ -121,7 +121,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initNormalRotation(TransInfo *t)
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 e23e5c188c8..c1cb4325c09 100644
--- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -81,10 +81,6 @@ static void applySeqSlideValue(TransInfo *t, const float val[2])
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -101,9 +97,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
snapSequenceBounds(t, mval);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
float tvec[3];
- t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
+ t->con.applyVec(t, NULL, NULL, t->values, tvec);
copy_v3_v3(t->values_final, tvec);
}
else {
@@ -120,7 +115,7 @@ static void applySeqSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initSeqSlide(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
index b54e6afc9a1..5613a782529 100644
--- a/source/blender/editors/transform/transform_mode_edge_slide.c
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -334,7 +334,7 @@ static void calcEdgeSlide_mval_range(TransInfo *t,
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
}
@@ -858,7 +858,7 @@ static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *t
/* use for visibility checks */
if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
!XRAY_ENABLED(v3d));
@@ -899,7 +899,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
if (t->spacetype == SPACE_VIEW3D) {
/* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
}
@@ -1043,7 +1043,7 @@ static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *t
/* use for visibility checks */
if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
+ v3d = t->area ? t->area->spacedata.first : NULL;
rv3d = t->region ? t->region->regiondata : NULL;
use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
!XRAY_ENABLED(v3d));
@@ -1417,7 +1417,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initEdgeSlide_ex(
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
index 460e2b41da8..4712fb7ba01 100644
--- a/source/blender/editors/transform/transform_mode_gpopacity.c
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -73,10 +73,6 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -90,7 +86,7 @@ static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
}
}
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initGPOpacity(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
index edb353b343d..ab9a0aa79ed 100644
--- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -73,10 +73,6 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -92,7 +88,7 @@ static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
}
}
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initGPShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
index b6719067f5b..68f3abda85b 100644
--- a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -78,10 +78,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -97,10 +93,6 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -124,7 +116,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initMaskShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
index 2f305989f82..8d953610eb8 100644
--- a/source/blender/editors/transform/transform_mode_mirror.c
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -69,10 +69,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -83,7 +79,7 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
else {
size[0] = size[1] = size[2] = 1;
@@ -93,10 +89,6 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -108,10 +100,10 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
if (t->flag & T_2D_EDIT) {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y)"));
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y)"));
}
else {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y, Z)"));
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y, Z)"));
}
}
}
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
index 890fc820cd5..4a2f979ec38 100644
--- a/source/blender/editors/transform/transform_mode_push_pull.c
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -82,10 +82,6 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -114,7 +110,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initPushPull(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
index 59f2ab5c294..d919d5c889d 100644
--- a/source/blender/editors/transform/transform_mode_resize.c
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -93,10 +93,6 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -131,7 +127,7 @@ static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initResize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
index bea039194d0..6480cb6c30e 100644
--- a/source/blender/editors/transform/transform_mode_rotate.c
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -82,10 +82,6 @@ static void applyRotationValue(TransInfo *t,
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -146,7 +142,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
snapGridIncrement(t, &final);
float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
+ /* Use the negative axis to match the default Z axis of the view matrix. */
+ negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
t->con.applyRot(t, NULL, NULL, axis_final, NULL);
@@ -169,7 +166,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initRotation(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
index 8b7dc12f41b..fa33c1550e7 100644
--- a/source/blender/editors/transform/transform_mode_shear.c
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t)
{
float dir[3];
bool dir_flip = false;
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
+ copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
/* Needed for axis aligned view gizmo. */
- if (t->orientation.user == V3D_ORIENT_VIEW) {
+ if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) {
if (t->orient_axis_ortho == 0) {
if (t->center2d[1] > t->mouse.imval[1]) {
dir_flip = !dir_flip;
@@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
unit_m3(smat);
smat[1][0] = value;
- copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
- copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
+ copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]);
+ copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]);
cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
invert_m3_m3(axismat, axismat_inv);
@@ -165,11 +165,6 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
const float *center, *co;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -217,7 +212,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initShear(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
index e24e63f445c..78d3efa0d69 100644
--- a/source/blender/editors/transform/transform_mode_shrink_fatten.c
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -95,10 +95,6 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
float tdistance; /* temp dist */
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -115,7 +111,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initShrinkFatten(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
index 23ba9a07f3e..23d83050613 100644
--- a/source/blender/editors/transform/transform_mode_skin_resize.c
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -73,11 +73,6 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
for (i = 0; i < tc->data_len; i++, td++) {
float tmat[3][3], smat[3][3];
float fsize[3];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -102,7 +97,7 @@ static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initSkinResize(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
index 9ae0cfdf805..ca0a8818477 100644
--- a/source/blender/editors/transform/transform_mode_tilt.c
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -77,10 +77,6 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -93,7 +89,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTilt(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
index b75ef4da0f2..ce46cc36276 100644
--- a/source/blender/editors/transform/transform_mode_timescale.c
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -109,7 +109,7 @@ static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeScale(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
index fce526873f1..43e14a26930 100644
--- a/source/blender/editors/transform/transform_mode_timeslide.c
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -82,7 +82,7 @@ static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
/* set value for drawing black line */
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
saction->timeslide = cval;
}
@@ -160,14 +160,14 @@ static void applyTimeSlide(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeSlide(TransInfo *t)
{
/* this tool is only really available in the Action Editor... */
if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
/* set flag for drawing stuff */
saction->flag |= SACTION_MOVING;
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
index 494609cafb0..c514df497bc 100644
--- a/source/blender/editors/transform/transform_mode_timetranslate.c
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -136,7 +136,7 @@ static void applyTimeTranslate(TransInfo *t, const int mval[2])
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTimeTranslate(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
index 5a3b138823c..f6c5448a906 100644
--- a/source/blender/editors/transform/transform_mode_tosphere.c
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -79,10 +79,6 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
float tratio;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -101,7 +97,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initToSphere(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
index 758ee3b9cae..ca5a749b275 100644
--- a/source/blender/editors/transform/transform_mode_trackball.c
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -63,10 +63,6 @@ static void applyTrackballValue(TransInfo *t,
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -143,7 +139,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initTrackball(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
index aef5a999d18..96820ca6385 100644
--- a/source/blender/editors/transform/transform_mode_translate.c
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -191,7 +191,7 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_
}
if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
const char *str_old = BLI_strdup(str);
@@ -236,10 +236,6 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -277,8 +273,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
}
if (t->con.applyVec) {
- float pvec[3];
- t->con.applyVec(t, tc, td, vec, tvec, pvec);
+ t->con.applyVec(t, tc, td, vec, tvec);
}
else {
copy_v3_v3(tvec, vec);
@@ -319,45 +314,39 @@ static void applyTranslationValue(TransInfo *t, const float vec[3])
static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
{
char str[UI_MAX_DRAW_STR];
- float values_final[3];
+ float global_dir[3];
if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
+ mul_v3_m3v3(global_dir, t->spacemtx, t->values);
}
else {
- copy_v3_v3(t->values_final, t->values);
+ copy_v3_v3(global_dir, t->values);
if ((t->con.mode & CON_APPLY) == 0) {
- snapGridIncrement(t, t->values_final);
+ snapGridIncrement(t, global_dir);
}
- if (applyNumInput(&t->num, t->values_final)) {
- removeAspectRatio(t, t->values_final);
+ if (applyNumInput(&t->num, global_dir)) {
+ removeAspectRatio(t, global_dir);
}
- applySnapping(t, t->values_final);
+ applySnapping(t, global_dir);
}
- copy_v3_v3(values_final, t->values_final);
if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
- headerTranslation(t, pvec, str);
-
- /* only so we have re-usable value with redo, see T46741. */
- mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
+ float in[3];
+ copy_v3_v3(in, global_dir);
+ t->con.applyVec(t, NULL, NULL, in, global_dir);
+ headerTranslation(t, global_dir, str);
}
else {
- headerTranslation(t, t->values_final, str);
- copy_v3_v3(values_final, t->values_final);
+ headerTranslation(t, global_dir, str);
}
- /* don't use 't->values' now on */
-
- applyTranslationValue(t, values_final);
+ applyTranslationValue(t, global_dir);
/* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
- applyTranslationValue(t, values_final);
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) {
+ applyTranslationValue(t, global_dir);
/* In proportional edit it can happen that */
/* vertices in the radius of the brush end */
@@ -368,9 +357,11 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
}
}
- recalcData(t);
+ /* Set the redo value. */
+ mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir);
- ED_area_status_text(t->sa, str);
+ recalcData(t);
+ ED_area_status_text(t->area, str);
}
void initTranslation(TransInfo *t)
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
index 2325c4d1d26..7bee48337f9 100644
--- a/source/blender/editors/transform/transform_mode_vert_slide.c
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -602,7 +602,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
recalcData(t);
- ED_area_status_text(t->sa, str);
+ ED_area_status_text(t->area, str);
}
void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 7e56b34af2f..d643244e6ca 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -223,6 +223,9 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+
return OPERATOR_FINISHED;
}
@@ -233,12 +236,11 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent
static bool delete_orientation_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
-
if (ED_operator_areaactive(C) == 0) {
return 0;
}
+ Scene *scene = CTX_data_scene(C);
return ((scene->orientation_slots[SCE_ORIENT_DEFAULT].type >= V3D_ORIENT_CUSTOM) &&
(scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom != -1));
}
@@ -264,6 +266,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
const bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
const bool use_view = RNA_boolean_get(op->ptr, "use_view");
View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
RNA_string_get(op->ptr, "name", name);
@@ -274,10 +277,18 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite);
+ if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create orientation");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (use) {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ }
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -705,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+ if (flags & P_POST_TRANSFORM) {
+ prop = RNA_def_boolean(ot->srna,
+ "use_automerge_and_split",
+ 0,
+ "Auto Merge & Split",
+ "Forces the use of Auto Merge & Split");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
@@ -730,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
- P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT);
+ P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -893,8 +913,8 @@ static bool transform_shear_poll(bContext *C)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- return sa && !ELEM(sa->spacetype, SPACE_ACTION);
+ ScrArea *area = CTX_wm_area(C);
+ return area && !ELEM(area->spacetype, SPACE_ACTION);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 5cc1feddf7a..cd170b144d8 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -296,7 +296,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
return true;
}
-void BIF_createTransformOrientation(bContext *C,
+bool BIF_createTransformOrientation(bContext *C,
ReportList *reports,
const char *name,
const bool use_view,
@@ -333,6 +333,7 @@ void BIF_createTransformOrientation(bContext *C,
if (activate && ts != NULL) {
BIF_selectTransformOrientation(C, ts);
}
+ return (ts != NULL);
}
TransformOrientation *addMatrixSpace(bContext *C,
@@ -396,24 +397,27 @@ int BIF_countTransformOrientation(const bContext *C)
return BLI_listbase_count(transform_orientations);
}
-bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
+void applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3], char *r_name)
{
if (r_name) {
BLI_strncpy(r_name, ts->name, MAX_NAME);
}
copy_m3_m3(r_mat, ts->mat);
-
- return true;
}
-static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
+/* Updates all `BONE_TRANSFORM` flags.
+ * Returns total number of bones with `BONE_TRANSFORM`.
+ * Note: `transform_convert_pose_transflags_update` has a similar logic. */
+static int armature_bone_transflags_update_recursive(bArmature *arm,
+ ListBase *lb,
+ const bool do_it)
{
Bone *bone;
bool do_next;
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
@@ -426,109 +430,194 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
}
}
}
- total += count_bone_select(arm, &bone->childbase, do_next);
+ total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next);
}
return total;
}
-void initTransformOrientation(bContext *C, TransInfo *t)
+void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3])
{
- Object *ob = CTX_data_active_object(C);
- Object *obedit = CTX_data_active_object(C);
+ ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *obedit = CTX_data_edit_object(C);
+ RegionView3D *rv3d = region->regiondata;
+ Object *ob = OBACT(view_layer);
+ const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
+ const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
+ const int pivot_point = scene->toolsettings->transform_pivot_point;
- switch (t->orientation.user) {
- case V3D_ORIENT_GLOBAL:
- unit_m3(t->spacemtx);
- BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
- break;
+ ED_transform_calc_orientation_from_type_ex(
+ C, r_mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
+}
- case V3D_ORIENT_GIMBAL:
- unit_m3(t->spacemtx);
- if (ob && gimbal_axis(ob, t->spacemtx)) {
- BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename));
- break;
+short ED_transform_calc_orientation_from_type_ex(const bContext *C,
+ float r_mat[3][3],
+ /* extra args (can be accessed from context) */
+ Scene *scene,
+ RegionView3D *rv3d,
+ Object *ob,
+ Object *obedit,
+ const short orientation_type,
+ int orientation_index_custom,
+ const int pivot_point)
+{
+ switch (orientation_type) {
+ case V3D_ORIENT_GLOBAL: {
+ unit_m3(r_mat);
+ return V3D_ORIENT_GLOBAL;
+ }
+ case V3D_ORIENT_GIMBAL: {
+ if (gimbal_axis(ob, r_mat)) {
+ return V3D_ORIENT_GIMBAL;
}
- ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */
- case V3D_ORIENT_NORMAL:
- if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
- BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename));
- ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
- break;
+ /* if not gimbal, fall through to normal */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_ORIENT_NORMAL: {
+ if (obedit || ob->mode & OB_MODE_POSE) {
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ return V3D_ORIENT_NORMAL;
}
- ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */
- case V3D_ORIENT_LOCAL:
- BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename));
-
+ /* no break we define 'normal' as 'local' in Object mode */
+ ATTR_FALLTHROUGH;
+ }
+ case V3D_ORIENT_LOCAL: {
if (ob) {
- copy_m3_m4(t->spacemtx, ob->obmat);
- normalize_m3(t->spacemtx);
- }
- else {
- unit_m3(t->spacemtx);
+ if (ob->mode & OB_MODE_POSE) {
+ /* each bone moves on its own local axis, but to avoid confusion,
+ * use the active pones axis for display [#33575], this works as expected on a single
+ * bone and users who select many bones will understand what's going on and what local
+ * means when they start transforming */
+ ED_getTransformOrientationMatrix(C, r_mat, pivot_point);
+ }
+ else {
+ copy_m3_m4(r_mat, ob->obmat);
+ normalize_m3(r_mat);
+ }
+ return V3D_ORIENT_LOCAL;
}
-
- break;
-
- case V3D_ORIENT_VIEW:
- if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
- RegionView3D *rv3d = t->region->regiondata;
- float mat[3][3];
-
- BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
- copy_m3_m4(mat, rv3d->viewinv);
- normalize_m3(mat);
- copy_m3_m3(t->spacemtx, mat);
+ unit_m3(r_mat);
+ return V3D_ORIENT_GLOBAL;
+ }
+ case V3D_ORIENT_VIEW: {
+ if (rv3d != NULL) {
+ copy_m3_m4(r_mat, rv3d->viewinv);
+ normalize_m3(r_mat);
}
else {
- unit_m3(t->spacemtx);
+ unit_m3(r_mat);
}
- break;
+ return V3D_ORIENT_VIEW;
+ }
case V3D_ORIENT_CURSOR: {
- BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
- BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
- break;
+ BKE_scene_cursor_rot_to_mat3(&scene->cursor, r_mat);
+ return V3D_ORIENT_CURSOR;
}
- case V3D_ORIENT_CUSTOM_MATRIX:
- /* Already set. */
- BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
+ case V3D_ORIENT_CUSTOM_MATRIX: {
+ /* Do nothing. */;
break;
+ }
case V3D_ORIENT_CUSTOM:
- BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
-
- if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
- /* pass */
- }
- else {
- unit_m3(t->spacemtx);
- }
+ default: {
+ BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
+ scene, orientation_index_custom);
+ applyTransformOrientation(custom_orientation, r_mat, NULL);
break;
+ }
}
- if (t->orient_matrix_is_set == false) {
- t->orient_matrix_is_set = true;
- if (t->flag & T_MODAL) {
- /* Rotate for example defaults to operating on the view plane. */
- t->orientation.unset = V3D_ORIENT_VIEW;
- copy_m3_m4(t->orient_matrix, t->viewinv);
- normalize_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- }
- else {
- copy_m3_m3(t->orient_matrix, t->spacemtx);
+ return orientation_type;
+}
+
+/* Sets the matrix of the specified space orientation.
+ * If the matrix cannot be obtained, an orientation different from the one
+ * informed is returned */
+short transform_orientation_matrix_get(bContext *C,
+ TransInfo *t,
+ const short orientation,
+ const float custom[3][3],
+ float r_spacemtx[3][3])
+{
+ if (orientation == V3D_ORIENT_CUSTOM_MATRIX) {
+ copy_m3_m3(r_spacemtx, custom);
+ return V3D_ORIENT_CUSTOM_MATRIX;
+ }
+
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
+ Object *ob = CTX_data_active_object(C);
+ Object *obedit = CTX_data_active_object(C);
+ RegionView3D *rv3d = t->region->regiondata;
+ int orientation_index_custom = 0;
+
+ if (orientation >= V3D_ORIENT_CUSTOM) {
+ orientation_index_custom = orientation - V3D_ORIENT_CUSTOM;
}
+
+ return ED_transform_calc_orientation_from_type_ex(
+ C,
+ r_spacemtx,
+ /* extra args (can be accessed from context) */
+ t->scene,
+ rv3d,
+ ob,
+ obedit,
+ orientation,
+ orientation_index_custom,
+ t->around);
}
+
+ unit_m3(r_spacemtx);
+ return V3D_ORIENT_GLOBAL;
+}
+
+const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type)
+{
+ switch (orient_type) {
+ case V3D_ORIENT_GLOBAL:
+ return TIP_("global");
+ case V3D_ORIENT_GIMBAL:
+ return TIP_("gimbal");
+ case V3D_ORIENT_NORMAL:
+ return TIP_("normal");
+ case V3D_ORIENT_LOCAL:
+ return TIP_("local");
+ case V3D_ORIENT_VIEW:
+ return TIP_("view");
+ case V3D_ORIENT_CURSOR:
+ return TIP_("cursor");
+ case V3D_ORIENT_CUSTOM_MATRIX:
+ return TIP_("custom");
+ case V3D_ORIENT_CUSTOM:
+ default:
+ BLI_assert(orient_type >= V3D_ORIENT_CUSTOM);
+ TransformOrientation *ts = BKE_scene_transform_orientation_find(
+ t->scene, orient_type - V3D_ORIENT_CUSTOM);
+ return ts->name;
+ }
+}
+
+void transform_orientations_current_set(TransInfo *t, const short orient_index)
+{
+ const short orientation = t->orient[orient_index].type;
+ const char *spacename = transform_orientations_spacename_get(t, orientation);
+
+ BLI_strncpy(t->spacename, spacename, sizeof(t->spacename));
+ copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix);
+ invert_m3_m3(t->spacemtx_inv, t->spacemtx);
}
/**
* utility function - get first n, selected vert/edge/faces
*/
-static unsigned int bm_mesh_elems_select_get_n__internal(
- BMesh *bm, BMElem **elems, const unsigned int n, const BMIterType itype, const char htype)
+static uint bm_mesh_elems_select_get_n__internal(
+ BMesh *bm, BMElem **elems, const uint n, const BMIterType itype, const char htype)
{
BMIter iter;
BMElem *ele;
- unsigned int i;
+ uint i;
BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
@@ -579,18 +668,18 @@ static unsigned int bm_mesh_elems_select_get_n__internal(
return i;
}
-static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totvertsel), BM_VERTS_OF_MESH, BM_VERT);
}
-static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n)
+static uint bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totedgesel), BM_EDGES_OF_MESH, BM_EDGE);
}
#if 0
-static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totfacesel), BM_FACES_OF_MESH, BM_FACE);
@@ -859,7 +948,7 @@ int getTransformOrientation_ex(const bContext *C,
}
}
else {
- const bool use_handle = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) != 0;
+ const bool use_handle = v3d->overlay.handle_display != CURVE_HANDLE_NONE;
for (nu = nurbs->first; nu; nu = nu->next) {
/* only bezier has a normal */
@@ -1071,10 +1160,9 @@ int getTransformOrientation_ex(const bContext *C,
ok = true;
}
else {
- int totsel;
-
- totsel = count_bone_select(arm, &arm->bonebase, true);
- if (totsel) {
+ int transformed_len;
+ transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true);
+ if (transformed_len) {
/* use channels to get stats */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 86e99c986f8..82602e7d828 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -44,8 +44,8 @@
#include "GPU_immediate.h"
#include "GPU_state.h"
-#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -56,6 +56,7 @@
#include "WM_types.h"
+#include "ED_gizmo_library.h"
#include "ED_image.h"
#include "ED_markers.h"
#include "ED_node.h"
@@ -158,7 +159,7 @@ static bool doForceIncrementSnap(const TransInfo *t)
void drawSnapping(const struct bContext *C, TransInfo *t)
{
- unsigned char col[4], selectedCol[4], activeCol[4];
+ uchar col[4], selectedCol[4], activeCol[4];
if (!activeSnap(t)) {
return;
@@ -178,99 +179,53 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
(t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR);
if (draw_target || validSnap(t)) {
- TransSnapPoint *p;
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- float imat[4][4];
- float size;
+ const float *loc_cur = NULL;
+ const float *loc_prev = NULL;
+ const float *normal = NULL;
GPU_depth_test(false);
- size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (!BLI_listbase_is_empty(&t->tsnap.points)) {
+ /* Draw snap points. */
- invert_m4_m4(imat, rv3d->viewmat);
+ float size = 2.0f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+ float view_inv[4][4];
+ copy_m4_m4(view_inv, rv3d->viewinv);
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- for (p = t->tsnap.points.first; p; p = p->next) {
- if (p == t->tsnap.selectedPoint) {
- immUniformColor4ubv(selectedCol);
- }
- else {
- immUniformColor4ubv(col);
+ 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);
}
- imm_drawcircball(p->co, ED_view3d_pixel_size(rv3d, p->co) * size * 0.75f, imat, pos);
- }
-
- if (t->tsnap.status & POINT_INIT) {
- immUniformColor4ubv(activeCol);
-
- imm_drawcircball(
- t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat, pos);
+ immUnbindProgram();
}
/* draw normal if needed */
if (usingSnappingNormal(t) && validSnappingNormal(t)) {
- immUniformColor4ubv(activeCol);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3f(pos, t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
- immVertex3f(pos,
- t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
- t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
- t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
- immEnd();
+ normal = t->tsnap.snapNormal;
}
if (draw_target) {
- /* Draw snapTarget */
- float targ_co[3], vx[3], vy[3], v1[3], v2[3], v3[3], v4[4];
- copy_v3_v3(targ_co, t->tsnap.snapTarget);
- float px_size = 0.75f * size * ED_view3d_pixel_size(rv3d, targ_co);
-
- mul_v3_v3fl(vx, imat[0], px_size);
- mul_v3_v3fl(vy, imat[1], px_size);
-
- add_v3_v3v3(v1, vx, vy);
- sub_v3_v3v3(v2, vx, vy);
- negate_v3_v3(v3, v1);
- negate_v3_v3(v4, v2);
-
- add_v3_v3(v1, targ_co);
- add_v3_v3(v2, targ_co);
- add_v3_v3(v3, targ_co);
- add_v3_v3(v4, targ_co);
-
- immUniformColor4ubv(col);
- immBegin(GPU_PRIM_LINES, 4);
- immVertex3fv(pos, v3);
- immVertex3fv(pos, v1);
- immVertex3fv(pos, v4);
- immVertex3fv(pos, v2);
- immEnd();
-
- if (t->tsnap.snapElem & SCE_SNAP_MODE_EDGE_PERPENDICULAR) {
- immUnbindProgram();
-
- 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]);
- immUniform1f("dash_width", 6.0f * U.pixelsize);
- immUniform1f("dash_factor", 1.0f / 4.0f);
- immUniformColor4ubv(col);
+ loc_prev = t->tsnap.snapTarget;
+ }
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(pos, targ_co);
- immVertex3fv(pos, t->tsnap.snapPoint);
- immEnd();
- }
+ if (validSnap(t)) {
+ loc_cur = t->tsnap.snapPoint;
}
- immUnbindProgram();
+ ED_gizmotypes_snap_3d_draw_util(
+ rv3d, loc_prev, loc_cur, normal, col, activeCol, t->tsnap.snapElem);
GPU_depth_test(true);
}
@@ -351,11 +306,6 @@ void applyProject(TransInfo *t)
for (i = 0; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], no[3];
float mval_fl[2];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -462,11 +412,6 @@ void applyGridAbsolute(TransInfo *t)
for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
float iloc[3], loc[3], tvec[3];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
if (td->flag & TD_SKIP) {
continue;
}
@@ -590,7 +535,6 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data))
static void initSnappingMode(TransInfo *t)
{
- Main *bmain = CTX_data_main(t->context);
ToolSettings *ts = t->settings;
/* All obedit types will match. */
const int obedit_type = t->data_container->obedit ? t->data_container->obedit->type : -1;
@@ -687,7 +631,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- bmain, t->scene, 0, t->region, t->view);
+ t->scene, 0, t->region, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -1106,7 +1050,6 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- Image *ima = ED_space_image(t->sa->spacedata.first);
float co[2];
UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
@@ -1117,7 +1060,7 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
float dist_sq = FLT_MAX;
if (ED_uvedit_nearest_uv_multi(
- t->scene, ima, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
+ t->scene, objects, objects_len, co, &dist_sq, t->tsnap.snapPoint)) {
t->tsnap.snapPoint[0] *= t->aspect[0];
t->tsnap.snapPoint[1] *= t->aspect[1];
@@ -1581,7 +1524,7 @@ bool snapNodesTransform(
TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
{
return snapNodes(t->settings,
- t->sa->spacedata.first,
+ t->area->spacedata.first,
t->region,
mval,
t->tsnap.modeSelect,
@@ -1716,7 +1659,7 @@ static void applyGridIncrement(
if (t->spacetype == SPACE_GRAPH) {
View2D *v2d = &t->region->v2d;
Scene *scene = t->scene;
- SpaceGraph *sipo = t->sa->spacedata.first;
+ SpaceGraph *sipo = t->area->spacedata.first;
asp_local[0] = UI_view2d_grid_resolution_x__frames_or_seconds(
v2d, scene, sipo->flag & SIPO_DRAWTIME);
asp_local[1] = UI_view2d_grid_resolution_y__values(v2d);
@@ -1750,8 +1693,8 @@ static void applyGridIncrement(
float local_axis[3];
float pos_on_axis[3];
- copy_v3_v3(local_axis, t->con.mtx[i]);
- copy_v3_v3(pos_on_axis, t->con.mtx[i]);
+ copy_v3_v3(local_axis, t->spacemtx[i]);
+ copy_v3_v3(pos_on_axis, t->spacemtx[i]);
/* amount of movement on axis from initial pos */
mul_v3_fl(pos_on_axis, val[i]);
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index f55c73fd15e..c30b8d59dc0 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -38,10 +38,10 @@
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "BKE_anim.h" /* for duplis */
#include "BKE_armature.h"
#include "BKE_bvhutils.h"
#include "BKE_curve.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_main.h"
@@ -104,13 +104,12 @@ typedef struct SnapObjectData {
/* SNAP_EDIT_MESH */
BVHTreeFromEditMesh treedata_editmesh;
float min[3], max[3];
- struct LinkNode **bvh_cache_p;
+ struct Mesh_Runtime *mesh_runtime;
};
};
} SnapObjectData;
struct SnapObjectContext {
- Main *bmain;
Scene *scene;
int flag;
@@ -145,6 +144,17 @@ struct SnapObjectContext {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em)
+{
+ return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Snap Object Data
* \{ */
@@ -245,17 +255,17 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
return sod;
}
-static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob)
+static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (em->mesh_eval_final) {
- return &em->mesh_eval_final->runtime.bvh_cache;
+ return &em->mesh_eval_final->runtime;
}
if (em->mesh_eval_cage) {
- return &em->mesh_eval_cage->runtime.bvh_cache;
+ return &em->mesh_eval_cage->runtime;
}
- return &((Mesh *)ob->data)->runtime.bvh_cache;
+ return &((Mesh *)ob->data)->runtime;
}
static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
@@ -292,23 +302,23 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
clear_cache = true;
init = true;
}
- else if (sod->bvh_cache_p) {
- if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) {
+ else if (sod->mesh_runtime) {
+ if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
clear_cache = true;
init = true;
}
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
- !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) {
+ !bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
@@ -347,7 +357,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
bm_mesh_minmax(em->bm, sod->min, sod->max);
}
- sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
}
return sod;
@@ -360,7 +370,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
- bool is_obedit,
+ bool use_obedit,
bool use_backface_culling,
Object *ob,
float obmat[4][4],
@@ -447,7 +457,7 @@ struct RayCastAll_Data {
float local_scale;
Object *ob;
- unsigned int ob_uuid;
+ uint ob_uuid;
/* output data */
ListBase *hit_list;
@@ -460,7 +470,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
int index,
Object *ob,
const float obmat[4][4],
- unsigned int ob_uuid)
+ uint ob_uuid)
{
struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
@@ -586,7 +596,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
Object *ob,
Mesh *me,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_hide,
bool use_backface_culling,
/* read/write args */
@@ -761,7 +771,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
Object *ob,
BMEditMesh *em,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_backface_culling,
/* read/write args */
float *ray_depth,
@@ -836,14 +846,19 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_looptri_ex(
- treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL);
+ treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL, NULL);
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->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(treedata,
+ em,
+ 4,
+ BVHTREE_FROM_EM_LOOPTRI,
+ &sod->mesh_runtime->bvh_cache,
+ sod->mesh_runtime->eval_mutex);
}
if (treedata->tree == NULL) {
@@ -921,41 +936,52 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
return retval;
}
+struct RaycastObjUserData {
+ const float *ray_start;
+ const float *ray_dir;
+ uint ob_index;
+ /* read/write args */
+ float *ray_depth;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ ListBase *r_hit_list;
+ bool use_occlusion_test;
+ bool ret;
+};
+
/**
* \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static bool raycastObj(SnapObjectContext *sctx,
- const float ray_start[3],
- const float ray_dir[3],
- Object *ob,
- const float obmat[4][4],
- const unsigned int ob_index,
- bool use_obedit,
- bool use_occlusion_test,
- bool use_backface_culling,
- /* read/write args */
- float *ray_depth,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4],
- ListBase *r_hit_list)
+static void raycast_obj_fn(SnapObjectContext *sctx,
+ bool use_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
+ struct RaycastObjUserData *dt = data;
+ const uint ob_index = dt->ob_index++;
+ bool use_occlusion_test = dt->use_occlusion_test;
+ /* read/write args */
+ float *ray_depth = dt->ray_depth;
+
bool retval = false;
if (use_occlusion_test) {
if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
/* Use of occlude geometry in editing mode disabled. */
- return false;
+ return;
}
if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) {
/* Do not hit objects that are in wire or bounding box
* display mode. */
- return false;
+ return;
}
}
@@ -964,22 +990,22 @@ static bool raycastObj(SnapObjectContext *sctx,
Mesh *me = ob->data;
bool use_hide = false;
if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit) {
+ if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
retval = raycastEditMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
em_orig,
obmat,
ob_index,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
else {
@@ -991,8 +1017,8 @@ static bool raycastObj(SnapObjectContext *sctx,
}
}
retval = raycastMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
me,
obmat,
@@ -1000,10 +1026,10 @@ static bool raycastObj(SnapObjectContext *sctx,
use_hide,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
case OB_CURVE:
@@ -1012,8 +1038,8 @@ static bool raycastObj(SnapObjectContext *sctx,
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if (mesh_eval) {
retval = raycastMesh(sctx,
- ray_start,
- ray_dir,
+ dt->ray_start,
+ dt->ray_dir,
ob,
mesh_eval,
obmat,
@@ -1021,70 +1047,24 @@ static bool raycastObj(SnapObjectContext *sctx,
false,
use_backface_culling,
ray_depth,
- r_loc,
- r_no,
- r_index,
- r_hit_list);
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
break;
}
}
}
if (retval) {
- if (r_ob) {
- *r_ob = ob;
+ if (dt->r_ob) {
+ *dt->r_ob = ob;
}
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
}
- return true;
+ dt->ret = true;
}
-
- return false;
-}
-
-struct RaycastObjUserData {
- const float *ray_start;
- const float *ray_dir;
- unsigned int ob_index;
- /* read/write args */
- float *ray_depth;
- /* return args */
- float *r_loc;
- float *r_no;
- int *r_index;
- Object **r_ob;
- float (*r_obmat)[4];
- ListBase *r_hit_list;
- bool use_occlusion_test;
- bool ret;
-};
-
-static void raycast_obj_cb(SnapObjectContext *sctx,
- bool use_obedit,
- bool use_backface_culling,
- Object *ob,
- float obmat[4][4],
- void *data)
-{
- struct RaycastObjUserData *dt = data;
-
- dt->ret |= raycastObj(sctx,
- dt->ray_start,
- dt->ray_dir,
- ob,
- obmat,
- dt->ob_index++,
- use_obedit,
- dt->use_occlusion_test,
- use_backface_culling,
- dt->ray_depth,
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_ob,
- dt->r_obmat,
- dt->r_hit_list);
}
/**
@@ -1145,7 +1125,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, depsgraph, params, raycast_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, raycast_obj_fn, &data);
return data.ret;
}
@@ -1227,7 +1207,7 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree
const MLoopTri *lt = &data->looptri[index];
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
const MEdge *ed = &medge[mloop[lt->tri[j]].e];
- unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
+ uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) {
// printf("real edge found\n");
v_index[j] = mloop[lt->tri[j]].e;
@@ -1707,8 +1687,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
&nearest.dist_sq,
nearest.co)) {
nearest.index = vindex[v_id];
- nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata);
elem = SCE_SNAP_MODE_VERTEX;
+ if (r_no) {
+ float imat[4][4];
+ invert_m4_m4(imat, obmat);
+ nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata);
+ mul_transposed_mat3_m4_v3(imat, r_no);
+ normalize_v3(r_no);
+ }
}
}
}
@@ -1726,10 +1712,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
vmid,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_MIDPOINT;
}
@@ -1757,11 +1739,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
v_near,
&nearest.dist_sq,
nearest.co)) {
- float v_nor[2][3];
- nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata);
- nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata);
- mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]);
-
nearest.index = *r_index;
elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR;
}
@@ -1778,15 +1755,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
mul_m4_v3(obmat, r_loc);
}
- if (r_no) {
- float imat[4][4];
- invert_m4_m4(imat, obmat);
-
- copy_v3_v3(r_no, nearest.no);
- mul_transposed_mat3_m4_v3(imat, r_no);
- normalize_v3(r_no);
- }
-
*r_index = nearest.index;
}
@@ -1838,7 +1806,7 @@ static short snapArmature(SnapData *snapdata,
bArmature *arm = ob->data;
if (arm->edbo) {
- for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
@@ -1881,7 +1849,7 @@ static short snapArmature(SnapData *snapdata,
}
}
else if (ob->pose && ob->pose->chanbase.first) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
@@ -2537,11 +2505,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_verts_ex(
- &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(verts_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(&treedata,
+ em,
+ 2,
+ BVHTREE_FROM_EM_VERTS,
+ &sod->mesh_runtime->bvh_cache,
+ (ThreadMutex *)sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
sod->cached[0] = treedata.cached;
@@ -2564,11 +2537,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_edges_ex(
- &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(edges_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p);
+ BKE_bvhtree_from_editmesh_get(&treedata,
+ em,
+ 2,
+ BVHTREE_FROM_EM_EDGES,
+ &sod->mesh_runtime->bvh_cache,
+ sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
sod->cached[1] = treedata.cached;
@@ -2657,45 +2635,51 @@ static short snapEditMesh(SnapObjectContext *sctx,
return 0;
}
+struct SnapObjUserData {
+ SnapData *snapdata;
+ /* read/write args */
+ float *dist_px;
+ /* return args */
+ float *r_loc;
+ float *r_no;
+ int *r_index;
+ Object **r_ob;
+ float (*r_obmat)[4];
+ short ret;
+};
+
/**
* \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping;
*
* \note Duplicate args here are documented at #snapObjectsRay
*/
-static short snapObject(SnapObjectContext *sctx,
- SnapData *snapdata,
- Object *ob,
- float obmat[4][4],
+static void sanp_obj_fn(SnapObjectContext *sctx,
bool use_obedit,
bool use_backface_culling,
- /* read/write args */
- float *dist_px,
- /* return args */
- float r_loc[3],
- float r_no[3],
- int *r_index,
- Object **r_ob,
- float r_obmat[4][4])
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
+ struct SnapObjUserData *dt = data;
short retval = 0;
switch (ob->type) {
case OB_MESH: {
Mesh *me = ob->data;
if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit) {
+ if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
/* Operators only update the editmesh looptris of the original mesh. */
BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
retval = snapEditMesh(sctx,
- snapdata,
+ dt->snapdata,
ob,
em_orig,
obmat,
use_backface_culling,
- dist_px,
- r_loc,
- r_no,
- r_index);
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
else {
@@ -2707,99 +2691,66 @@ static short snapObject(SnapObjectContext *sctx,
}
else if (ob->dt == OB_BOUNDBOX) {
/* Do not snap to objects that are in bounding box display mode */
- return 0;
+ return;
}
- retval = snapMesh(
- sctx, snapdata, ob, me, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
+ retval = snapMesh(sctx,
+ dt->snapdata,
+ ob,
+ me,
+ obmat,
+ use_backface_culling,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break;
}
case OB_ARMATURE:
- retval = snapArmature(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index);
+ retval = snapArmature(
+ dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(snapdata, ob, obmat, use_obedit, dist_px, r_loc, r_no, r_index);
+ retval = snapCurve(
+ dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
if (mesh_eval) {
retval |= snapMesh(sctx,
- snapdata,
+ dt->snapdata,
ob,
mesh_eval,
obmat,
use_backface_culling,
- dist_px,
- r_loc,
- r_no,
- r_index);
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
}
break;
}
case OB_EMPTY:
- retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_GPENCIL:
- retval = snapEmpty(snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEmpty(dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CAMERA:
- retval = snapCamera(sctx, snapdata, ob, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapCamera(
+ sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (retval) {
- if (r_ob) {
- *r_ob = ob;
+ if (dt->r_ob) {
+ *dt->r_ob = ob;
}
- if (r_obmat) {
- copy_m4_m4(r_obmat, obmat);
+ if (dt->r_obmat) {
+ copy_m4_m4(dt->r_obmat, obmat);
}
- return retval;
- }
-
- return 0;
-}
-
-struct SnapObjUserData {
- SnapData *snapdata;
- /* read/write args */
- float *dist_px;
- /* return args */
- float *r_loc;
- float *r_no;
- int *r_index;
- Object **r_ob;
- float (*r_obmat)[4];
- short ret;
-};
-
-static void sanp_obj_cb(SnapObjectContext *sctx,
- bool is_obedit,
- bool use_backface_culling,
- Object *ob,
- float obmat[4][4],
- void *data)
-{
- struct SnapObjUserData *dt = data;
-
- short elem = snapObject(sctx,
- dt->snapdata,
- ob,
- obmat,
- is_obedit,
- use_backface_culling,
- /* read/write args */
- dt->dist_px,
- /* return args */
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_ob,
- dt->r_obmat);
-
- if (elem) {
- dt->ret = elem;
+ dt->ret = retval;
}
}
@@ -2852,7 +2803,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, depsgraph, params, sanp_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, sanp_obj_fn, &data);
return data.ret;
}
@@ -2863,13 +2814,12 @@ static short snapObjectsRay(SnapObjectContext *sctx,
/** \name Public Object Snapping API
* \{ */
-SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag)
+SnapObjectContext *ED_transform_snap_object_context_create(Scene *scene, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
sctx->flag = flag;
- sctx->bmain = bmain;
sctx->scene = scene;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
@@ -2880,14 +2830,13 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *s
return sctx;
}
-SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain,
- Scene *scene,
+SnapObjectContext *ED_transform_snap_object_context_create_view3d(Scene *scene,
int flag,
/* extra args for view3d */
const ARegion *region,
const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(scene, flag);
sctx->use_v3d = true;
sctx->v3d_data.region = region;
@@ -3049,7 +2998,7 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
static short transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to_flag,
+ const ushort snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3225,7 +3174,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3265,7 +3214,7 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
*/
bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
Depsgraph *depsgraph,
- const unsigned short snap_to,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 123fd5f35da..6633e1c427c 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -79,15 +79,26 @@ static CLG_LogRef LOG = {"ed.undo"};
void ED_undo_push(bContext *C, const char *str)
{
CLOG_INFO(&LOG, 1, "name='%s'", str);
+ WM_file_tag_modified();
- const int steps = U.undosteps;
-
+ wmWindowManager *wm = CTX_wm_manager(C);
+ int steps = U.undosteps;
+
+ /* Ensure steps that have been initialized are always pushed,
+ * even when undo steps are zero.
+ *
+ * Note that some modes (paint, sculpt) initialize an undo step before an action runs,
+ * then accumulate changes there, or restore data from it in the case of 2D painting.
+ *
+ * For this reason we need to handle the undo step even when undo steps is set to zero.
+ */
+ if ((steps <= 0) && wm->undo_stack->step_init != NULL) {
+ steps = 1;
+ }
if (steps <= 0) {
return;
}
- wmWindowManager *wm = CTX_wm_manager(C);
-
/* Only apply limit if this is the last undo step. */
if (wm->undo_stack->step_active && (wm->undo_stack->step_active->next == NULL)) {
BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, steps - 1, 0);
@@ -97,14 +108,12 @@ void ED_undo_push(bContext *C, const char *str)
if (U.undomemory != 0) {
const size_t memory_limit = (size_t)U.undomemory * 1024 * 1024;
- BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit);
+ BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, -1, memory_limit);
}
if (CLOG_CHECK(&LOG, 1)) {
BKE_undosys_print(wm->undo_stack);
}
-
- WM_file_tag_modified();
}
/**
@@ -119,7 +128,7 @@ static int ed_undo_step_impl(
CLOG_INFO(&LOG, 1, "name='%s', step=%d", undoname, step);
wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* undo during jobs are running can easily lead to freeing data using by jobs,
* or they can just lead to freezing job in some other cases */
@@ -138,7 +147,7 @@ static int ed_undo_step_impl(
if (ED_gpencil_session_active()) {
return ED_undo_gpencil_step(C, step, undoname);
}
- if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->type == OB_GPENCIL)) {
ED_gpencil_toggle_brush_cursor(C, false, NULL);
@@ -195,7 +204,7 @@ static int ed_undo_step_impl(
}
/* Set special modes for grease pencil */
- if (sa && (sa->spacetype == SPACE_VIEW3D)) {
+ if (area && (area->spacetype == SPACE_VIEW3D)) {
Object *obact = CTX_data_active_object(C);
if (obact && (obact->type == OB_GPENCIL)) {
/* set cursor */
@@ -558,11 +567,11 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
struct Scene *scene = CTX_data_scene(C);
/* keep in sync with logic in view3d_panel_operator_redo() */
- ARegion *ar_orig = CTX_wm_region(C);
- ARegion *ar_win = BKE_area_find_region_active_win(CTX_wm_area(C));
+ ARegion *region_orig = CTX_wm_region(C);
+ ARegion *region_win = BKE_area_find_region_active_win(CTX_wm_area(C));
- if (ar_win) {
- CTX_wm_region_set(C, ar_win);
+ if (region_win) {
+ CTX_wm_region_set(C, region_win);
}
if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) &&
@@ -585,9 +594,9 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
if (op->type->check) {
if (op->type->check(C, op)) {
/* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu) {
- ED_region_tag_refresh_ui(ar_menu);
+ ARegion *region_menu = CTX_wm_menu(C);
+ if (region_menu) {
+ ED_region_tag_refresh_ui(region_menu);
}
}
}
@@ -610,7 +619,7 @@ int ED_undo_operator_repeat(bContext *C, wmOperator *op)
}
/* set region back */
- CTX_wm_region_set(C, ar_orig);
+ CTX_wm_region_set(C, region_orig);
}
else {
CLOG_WARN(&LOG, "called with NULL 'op'");
@@ -816,7 +825,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
{
const short object_type = obact->type;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -825,7 +834,7 @@ static int undo_editmode_objects_from_view_layer_prepare(ViewLayer *view_layer,
}
int len = 0;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
if (ob == obact) {
@@ -852,7 +861,7 @@ Object **ED_undo_editmode_objects_from_view_layer(ViewLayer *view_layer, uint *r
const short object_type = obact->type;
int i = 0;
Object **objects = MEM_malloc_arrayN(len, sizeof(*objects), __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
@@ -881,7 +890,7 @@ Base **ED_undo_editmode_bases_from_view_layer(ViewLayer *view_layer, uint *r_len
const short object_type = obact->type;
int i = 0;
Base **base_array = MEM_malloc_arrayN(len, sizeof(*base_array), __func__);
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if ((ob->type == object_type) && (ob->mode & OB_MODE_EDIT)) {
ID *id = ob->data;
diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c
index 086aa6c4c9d..2df26abe8b3 100644
--- a/source/blender/editors/undo/memfile_undo.c
+++ b/source/blender/editors/undo/memfile_undo.c
@@ -25,14 +25,17 @@
#include "BLI_ghash.h"
+#include "DNA_node_types.h"
#include "DNA_object_enums.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
#include "BKE_undo_system.h"
@@ -106,7 +109,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
ID *id_self = cb_data->id_self;
ID **id_pointer = cb_data->id_pointer;
BLI_assert((id_self->tag & LIB_TAG_UNDO_OLD_ID_REUSED) != 0);
- Main *bmain = cb_data->user_data;
ID *id = *id_pointer;
if (id != NULL && id->lib == NULL && (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) == 0) {
@@ -129,9 +131,6 @@ static int memfile_undosys_step_id_reused_cb(LibraryIDLinkCallbackData *cb_data)
}
}
- /* In case an old, re-used ID is using a newly read data-block (i.e. one of its ID pointers got
- * updated), we have to tell the depsgraph about it. */
- DEG_id_tag_update_ex(bmain, id_self, ID_RECALC_COPY_ON_WRITE);
return do_stop_iter ? IDWALK_RET_STOP_ITER : IDWALK_RET_NOP;
}
@@ -148,7 +147,7 @@ static void memfile_undosys_step_decode(struct bContext *C,
bool use_old_bmain_data = true;
- if (!U.experimental.use_undo_speedup) {
+ if (USER_EXPERIMENTAL_TEST(&U, use_undo_legacy)) {
use_old_bmain_data = false;
}
else if (undo_direction > 0) {
@@ -217,12 +216,37 @@ static void memfile_undosys_step_decode(struct bContext *C,
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_UNDO_OLD_ID_REUSED) {
BKE_library_foreach_ID_link(
- bmain, id, memfile_undosys_step_id_reused_cb, bmain, IDWALK_READONLY);
+ bmain, id, memfile_undosys_step_id_reused_cb, NULL, IDWALK_READONLY);
+ }
+
+ /* Tag depsgraph to update data-block for changes that happened between the
+ * current and the target state, see direct_link_id_restore_recalc(). */
+ if (id->recalc) {
+ DEG_id_tag_update_ex(bmain, id, id->recalc);
}
}
FOREACH_MAIN_ID_END;
- BKE_main_id_tag_all(bmain, LIB_TAG_UNDO_OLD_ID_REUSED, false);
+ FOREACH_MAIN_ID_BEGIN (bmain, id) {
+ /* Clear temporary tag. */
+ id->tag &= ~LIB_TAG_UNDO_OLD_ID_REUSED;
+
+ /* We only start accumulating from this point, any tags set up to here
+ * are already part of the current undo state. This is done in a second
+ * loop because DEG_id_tag_update may set tags on other datablocks. */
+ id->recalc_after_undo_push = 0;
+ bNodeTree *nodetree = ntreeFromID(id);
+ if (nodetree != NULL) {
+ nodetree->id.recalc_after_undo_push = 0;
+ }
+ if (GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ if (scene->master_collection != NULL) {
+ scene->master_collection->id.recalc_after_undo_push = 0;
+ }
+ }
+ }
+ FOREACH_MAIN_ID_END;
}
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, CTX_data_scene(C));
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 987327eefc1..17a90d10ca7 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -17,6 +17,7 @@
set(INC
../include
+ ../space_sequencer
../../blenkernel
../../blenlib
../../blentranslation
@@ -39,6 +40,7 @@ set(INC_SYS
set(SRC
ed_transverts.c
ed_util.c
+ ed_util_imbuf.c
gizmo_utils.c
numinput.c
select_utils.c
@@ -91,6 +93,7 @@ set(SRC
../include/ED_undo.h
../include/ED_userpref.h
../include/ED_util.h
+ ../include/ED_util_imbuf.h
../include/ED_uvedit.h
../include/ED_view3d.h
../include/UI_icons.h
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 67a62473dc0..1c56ad878e2 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -111,7 +111,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit)
}
BKE_nurb_test_2d(nu);
- BKE_nurb_handles_test(nu, true); /* test for bezier too */
+ BKE_nurb_handles_test(nu, true, false); /* test for bezier too */
nu = nu->next;
}
}
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index fa28d9c2d6d..af387e4f7c2 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -35,6 +35,7 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@@ -82,7 +83,7 @@
void ED_editors_init_for_undo(Main *bmain)
{
wmWindowManager *wm = bmain->wm.first;
- for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Base *base = BASACT(view_layer);
if (base != NULL) {
@@ -152,10 +153,10 @@ void ED_editors_init(bContext *C)
ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, true, reports);
}
else if (mode == OB_MODE_VERTEX_PAINT) {
- ED_object_vpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_vpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
else if (mode == OB_MODE_WEIGHT_PAINT) {
- ED_object_wpaintmode_enter_ex(bmain, depsgraph, wm, scene, ob);
+ ED_object_wpaintmode_enter_ex(bmain, depsgraph, scene, ob);
}
else {
BLI_assert(0);
@@ -173,7 +174,7 @@ void ED_editors_init(bContext *C)
else {
/* TODO(campbell): avoid operator calls. */
if (obact == ob) {
- ED_object_mode_toggle(C, mode);
+ ED_object_mode_set(C, mode);
}
}
}
@@ -224,8 +225,8 @@ void ED_editors_exit(Main *bmain, bool do_undo_system)
}
/* global in meshtools... */
- ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e');
- ED_mesh_mirror_topo_table(NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(NULL);
+ ED_mesh_mirror_topo_table_end(NULL);
}
bool ED_editors_flush_edits_for_object_ex(Main *bmain,
@@ -472,12 +473,12 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_
*
* \param new_id: may be NULL to unlink \a old_id.
*/
-void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id)
+void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id)
{
SpaceType *st = BKE_spacetype_from_id(sl->spacetype);
if (st && st->id_remap) {
- st->id_remap(sa, sl, old_id, new_id);
+ st->id_remap(area, sl, old_id, new_id);
}
}
diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c
new file mode 100644
index 00000000000..132a63a8249
--- /dev/null
+++ b/source/blender/editors/util/ed_util_imbuf.c
@@ -0,0 +1,571 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edutil
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_rect.h"
+
+#include "BKE_colortools.h"
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_sequencer.h"
+
+#include "ED_image.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "GPU_immediate.h"
+#include "GPU_state.h"
+
+#include "IMB_colormanagement.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "sequencer_intern.h"
+
+/* Own define. */
+#include "ED_util_imbuf.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample Struct (Operator Custom Data)
+ * \{ */
+
+typedef struct ImageSampleInfo {
+ ARegionType *art;
+ void *draw_handle;
+ int x, y;
+ int channels;
+
+ int width, height;
+ int sample_size;
+
+ unsigned char col[4];
+ float colf[4];
+ float linearcol[4];
+ int z;
+ float zf;
+
+ unsigned char *colp;
+ const float *colfp;
+ int *zp;
+ float *zfp;
+
+ bool draw;
+ bool color_manage;
+ int use_default_view;
+} ImageSampleInfo;
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample
+ * \{ */
+
+static void image_sample_pixel_color_ubyte(const ImBuf *ibuf,
+ const int coord[2],
+ uchar r_col[4],
+ float r_col_linear[4])
+{
+ const uchar *cp = (unsigned char *)(ibuf->rect + coord[1] * ibuf->x + coord[0]);
+ copy_v4_v4_uchar(r_col, cp);
+ rgba_uchar_to_float(r_col_linear, r_col);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(r_col_linear, false, ibuf->rect_colorspace);
+}
+
+static void image_sample_pixel_color_float(ImBuf *ibuf, const int coord[2], float r_col[4])
+{
+ const float *cp = ibuf->rect_float + (ibuf->channels) * (coord[1] * ibuf->x + coord[0]);
+ copy_v4_v4(r_col, cp);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Region Sample
+ * \{ */
+
+static void image_sample_rect_color_ubyte(const ImBuf *ibuf,
+ const rcti *rect,
+ uchar r_col[4],
+ float r_col_linear[4])
+{
+ uint col_accum_ub[4] = {0, 0, 0, 0};
+ zero_v4(r_col_linear);
+ int col_tot = 0;
+ int coord[2];
+ for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
+ for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
+ float col_temp_fl[4];
+ uchar col_temp_ub[4];
+ image_sample_pixel_color_ubyte(ibuf, coord, col_temp_ub, col_temp_fl);
+ add_v4_v4(r_col_linear, col_temp_fl);
+ col_accum_ub[0] += (uint)col_temp_ub[0];
+ col_accum_ub[1] += (uint)col_temp_ub[1];
+ col_accum_ub[2] += (uint)col_temp_ub[2];
+ col_accum_ub[3] += (uint)col_temp_ub[3];
+ col_tot += 1;
+ }
+ }
+ mul_v4_fl(r_col_linear, 1.0 / (float)col_tot);
+
+ r_col[0] = MIN2(col_accum_ub[0] / col_tot, 255);
+ r_col[1] = MIN2(col_accum_ub[1] / col_tot, 255);
+ r_col[2] = MIN2(col_accum_ub[2] / col_tot, 255);
+ r_col[3] = MIN2(col_accum_ub[3] / col_tot, 255);
+}
+
+static void image_sample_rect_color_float(ImBuf *ibuf, const rcti *rect, float r_col[4])
+{
+ zero_v4(r_col);
+ int col_tot = 0;
+ int coord[2];
+ for (coord[0] = rect->xmin; coord[0] <= rect->xmax; coord[0]++) {
+ for (coord[1] = rect->ymin; coord[1] <= rect->ymax; coord[1]++) {
+ float col_temp_fl[4];
+ image_sample_pixel_color_float(ibuf, coord, col_temp_fl);
+ add_v4_v4(r_col, col_temp_fl);
+ col_tot += 1;
+ }
+ }
+ mul_v4_fl(r_col, 1.0 / (float)col_tot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample (Internal Utilities)
+ * \{ */
+
+static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *region = CTX_wm_region(C);
+ Image *image = ED_space_image(sima);
+
+ float uv[2];
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &uv[0], &uv[1]);
+ int tile = BKE_image_get_tile_from_pos(sima->image, uv, uv, NULL);
+
+ void *lock;
+ ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, tile);
+ ImageSampleInfo *info = op->customdata;
+ Scene *scene = CTX_data_scene(C);
+ CurveMapping *curve_mapping = scene->view_settings.curve_mapping;
+
+ if (ibuf == NULL) {
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ info->draw = false;
+ return;
+ }
+
+ if (uv[0] >= 0.0f && uv[1] >= 0.0f && uv[0] < 1.0f && uv[1] < 1.0f) {
+ int x = (int)(uv[0] * ibuf->x), y = (int)(uv[1] * ibuf->y);
+
+ CLAMP(x, 0, ibuf->x - 1);
+ CLAMP(y, 0, ibuf->y - 1);
+
+ info->width = ibuf->x;
+ info->height = ibuf->y;
+ info->x = x;
+ info->y = y;
+
+ info->draw = true;
+ info->channels = ibuf->channels;
+
+ info->colp = NULL;
+ info->colfp = NULL;
+ info->zp = NULL;
+ info->zfp = NULL;
+
+ info->use_default_view = (image->flag & IMA_VIEW_AS_RENDER) ? false : true;
+
+ rcti sample_rect;
+ sample_rect.xmin = max_ii(0, x - info->sample_size / 2);
+ sample_rect.ymin = max_ii(0, y - info->sample_size / 2);
+ sample_rect.xmax = min_ii(ibuf->x, sample_rect.xmin + info->sample_size) - 1;
+ sample_rect.ymax = min_ii(ibuf->y, sample_rect.ymin + info->sample_size) - 1;
+
+ if (ibuf->rect) {
+ image_sample_rect_color_ubyte(ibuf, &sample_rect, info->col, info->linearcol);
+ rgba_uchar_to_float(info->colf, info->col);
+
+ info->colp = info->col;
+ info->colfp = info->colf;
+ info->color_manage = true;
+ }
+ if (ibuf->rect_float) {
+ image_sample_rect_color_float(ibuf, &sample_rect, info->colf);
+
+ if (ibuf->channels == 4) {
+ /* pass */
+ }
+ else if (ibuf->channels == 3) {
+ info->colf[3] = 1.0f;
+ }
+ else {
+ info->colf[1] = info->colf[0];
+ info->colf[2] = info->colf[0];
+ info->colf[3] = 1.0f;
+ }
+ info->colfp = info->colf;
+
+ copy_v4_v4(info->linearcol, info->colf);
+
+ info->color_manage = true;
+ }
+
+ if (ibuf->zbuf) {
+ /* TODO, blend depth (not urgent). */
+ info->z = ibuf->zbuf[y * ibuf->x + x];
+ info->zp = &info->z;
+ if (ibuf->zbuf == (int *)ibuf->rect) {
+ info->colp = NULL;
+ }
+ }
+ if (ibuf->zbuf_float) {
+ /* TODO, blend depth (not urgent). */
+ info->zf = ibuf->zbuf_float[y * ibuf->x + x];
+ info->zfp = &info->zf;
+ if (ibuf->zbuf_float == ibuf->rect_float) {
+ info->colfp = NULL;
+ }
+ }
+
+ if (curve_mapping && ibuf->channels == 4) {
+ /* we reuse this callback for set curves point operators */
+ if (RNA_struct_find_property(op->ptr, "point")) {
+ int point = RNA_enum_get(op->ptr, "point");
+
+ if (point == 1) {
+ BKE_curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
+ }
+ else if (point == 0) {
+ BKE_curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
+ }
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ }
+ }
+
+ // XXX node curve integration ..
+#if 0
+ {
+ ScrArea *sa, *cur = curarea;
+
+ node_curvemap_sample(fp); /* sends global to node editor */
+ for (sa = G.curscreen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_NODE) {
+ areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ }
+ }
+ node_curvemap_sample(NULL); /* clears global in node editor */
+ curarea = cur;
+ }
+#endif
+ }
+ else {
+ info->draw = 0;
+ }
+
+ ED_space_image_release_buffer(sima, ibuf, lock);
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ 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, depsgraph, scene, sseq, CFRA, 0, NULL);
+ ImageSampleInfo *info = op->customdata;
+ float fx, fy;
+
+ if (ibuf == NULL) {
+ IMB_freeImBuf(ibuf);
+ info->draw = 0;
+ return;
+ }
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &fx, &fy);
+
+ fx /= scene->r.xasp / scene->r.yasp;
+
+ fx += (float)scene->r.xsch / 2.0f;
+ fy += (float)scene->r.ysch / 2.0f;
+ fx *= (float)ibuf->x / (float)scene->r.xsch;
+ fy *= (float)ibuf->y / (float)scene->r.ysch;
+
+ if (fx >= 0.0f && fy >= 0.0f && fx < ibuf->x && fy < ibuf->y) {
+ const float *fp;
+ unsigned char *cp;
+ int x = (int)fx, y = (int)fy;
+
+ info->x = x;
+ info->y = y;
+ info->draw = 1;
+ info->channels = ibuf->channels;
+
+ info->colp = NULL;
+ info->colfp = NULL;
+
+ if (ibuf->rect) {
+ cp = (unsigned char *)(ibuf->rect + y * ibuf->x + x);
+
+ info->col[0] = cp[0];
+ info->col[1] = cp[1];
+ info->col[2] = cp[2];
+ info->col[3] = cp[3];
+ info->colp = info->col;
+
+ info->colf[0] = (float)cp[0] / 255.0f;
+ info->colf[1] = (float)cp[1] / 255.0f;
+ info->colf[2] = (float)cp[2] / 255.0f;
+ info->colf[3] = (float)cp[3] / 255.0f;
+ info->colfp = info->colf;
+
+ copy_v4_v4(info->linearcol, info->colf);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(
+ info->linearcol, false, ibuf->rect_colorspace);
+
+ info->color_manage = true;
+ }
+ if (ibuf->rect_float) {
+ fp = (ibuf->rect_float + (ibuf->channels) * (y * ibuf->x + x));
+
+ info->colf[0] = fp[0];
+ info->colf[1] = fp[1];
+ info->colf[2] = fp[2];
+ info->colf[3] = fp[3];
+ info->colfp = info->colf;
+
+ /* sequencer's image buffers are in non-linear space, need to make them linear */
+ copy_v4_v4(info->linearcol, info->colf);
+ BKE_sequencer_pixel_from_sequencer_space_v4(scene, info->linearcol);
+
+ info->color_manage = true;
+ }
+ }
+ else {
+ info->draw = 0;
+ }
+
+ IMB_freeImBuf(ibuf);
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ image_sample_apply(C, op, event);
+ }
+
+ if (sa && sa->spacetype == SPACE_SEQ) {
+ sequencer_sample_apply(C, op, event);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Pixel Sample (Public Operator Callback)
+ *
+ * Callbacks for the sample operator, used by sequencer and image spaces.
+ * \{ */
+
+void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info)
+{
+ ImageSampleInfo *info = arg_info;
+ if (!info->draw) {
+ return;
+ }
+
+ Scene *scene = CTX_data_scene(C);
+ ED_image_draw_info(scene,
+ region,
+ info->color_manage,
+ info->use_default_view,
+ info->channels,
+ info->x,
+ info->y,
+ info->colp,
+ info->colfp,
+ info->linearcol,
+ info->zp,
+ info->zfp);
+
+ if (info->sample_size > 1) {
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+
+ const wmWindow *win = CTX_wm_window(C);
+ const wmEvent *event = win->eventstate;
+
+ SpaceImage *sima = CTX_wm_space_image(C);
+ GPUVertFormat *format = immVertexFormat();
+ 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);
+ immUniformColor3fv(color);
+
+ /* TODO(campbell): lock to pixels. */
+ rctf sample_rect_fl;
+ BLI_rctf_init_pt_radius(
+ &sample_rect_fl,
+ (float[2]){event->x - region->winrct.xmin, event->y - region->winrct.ymin},
+ (float)(info->sample_size / 2.0f) * sima->zoom);
+
+ glEnable(GL_COLOR_LOGIC_OP);
+ glLogicOp(GL_XOR);
+ GPU_line_width(1.0f);
+ imm_draw_box_wire_2d(pos,
+ (float)sample_rect_fl.xmin,
+ (float)sample_rect_fl.ymin,
+ (float)sample_rect_fl.xmax,
+ (float)sample_rect_fl.ymax);
+ glDisable(GL_COLOR_LOGIC_OP);
+
+ immUnbindProgram();
+ }
+ }
+}
+
+void ED_imbuf_sample_exit(bContext *C, wmOperator *op)
+{
+ ImageSampleInfo *info = op->customdata;
+
+ ED_region_draw_cb_exit(info->art, info->draw_handle);
+ ED_area_tag_redraw(CTX_wm_area(C));
+ MEM_freeN(info);
+}
+
+int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ ARegion *region = CTX_wm_region(C);
+ ImageSampleInfo *info;
+
+ info = MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+
+ info->art = region->type;
+ info->draw_handle = ED_region_draw_cb_activate(
+ region->type, ED_imbuf_sample_draw, info, REGION_DRAW_POST_PIXEL);
+ info->sample_size = RNA_int_get(op->ptr, "size");
+ op->customdata = info;
+
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ if (region->regiontype == RGN_TYPE_WINDOW) {
+ if (event->mval[1] <= 16 && ED_space_image_show_cache(sima)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ if (!ED_space_image_has_buffer(sima)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ ed_imbuf_sample_apply(C, op, event);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+int ED_imbuf_sample_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ switch (event->type) {
+ case LEFTMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ ED_imbuf_sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ break;
+ case MOUSEMOVE:
+ ed_imbuf_sample_apply(C, op, event);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void ED_imbuf_sample_cancel(bContext *C, wmOperator *op)
+{
+ ED_imbuf_sample_exit(C, op);
+}
+
+bool ED_imbuf_sample_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa && sa->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ if (sima == NULL) {
+ return false;
+ }
+
+ Object *obedit = CTX_data_edit_object(C);
+ if (obedit) {
+ /* Disable when UV editing so it doesn't swallow all click events
+ * (use for setting cursor). */
+ if (ED_space_image_show_uvedit(sima, obedit)) {
+ return false;
+ }
+ }
+ else if (sima->mode != SI_MODE_VIEW) {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (sa && sa->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+
+ if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
+ return false;
+ }
+
+ return sseq && BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL;
+ }
+
+ return false;
+}
+
+/** \} */
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index 85a7cc94ae3..08e7b3a9a0a 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -59,9 +59,9 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
- WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, sa);
+ WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, area);
if (gzgt->users == 0) {
WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
}
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index d2ba9ab9591..b40b82c50fb 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -40,6 +40,7 @@ set(SRC
uvedit_draw.c
uvedit_ops.c
uvedit_parametrizer.c
+ uvedit_select.c
uvedit_smart_stitch.c
uvedit_unwrap_ops.c
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 887ce274680..edfbfd0cdc3 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -58,8 +58,7 @@
/* UV Utilities */
-static int uvedit_center(
- Scene *scene, Object **objects, uint objects_len, Image *ima, float center[2])
+static int uvedit_center(Scene *scene, Object **objects, uint objects_len, float center[2])
{
BMFace *f;
BMLoop *l;
@@ -75,7 +74,7 @@ static int uvedit_center(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -97,8 +96,10 @@ static int uvedit_center(
return tot;
}
-static void uvedit_translate(
- Scene *scene, Object **objects, uint objects_len, Image *ima, const float delta[2])
+static void uvedit_translate(Scene *scene,
+ Object **objects,
+ uint objects_len,
+ const float delta[2])
{
BMFace *f;
BMLoop *l;
@@ -112,7 +113,7 @@ static void uvedit_translate(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (!uvedit_face_visible_test(scene, f)) {
continue;
}
@@ -134,7 +135,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2];
int imx, imy, step, digits;
float width = 8 * UI_UNIT_X;
@@ -144,7 +144,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
ED_space_image_get_size(sima, &imx, &imy);
- if (uvedit_center(scene, objects, objects_len, ima, center)) {
+ if (uvedit_center(scene, objects, objects_len, center)) {
float range_xy[2][2] = {
{-10.0f, 10.0f},
{-10.0f, 10.0f},
@@ -212,7 +212,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
- Image *ima = sima->image;
float center[2], delta[2];
int imx, imy;
@@ -225,7 +224,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
CTX_data_view_layer(C), CTX_wm_view3d(C), &objects_len);
ED_space_image_get_size(sima, &imx, &imy);
- uvedit_center(scene, objects, objects_len, ima, center);
+ uvedit_center(scene, objects, objects_len, center);
if (sima->flag & SI_COORDFLOATS) {
delta[0] = uvedit_old_center[0] - center[0];
@@ -236,7 +235,7 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event)
delta[1] = uvedit_old_center[1] / imy - center[1];
}
- uvedit_translate(scene, objects, objects_len, ima, delta);
+ uvedit_translate(scene, objects, objects_len, delta);
WM_event_add_notifier(C, NC_IMAGE, sima->image);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -259,11 +258,11 @@ static bool image_panel_uv_poll(const bContext *C, PanelType *UNUSED(pt))
return ED_uvedit_test(obedit);
}
-static void image_panel_uv(const bContext *C, Panel *pa)
+static void image_panel_uv(const bContext *C, Panel *panel)
{
uiBlock *block;
- block = uiLayoutAbsoluteBlock(pa->layout);
+ block = uiLayoutAbsoluteBlock(panel->layout);
UI_block_func_handle_set(block, do_uvedit_vertex, NULL);
uvedit_vertex_buttons(C, block);
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index 1e576f6fea4..897e2f13774 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -39,6 +39,7 @@
#include "../../draw/intern/draw_cache_impl.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BKE_deform.h"
@@ -206,8 +207,10 @@ static void uvedit_get_batches(Object *ob,
else {
batches->faces = NULL;
}
-
- DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob, ob->data, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
/* after create_requested we can load the actual areas */
@@ -216,24 +219,46 @@ static void uvedit_get_batches(Object *ob,
}
}
-static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
+static void draw_uvs_shadow(SpaceImage *sima,
const Scene *scene,
Object *obedit,
Depsgraph *depsgraph)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit);
Mesh *me = ob_eval->data;
+ const float overlay_alpha = sima->uv_opacity;
float col[4];
UI_GetThemeColor4fv(TH_UV_SHADOW, col);
DRW_mesh_batch_cache_validate(me);
GPUBatch *edges = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false);
+
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
if (edges) {
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
+ col[3] = overlay_alpha;
GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(edges, "color", col);
GPU_batch_draw(edges);
+
+ if (sima->flag & SI_SMOOTH_UV) {
+ GPU_line_smooth(false);
+ GPU_blend(false);
+ }
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
}
@@ -251,7 +276,10 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra
DRW_mesh_batch_cache_validate(me);
GPUBatch *geom = DRW_mesh_batch_cache_get_uv_edges(me);
- DRW_mesh_batch_cache_create_requested(ob_eval, me, scene, false, false);
+ struct TaskGraph *task_graph = BLI_task_graph_create();
+ DRW_mesh_batch_cache_create_requested(task_graph, ob_eval, me, scene, false, false);
+ BLI_task_graph_work_and_wait(task_graph);
+ BLI_task_graph_free(task_graph);
GPU_batch_program_set_builtin(geom, GPU_SHADER_2D_UV_UNIFORM_COLOR);
GPU_batch_uniform_4fv(geom, "color", col);
@@ -265,6 +293,7 @@ static void draw_uvs_texpaint(const Scene *scene, Object *ob, Depsgraph *depsgra
bool prev_ma_match = (mpoly->mat_nr == (ob_eval->actcol - 1));
GPU_matrix_bind(geom->interface);
+ GPU_shader_set_srgb_uniform(geom->interface);
GPU_batch_bind(geom);
/* TODO(fclem): If drawcall count becomes a problem in the future
@@ -305,6 +334,7 @@ static void draw_uvs(SpaceImage *sima,
Object *ob_eval = batch->ob_eval;
const ToolSettings *ts = scene->toolsettings;
float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ const float overlay_alpha = sima->uv_opacity;
if (sima->flag & SI_DRAWSHADOW) {
bool is_cage_like_final_meshes = false;
@@ -345,7 +375,11 @@ static void draw_uvs(SpaceImage *sima,
UI_GetThemeColor4fv(TH_FACE, col1);
UI_GetThemeColor4fv(TH_FACE_SELECT, col2);
UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3);
- col3[3] *= 0.2; /* Simulate dithering */
+
+ col1[3] *= overlay_alpha;
+ col2[3] *= overlay_alpha;
+ col3[3] *= overlay_alpha;
+
GPU_batch_uniform_4fv(batch->faces, "faceColor", col1);
GPU_batch_uniform_4fv(batch->faces, "selectColor", col2);
GPU_batch_uniform_4fv(batch->faces, "activeColor", col3);
@@ -371,9 +405,16 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(true);
GPU_blend(true);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(true);
+ }
+
switch (sima->dt_uv) {
case SI_UVDT_DASH: {
- float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}};
+ float dash_colors[2][4] = {
+ {0.56f, 0.56f, 0.56f, overlay_alpha},
+ {0.07f, 0.07f, 0.07f, overlay_alpha},
+ };
float viewport_size[4];
GPU_viewport_size_get_f(viewport_size);
@@ -397,7 +438,8 @@ static void draw_uvs(SpaceImage *sima,
* instead of modifying the provoking vert. */
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
- UI_GetThemeColor4fv(TH_EDGE_SELECT, col2);
+ UI_GetThemeColor3fv(TH_EDGE_SELECT, col2);
+ col2[3] = overlay_alpha;
GPU_batch_program_set_builtin(
batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES);
@@ -405,18 +447,19 @@ static void draw_uvs(SpaceImage *sima,
if (sima->dt_uv == SI_UVDT_OUTLINE) {
/* Black Outline. */
GPU_line_width(3.0f);
- GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f);
- GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
+ GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha);
GPU_batch_draw(batch->edges);
- UI_GetThemeColor4fv(TH_WIRE_EDIT, col1);
+ UI_GetThemeColor3fv(TH_WIRE_EDIT, col1);
}
else if (sima->dt_uv == SI_UVDT_WHITE) {
- copy_v4_fl4(col1, 1.0f, 1.0f, 1.0f, 1.0f);
+ copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f);
}
else {
- copy_v4_fl4(col1, 0.0f, 0.0f, 0.0f, 1.0f);
+ copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f);
}
+ col1[3] = overlay_alpha;
/* Inner Line. Use depth test to insure selection is drawn on top. */
GPU_depth_test(true);
@@ -434,6 +477,9 @@ static void draw_uvs(SpaceImage *sima,
GPU_line_smooth(false);
GPU_blend(false);
}
+ else if (overlay_alpha < 1.0f) {
+ GPU_blend(false);
+ }
}
if (batch->verts || batch->facedots) {
UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2);
diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h
index 7bc6b048585..31384d6df17 100644
--- a/source/blender/editors/uvedit/uvedit_intern.h
+++ b/source/blender/editors/uvedit/uvedit_intern.h
@@ -57,13 +57,11 @@ typedef struct UvNearestHit {
}
bool uv_find_nearest_vert(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
const float penalty_dist,
struct UvNearestHit *hit_final);
bool uv_find_nearest_vert_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -71,24 +69,20 @@ bool uv_find_nearest_vert_multi(struct Scene *scene,
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_edge_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face(struct Scene *scene,
- struct Image *ima,
struct Object *obedit,
const float co[2],
struct UvNearestHit *hit_final);
bool uv_find_nearest_face_multi(struct Scene *scene,
- struct Image *ima,
struct Object **objects,
const uint objects_len,
const float co[2],
@@ -99,6 +93,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene,
void uvedit_live_unwrap_update(struct SpaceImage *sima,
struct Scene *scene,
struct Object *obedit);
+void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]);
/* operators */
@@ -113,4 +108,28 @@ void UV_OT_sphere_project(struct wmOperatorType *ot);
void UV_OT_unwrap(struct wmOperatorType *ot);
void UV_OT_stitch(struct wmOperatorType *ot);
+/* uvedit_select.c */
+
+bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit);
+bool uvedit_select_is_any_selected_multi(struct Scene *scene,
+ struct Object **objects,
+ const uint objects_len);
+const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene,
+ struct BMVert *eve,
+ const int cd_loop_uv_offset);
+
+void UV_OT_select_all(struct wmOperatorType *ot);
+void UV_OT_select(struct wmOperatorType *ot);
+void UV_OT_select_loop(struct wmOperatorType *ot);
+void UV_OT_select_linked(struct wmOperatorType *ot);
+void UV_OT_select_linked_pick(struct wmOperatorType *ot);
+void UV_OT_select_split(struct wmOperatorType *ot);
+void UV_OT_select_pinned(struct wmOperatorType *ot);
+void UV_OT_select_box(struct wmOperatorType *ot);
+void UV_OT_select_lasso(struct wmOperatorType *ot);
+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);
+
#endif /* __UVEDIT_INTERN_H__ */
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index b805681cfd3..652d07f02db 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -36,15 +36,9 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
-#include "BLI_alloca.h"
#include "BLI_array.h"
-#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"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -52,31 +46,22 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_image.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_material.h"
-#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_node.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_node.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "ED_uvedit.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_message.h"
@@ -88,26 +73,6 @@
#include "uvedit_intern.h"
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len);
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select);
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit);
-
/* -------------------------------------------------------------------- */
/** \name State Testing
* \{ */
@@ -225,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i
/** \name Space Conversion
* \{ */
-static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
+void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2])
{
int width, height;
@@ -237,351 +202,8 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist
height = IMG_SIZE_FALLBACK;
}
- dist[0] = pixeldist / width;
- dist[1] = pixeldist / height;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Visibility and Selection Utilities
- * \{ */
-
-static void uvedit_vertex_select_tagged(BMEditMesh *em,
- Scene *scene,
- bool select,
- int cd_loop_uv_offset)
-{
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- 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(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-}
-
-bool uvedit_face_visible_nolocal_ex(const ToolSettings *ts, BMFace *efa)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
- }
- else {
- return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
-}
-bool uvedit_face_visible_nolocal(const Scene *scene, BMFace *efa)
-{
- return uvedit_face_visible_nolocal_ex(scene->toolsettings, efa);
-}
-
-bool uvedit_face_visible_test_ex(const ToolSettings *ts, Object *obedit, Image *ima, BMFace *efa)
-{
- if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
- Image *face_image;
- ED_object_get_active_image(obedit, efa->mat_nr + 1, &face_image, NULL, NULL, NULL);
- return (face_image == ima) ? uvedit_face_visible_nolocal_ex(ts, efa) : false;
- }
- else {
- return uvedit_face_visible_nolocal_ex(ts, efa);
- }
-}
-bool uvedit_face_visible_test(const Scene *scene, Object *obedit, Image *ima, BMFace *efa)
-{
- return uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa);
-}
-
-bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (!(luv->flag & MLOOPUV_VERTSEL)) {
- return false;
- }
- }
-
- return true;
- }
-}
-bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
-{
- return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
-}
-
-bool uvedit_face_select_set(const struct Scene *scene,
- struct BMEditMesh *em,
- struct BMFace *efa,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
- }
- else {
- return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
-}
-
-bool uvedit_face_select_enable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, true);
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)efa);
- }
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_face_select_disable(const Scene *scene,
- BMEditMesh *em,
- BMFace *efa,
- const int cd_loop_uv_offset)
-{
- const ToolSettings *ts = scene->toolsettings;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BM_face_select_set(em->bm, efa, false);
- }
- else {
- BMLoop *l;
- MLoopUV *luv;
- BMIter liter;
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- return true;
- }
-
- return false;
-}
-
-bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
- }
- else if (ts->selectmode == SCE_SELECT_EDGE) {
- return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
- BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
- }
-}
-bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
-{
- return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
-}
-
-void uvedit_edge_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-
-{
- if (select) {
- uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_edge_select_enable(BMEditMesh *em,
- const Scene *scene,
- 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);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->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);
- }
-
- if (do_history) {
- BM_select_history_store(em->bm, (BMElem *)l->e);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag |= MLOOPUV_VERTSEL;
- luv2->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_edge_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- 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, false);
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- BM_edge_select_set(em->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);
- }
- }
- else {
- MLoopUV *luv1, *luv2;
-
- luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- luv1->flag &= ~MLOOPUV_VERTSEL;
- luv2->flag &= ~MLOOPUV_VERTSEL;
- }
-}
-
-bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode & SCE_SELECT_FACE) {
- return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
- }
- else {
- return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- 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);
-}
-
-void uvedit_uv_select_set(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- const bool select,
- const bool do_history,
- const int cd_loop_uv_offset)
-{
- if (select) {
- uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
- }
- else {
- uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
- }
-}
-
-void uvedit_uv_select_enable(BMEditMesh *em,
- const Scene *scene,
- 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);
- }
- else {
- BM_vert_select_set(em->bm, l->v, true);
- }
-
- if (do_history) {
- BM_select_history_remove(em->bm, (BMElem *)l->v);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag |= MLOOPUV_VERTSEL;
- }
-}
-
-void uvedit_uv_select_disable(BMEditMesh *em,
- const Scene *scene,
- BMLoop *l,
- 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, false);
- }
- else {
- BM_vert_select_set(em->bm, l->v, false);
- }
- }
- else {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
+ r_dist[0] = pixeldist / width;
+ r_dist[1] = pixeldist / height;
}
/** \} */
@@ -630,12 +252,8 @@ void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float as
}
}
-bool ED_uvedit_minmax_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float r_min[2],
- float r_max[2])
+bool ED_uvedit_minmax_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
{
bool changed = false;
INIT_MINMAX2(r_min, r_max);
@@ -652,7 +270,7 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -668,10 +286,9 @@ bool ED_uvedit_minmax_multi(const Scene *scene,
return changed;
}
-bool ED_uvedit_minmax(
- const Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
+bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
{
- return ED_uvedit_minmax_multi(scene, ima, &obedit, 1, r_min, r_max);
+ return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
}
/* Be careful when using this, it bypasses all synchronization options */
@@ -692,10 +309,12 @@ void ED_uvedit_select_all(BMesh *bm)
}
}
-static bool ED_uvedit_median_multi(
- const Scene *scene, Image *ima, Object **objects_edit, uint objects_len, float co[2])
+static bool ED_uvedit_median_multi(const Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ float co[2])
{
- unsigned int sel = 0;
+ uint sel = 0;
zero_v2(co);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
@@ -710,7 +329,7 @@ static bool ED_uvedit_median_multi(
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -729,24 +348,20 @@ static bool ED_uvedit_median_multi(
return (sel != 0);
}
-bool ED_uvedit_center_multi(const Scene *scene,
- Image *ima,
- Object **objects_edit,
- uint objects_len,
- float cent[2],
- char mode)
+bool ED_uvedit_center_multi(
+ const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
{
bool changed = false;
if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
float min[2], max[2];
- if (ED_uvedit_minmax_multi(scene, ima, objects_edit, objects_len, min, max)) {
+ if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) {
mid_v2_v2v2(cent, min, max);
changed = true;
}
}
else {
- if (ED_uvedit_median_multi(scene, ima, objects_edit, objects_len, cent)) {
+ if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) {
changed = true;
}
}
@@ -770,7 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
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);
- *r_has_select = uv_select_is_any_selected_multi(scene, sima->image, objects, objects_len);
+ *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len);
MEM_freeN(objects);
}
break;
@@ -779,7 +394,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima,
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);
- changed = ED_uvedit_center_multi(scene, sima->image, objects, objects_len, r_center, mode);
+ changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode);
MEM_freeN(objects);
if (r_has_select != NULL) {
*r_has_select = changed;
@@ -799,877 +414,6 @@ bool ED_uvedit_center_from_pivot(
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Find Nearest Elements
- * \{ */
-
-bool uv_find_nearest_edge(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv, *luv_next;
- int i;
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
-
- const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
-
- if (dist_test_sq < hit->dist_sq) {
- hit->efa = efa;
-
- hit->l = l;
- hit->luv = luv;
- hit->luv_next = luv_next;
- hit->lindex = i;
-
- hit->dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- return found;
-}
-
-bool uv_find_nearest_edge_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool uv_find_nearest_face(
- Scene *scene, Image *ima, Object *obedit, const float co[2], UvNearestHit *hit_final)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- bool found = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMIter iter;
- BMFace *efa;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- const float dist_test_sq = len_squared_v2v2(co, cent);
-
- if (dist_test_sq < hit.dist_sq) {
- hit.efa = efa;
- hit.dist_sq = dist_test_sq;
- found = true;
- }
- }
- }
- if (found) {
- *hit_final = hit;
- }
- return found;
-}
-
-bool uv_find_nearest_face_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
-{
- const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
- const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
- const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
-
- return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
- (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
-}
-
-bool uv_find_nearest_vert(Scene *scene,
- Image *ima,
- Object *obedit,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
-
- /* this will fill in hit.vert1 and hit.vert2 */
- float dist_sq_init = hit_final->dist_sq;
- UvNearestHit hit = *hit_final;
- if (uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
- hit.dist_sq = dist_sq_init;
-
- hit.l = NULL;
- hit.luv = hit.luv_next = NULL;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter;
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BMIter liter;
- BMLoop *l;
- int i;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
- float dist_test_sq;
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
- dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
- dist_test_sq = square_f(dist_test_sq);
- }
- else {
- dist_test_sq = len_squared_v2v2(co, luv->uv);
- }
-
- if (dist_test_sq <= hit.dist_sq) {
- if (dist_test_sq == hit.dist_sq) {
- if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
- continue;
- }
- }
-
- hit.dist_sq = dist_test_sq;
-
- hit.l = l;
- hit.luv = luv;
- hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
- hit.efa = efa;
- hit.lindex = i;
- found = true;
- }
- }
- }
- }
-
- if (found) {
- *hit_final = hit;
- }
-
- return found;
-}
-
-bool uv_find_nearest_vert_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- float const co[2],
- const float penalty_dist,
- UvNearestHit *hit_final)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
- hit_final->ob = obedit;
- found = true;
- }
- }
- return found;
-}
-
-bool ED_uvedit_nearest_uv(const Scene *scene,
- Object *obedit,
- Image *ima,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter;
- BMFace *efa;
- const float *uv_best = NULL;
- float dist_best = *dist_sq;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BMLoop *l_iter, *l_first;
- l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
- do {
- const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
- const float dist_test = len_squared_v2v2(co, uv);
- if (dist_best > dist_test) {
- dist_best = dist_test;
- uv_best = uv;
- }
- } while ((l_iter = l_iter->next) != l_first);
- }
-
- if (uv_best != NULL) {
- copy_v2_v2(r_uv, uv_best);
- *dist_sq = dist_best;
- return true;
- }
- else {
- return false;
- }
-}
-
-bool ED_uvedit_nearest_uv_multi(const Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float co[2],
- float *dist_sq,
- float r_uv[2])
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (ED_uvedit_nearest_uv(scene, obedit, ima, co, dist_sq, r_uv)) {
- found = true;
- }
- }
- return found;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select
- * \{ */
-
-static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
-{
- UvMapVert *iterv;
- int count = 0;
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate && iterv != first) {
- break;
- }
-
- count++;
- }
-
- if (count < 5) {
- first->flag = 1;
- }
-}
-
-static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
-{
- UvMapVert *iterv, *first;
- first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- for (iterv = first; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- first = iterv;
- }
- if (iterv->poly_index == BM_elem_index_get(efa)) {
- return first;
- }
- }
-
- return NULL;
-}
-
-static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
- UvMapVert *first1,
- UvMapVert *first2,
- int *totface)
-{
- UvMapVert *iterv1, *iterv2;
- BMFace *efa;
- int tot = 0;
-
- /* count number of faces this edge has */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- /* if face already tagged, don't do this edge */
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- return false;
- }
-
- tot++;
- break;
- }
- }
- }
-
- if (*totface == 0) { /* start edge */
- *totface = tot;
- }
- else if (tot != *totface) { /* check for same number of faces as start edge */
- return false;
- }
-
- /* tag the faces */
- for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
- if (iterv1->separate && iterv1 != first1) {
- break;
- }
-
- for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
- if (iterv2->separate && iterv2 != first2) {
- break;
- }
-
- if (iterv1->poly_index == iterv2->poly_index) {
- efa = BM_face_at_index(em->bm, iterv1->poly_index);
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- break;
- }
- }
- }
-
- return true;
-}
-
-static int uv_select_edgeloop(Scene *scene,
- Image *ima,
- Object *obedit,
- UvNearestHit *hit,
- const float limit[2],
- const bool extend)
-{
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMIter iter, liter;
- BMLoop *l;
- UvVertMap *vmap;
- UvMapVert *iterv_curr;
- UvMapVert *iterv_next;
- int starttotf;
- bool looking, select;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* setup */
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
-
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* set flags for first face and verts */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
-
- starttotf = 0;
- uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
-
- /* sorry, first edge isn't even ok */
- looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
-
- /* iterate */
- while (looking) {
- looking = false;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!BM_elem_flag_test(efa, BM_ELEM_TAG) &&
- uvedit_face_visible_test(scene, obedit, ima, efa)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- /* check face not hidden and not tagged */
- if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
- continue;
- }
- if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
- continue;
- }
-
- /* check if vertex is tagged and has right valence */
- if (iterv_curr->flag || iterv_next->flag) {
- if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
- looking = true;
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
-
- uv_select_edgeloop_vertex_loop_flag(iterv_curr);
- uv_select_edgeloop_vertex_loop_flag(iterv_next);
- break;
- }
- }
- }
- }
- }
- }
-
- /* do the actual select/deselect */
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
- iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
- iterv_curr->flag = 1;
- iterv_next->flag = 1;
-
- if (extend) {
- select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
- }
- else {
- select = true;
- }
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
-
- if (iterv_curr->flag) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- /* cleanup */
- BM_uv_vert_map_free(vmap);
-
- return (select) ? 1 : -1;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked
- * \{ */
-
-static void uv_select_linked_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len,
- const float limit[2],
- UvNearestHit *hit_final,
- bool extend,
- bool deselect,
- bool toggle,
- bool select_faces)
-{
- /* loop over objects, or just use hit_final->ob */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- if (hit_final && ob_index != 0) {
- break;
- }
- Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvVertMap *vmap;
- UvMapVert *vlist, *iterv, *startv;
- int i, stacksize = 0, *stack;
- unsigned int a;
- char *flag;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
-
- /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
- * this made *every* projection split the island into front/back islands.
- * Keep 'use_winding' to false, see: T50970.
- *
- * Better solve this by having a delimit option for select-linked operator,
- * keeping island-select working as is. */
- vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
-
- if (vmap == NULL) {
- continue;
- }
-
- stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
- flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
-
- if (hit_final == NULL) {
- /* Use existing selection */
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
-
- break;
- }
- }
- }
- }
- }
- }
- else {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (efa == hit_final->efa) {
- stack[stacksize] = a;
- stacksize++;
- flag[a] = 1;
- break;
- }
- }
- }
-
- while (stacksize > 0) {
-
- stacksize--;
- a = stack[stacksize];
-
- efa = BM_face_at_index(em->bm, a);
-
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
-
- /* make_uv_vert_map_EM sets verts tmp.l to the indices */
- vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- startv = vlist;
-
- for (iterv = vlist; iterv; iterv = iterv->next) {
- if (iterv->separate) {
- startv = iterv;
- }
- if (iterv->poly_index == a) {
- break;
- }
- }
-
- for (iterv = startv; iterv; iterv = iterv->next) {
- if ((startv != iterv) && (iterv->separate)) {
- break;
- }
- else if (!flag[iterv->poly_index]) {
- flag[iterv->poly_index] = 1;
- stack[stacksize] = iterv->poly_index;
- stacksize++;
- }
- }
- }
- }
-
- /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
- if ((toggle == true) && (extend == false) && (deselect == false)) {
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- bool found_selected = false;
- if (!flag[a]) {
- continue;
- }
-
- if (select_faces) {
- if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- found_selected = true;
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- found_selected = true;
- }
- }
-
- if (found_selected) {
- deselect = true;
- break;
- }
- }
- }
- }
-
-#define SET_SELECTION(value) \
- if (select_faces) { \
- BM_face_select_set(em->bm, efa, value); \
- } \
- else { \
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
- luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
- } \
- } \
- (void)0
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
- if (!flag[a]) {
- if (!extend && !deselect && !toggle) {
- SET_SELECTION(false);
- }
- continue;
- }
-
- if (!deselect) {
- SET_SELECTION(true);
- }
- else {
- SET_SELECTION(false);
- }
- }
-
-#undef SET_SELECTION
-
- MEM_freeN(stack);
- MEM_freeN(flag);
- BM_uv_vert_map_free(vmap);
- }
-}
-
-/* WATCH IT: this returns first selected UV,
- * not ideal in many cases since there could be multiple */
-static float *uv_sel_co_from_eve(
- Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
-{
- BMIter liter;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
- if (!uvedit_face_visible_test(scene, obedit, ima, 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);
- return luv->uv;
- }
- }
-
- return NULL;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select More/Less Operator
- * \{ */
-
-static int uv_select_more_less(bContext *C, const bool select)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- SpaceImage *sima = CTX_wm_space_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const ToolSettings *ts = scene->toolsettings;
-
- 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);
-
- const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (select) {
- EDBM_select_more(em, true);
- }
- else {
- EDBM_select_less(em, true);
- }
-
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- continue;
- }
-
- if (is_uv_face_selectmode) {
-
- /* clear tags */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
-
-#define IS_SEL 1
-#define IS_UNSEL 2
-
- int sel_state = 0;
-
- 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_VERTSEL) {
- sel_state |= IS_SEL;
- }
- else {
- sel_state |= IS_UNSEL;
- }
-
- /* if we have a mixed selection, tag to grow it */
- if (sel_state == (IS_SEL | IS_UNSEL)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- break;
- }
- }
-
-#undef IS_SEL
-#undef IS_UNSEL
- }
- }
- }
- else {
-
- /* clear tags */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_disable(l, BM_ELEM_TAG);
- }
- }
-
- /* mark loops to be selected */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- 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_VERTSEL) != 0) == select) {
- BM_elem_flag_enable(l->next, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
- }
- }
-
- if (changed) {
- if (is_uv_face_selectmode) {
- /* Select tagged faces. */
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- else {
- /* Select tagged loops. */
- uv_select_flush_from_tag_loop(sima, scene, obedit, select);
- }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, true);
-}
-
-static void UV_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select More";
- ot->description = "Select more UV vertices connected to initial selection";
- ot->idname = "UV_OT_select_more";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_more_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
-{
- return uv_select_more_less(C, false);
-}
-
-static void UV_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Less";
- ot->description = "Deselect UV vertices at the boundary of each selection region";
- ot->idname = "UV_OT_select_less";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_less_exec;
- ot->poll = ED_operator_uvedit_space_image;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Weld Align Operator
* \{ */
@@ -1688,7 +432,6 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
float cent[2], min[2], max[2];
@@ -1715,7 +458,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1730,7 +473,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
}
- ED_uvedit_center_multi(scene, ima, objects, objects_len, cent, 0);
+ ED_uvedit_center_multi(scene, objects, objects_len, cent, 0);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
@@ -1749,7 +492,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1769,7 +512,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
BMLoop *l;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -1796,7 +539,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* 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, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -1866,9 +609,10 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
if (BLI_array_len(eve_line) > 2) {
/* we know the returns from these must be valid */
- const float *uv_start = uv_sel_co_from_eve(scene, obedit, ima, em, eve_line[0]);
- const float *uv_end = uv_sel_co_from_eve(
- scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]);
+ 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;
@@ -1893,7 +637,7 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool)
/* 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, obedit, ima, l->f)) {
+ if (!uvedit_face_visible_test(scene, l->f)) {
continue;
}
@@ -2001,7 +745,6 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -2055,7 +798,7 @@ static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2146,7 +889,6 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const float threshold = RNA_float_get(op->ptr, "threshold");
@@ -2186,7 +928,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2219,7 +961,7 @@ static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -2316,1665 +1058,6 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name (De)Select All Operator
- * \{ */
-
-static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
- }
- else {
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (luv->flag & MLOOPUV_VERTSEL) {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-static bool uv_select_is_any_selected_multi(Scene *scene,
- Image *ima,
- Object **objects,
- const uint objects_len)
-{
- bool found = false;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- if (uv_select_is_any_selected(scene, ima, obedit)) {
- found = true;
- break;
- }
- }
- return found;
-}
-
-static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
-{
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
- }
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- switch (action) {
- case SEL_TOGGLE:
- EDBM_select_toggle_all(em);
- break;
- case SEL_SELECT:
- EDBM_flag_enable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_DESELECT:
- EDBM_flag_disable_all(em, BM_ELEM_SELECT);
- break;
- case SEL_INVERT:
- EDBM_select_swap(em);
- EDBM_selectmode_flush(em);
- break;
- }
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- switch (action) {
- case SEL_SELECT:
- luv->flag |= MLOOPUV_VERTSEL;
- break;
- case SEL_DESELECT:
- luv->flag &= ~MLOOPUV_VERTSEL;
- break;
- case SEL_INVERT:
- luv->flag ^= MLOOPUV_VERTSEL;
- break;
- }
- }
- }
- }
-}
-
-static void uv_select_all_perform_multi(
- Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
-{
- if (action == SEL_TOGGLE) {
- action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT :
- SEL_SELECT;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_all_perform(scene, ima, obedit, action);
- }
-}
-
-static int uv_select_all_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
- int action = RNA_enum_get(op->ptr, "action");
-
- 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);
-
- uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "(De)select All";
- ot->description = "Change selection of all UV vertices";
- ot->idname = "UV_OT_select_all";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_all_exec;
- ot->poll = ED_operator_uvedit;
-
- WM_operator_properties_select_all(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Mouse Select Operator
- * \{ */
-
-static bool uv_sticky_select(
- float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
-{
- int i;
-
- /* this function test if some vertex needs to selected
- * in addition to the existing ones due to sticky select */
- if (sticky == SI_STICKY_DISABLE) {
- return false;
- }
-
- for (i = 0; i < hitlen; i++) {
- if (hitv[i] == v) {
- if (sticky == SI_STICKY_LOC) {
- if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
- return true;
- }
- }
- else if (sticky == SI_STICKY_VERTEX) {
- return true;
- }
- }
- }
-
- return false;
-}
-
-static int uv_mouse_select_multi(bContext *C,
- Object **objects,
- uint objects_len,
- const float co[2],
- const bool extend,
- const bool deselect_all,
- const bool loop)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
- int i, selectmode, sticky, sync, *hitv = NULL;
- bool select = true;
- bool found_item = false;
- /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
- int flush = 0;
- int hitlen = 0;
- float limit[2], **hituv = NULL;
-
- /* notice 'limit' is the same no matter the zoom level, since this is like
- * remove doubles and could annoying if it joined points when zoomed out.
- * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
- * shift-selecting can consider an adjacent point close enough to add to
- * the selection rather than de-selecting the closest. */
-
- float penalty_dist;
- {
- float penalty[2];
- uvedit_pixel_to_float(sima, limit, 0.05f);
- uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
- penalty_dist = len_v2(penalty);
- }
-
- /* retrieve operation mode */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- sync = 1;
-
- if (ts->selectmode & SCE_SELECT_FACE) {
- selectmode = UV_SELECT_FACE;
- }
- else if (ts->selectmode & SCE_SELECT_EDGE) {
- selectmode = UV_SELECT_EDGE;
- }
- else {
- selectmode = UV_SELECT_VERTEX;
- }
-
- sticky = SI_STICKY_DISABLE;
- }
- else {
- sync = 0;
- selectmode = ts->uv_selectmode;
- sticky = (sima) ? sima->sticky : 1;
- }
-
- /* find nearest element */
- if (loop) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- }
- else if (selectmode == UV_SELECT_VERTEX) {
- /* find vertex */
- found_item = uv_find_nearest_vert_multi(
- scene, ima, objects, objects_len, co, penalty_dist, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 1 vertex as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hituv[hit.lindex] = hit.luv->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* find edge */
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- /* mark 2 edge vertices as being hit */
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
-
- hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
- hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
- hituv[hit.lindex] = hit.luv->uv;
- hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* find face */
- found_item = uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
-
- if (found_item) {
- BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* make active */
- BM_mesh_active_face_set(em->bm, hit.efa);
-
- /* mark all face vertices as being hit */
-
- hitv = BLI_array_alloca(hitv, hit.efa->len);
- hituv = BLI_array_alloca(hituv, hit.efa->len);
- BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- hituv[i] = luv->uv;
- hitv[i] = BM_elem_index_get(l->v);
- }
-
- hitlen = hit.efa->len;
- }
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- found_item = uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit);
- found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
- }
-
- if (!found_item) {
- if (deselect_all) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
- }
-
- Object *obedit = hit.ob;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (loop) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
- }
- else if (selectmode == UV_SELECT_ISLAND) {
- if (!extend) {
- /* TODO(MULTI_EDIT): We only need to de-select non-active */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
- /* Current behavior of 'extend'
- * is actually toggling, so pass extend flag as 'toggle' here */
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, false, false, extend, false);
- }
- else if (extend) {
- if (selectmode == UV_SELECT_VERTEX) {
- /* (de)select uv vertex */
- select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
- uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* (de)select edge */
- select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
- uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* (de)select face */
- select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
- uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
- flush = -1;
- }
-
- /* de-selecting an edge may deselect a face too - validate */
- if (sync) {
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-
- /* (de)select sticky uv nodes */
- if (sticky != SI_STICKY_DISABLE) {
-
- BM_mesh_elem_index_ensure(em->bm, BM_VERT);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
-
- flush = select ? 1 : -1;
- }
- }
- else {
- /* deselect all */
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
-
- if (selectmode == UV_SELECT_VERTEX) {
- /* select vertex */
- uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_EDGE) {
- /* select edge */
- uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
- flush = 1;
- }
- else if (selectmode == UV_SELECT_FACE) {
- /* select face */
- uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
- }
-
- /* select sticky uvs */
- if (sticky != SI_STICKY_DISABLE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (sticky == SI_STICKY_DISABLE) {
- continue;
- }
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (uv_sticky_select(
- limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- }
-
- flush = 1;
- }
- }
- }
- }
-
- if (sync) {
- /* flush for mesh selection */
-
- /* before bmesh */
-#if 0
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (flush == 1) {
- EDBM_select_flush(em);
- }
- else if (flush == -1) {
- EDBM_deselect_flush(em);
- }
- }
-#else
- if (flush != 0) {
- if (loop) {
- /* push vertex -> edge selection */
- if (select) {
- EDBM_select_flush(em);
- }
- else {
- EDBM_deselect_flush(em);
- }
- }
- else {
- EDBM_selectmode_flush(em);
- }
- }
-#endif
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obiter = objects[ob_index];
- uv_select_tag_update_for_object(depsgraph, ts, obiter);
- }
-
- return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
-}
-static int uv_mouse_select(
- bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
-{
- 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_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
- int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
- MEM_freeN(objects);
- return ret;
-}
-
-static int uv_select_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool loop = false;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_exec(C, op);
-}
-
-static void UV_OT_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select";
- ot->description = "Select UV vertices";
- ot->idname = "UV_OT_select";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_exec;
- ot->invoke = uv_select_invoke;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* properties */
- PropertyRNA *prop;
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
- prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Loop Select Operator
- * \{ */
-
-static int uv_select_loop_exec(bContext *C, wmOperator *op)
-{
- float co[2];
-
- RNA_float_get_array(op->ptr, "location", co);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = false;
- const bool loop = true;
-
- return uv_mouse_select(C, co, extend, deselect_all, loop);
-}
-
-static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- ARegion *region = CTX_wm_region(C);
- float co[2];
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
-
- return uv_select_loop_exec(C, op);
-}
-
-static void UV_OT_select_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Loop Select";
- ot->description = "Select a loop of connected UV vertices";
- ot->idname = "UV_OT_select_loop";
- ot->flag = OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_loop_exec;
- ot->invoke = uv_select_loop_invoke;
- 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(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked Operator
- * \{ */
-
-static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
-{
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- float limit[2];
- bool extend = true;
- bool deselect = false;
- bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
-
- UvNearestHit hit = UV_NEAREST_HIT_INIT;
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Select linked only works in face select mode when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- if (pick) {
- extend = RNA_boolean_get(op->ptr, "extend");
- deselect = RNA_boolean_get(op->ptr, "deselect");
- }
- uvedit_pixel_to_float(sima, limit, 0.05f);
-
- 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);
-
- if (pick) {
- float co[2];
-
- if (event) {
- /* invoke */
- ARegion *region = CTX_wm_region(C);
-
- UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
- RNA_float_set_array(op->ptr, "location", co);
- }
- else {
- /* exec */
- RNA_float_get_array(op->ptr, "location", co);
- }
-
- if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
- MEM_freeN(objects);
- return OPERATOR_CANCELLED;
- }
- }
-
- if (!extend) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- uv_select_linked_multi(scene,
- ima,
- objects,
- objects_len,
- limit,
- pick ? &hit : NULL,
- extend,
- deselect,
- false,
- select_faces);
-
- /* weak!, but works */
- Object **objects_free = objects;
- if (pick) {
- objects = &hit.ob;
- objects_len = 1;
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
- }
-
- MEM_SAFE_FREE(objects_free);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_linked_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, false);
-}
-
-static void UV_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked";
- ot->description = "Select all UV vertices linked to the active UV map";
- ot->idname = "UV_OT_select_linked";
-
- /* api callbacks */
- ot->exec = uv_select_linked_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Linked (Cursor Pick) Operator
- * \{ */
-
-static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- return uv_select_linked_internal(C, op, event, true);
-}
-
-static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
-{
- return uv_select_linked_internal(C, op, NULL, true);
-}
-
-static void UV_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Linked Pick";
- ot->description = "Select all UV vertices linked under the mouse";
- ot->idname = "UV_OT_select_linked_pick";
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->invoke = uv_select_linked_pick_invoke;
- ot->exec = uv_select_linked_pick_exec;
- 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_boolean(ot->srna,
- "deselect",
- 0,
- "Deselect",
- "Deselect linked UV vertices rather than selecting them");
- RNA_def_float_vector(
- ot->srna,
- "location",
- 2,
- NULL,
- -FLT_MAX,
- FLT_MAX,
- "Location",
- "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
- -100.0f,
- 100.0f);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Split Operator
- * \{ */
-
-/**
- * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
- * but in this case they are not joined to begin with (only having the behavior of being joined)
- * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
- * key as #MESH_OT_split - Campbell.
- */
-static int uv_select_split_exec(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- Image *ima = CTX_data_edit_image(C);
-
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
- return OPERATOR_CANCELLED;
- }
-
- bool changed_multi = false;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
-
- BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- bool is_sel = false;
- bool is_unsel = false;
-
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- /* are we all selected? */
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_VERTSEL) {
- is_sel = true;
- }
- else {
- is_unsel = true;
- }
-
- /* we have mixed selection, bail out */
- if (is_sel && is_unsel) {
- break;
- }
- }
-
- if (is_sel && is_unsel) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- luv->flag &= ~MLOOPUV_VERTSEL;
- }
-
- changed = true;
- }
- }
-
- if (changed) {
- changed_multi = true;
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Split";
- ot->description = "Select only entirely selected faces";
- ot->idname = "UV_OT_select_split";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_split_exec;
- ot->poll = ED_operator_uvedit; /* requires space image */
-}
-
-static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
-{
- /* bmesh API handles flushing but not on de-select */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (ts->selectmode != SCE_SELECT_FACE) {
- if (select == false) {
- EDBM_deselect_flush(em);
- }
- else {
- EDBM_select_flush(em);
- }
- }
-
- if (select == false) {
- BM_select_history_validate(em->bm);
- }
- }
-}
-
-static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
- const ToolSettings *ts,
- Object *obedit)
-{
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
- else {
- Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
- BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
- /* Only for region redraw. */
- WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select/Tag Flushing Utils
- *
- * Utility functions to flush the uv-selection from tags.
- * \{ */
-
-/**
- * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
- */
-static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
- BMEditMesh *em,
- UvVertMap *vmap,
- const unsigned int efa_index,
- BMLoop *l,
- const bool select,
- const int cd_loop_uv_offset)
-{
- UvMapVert *start_vlist = NULL, *vlist_iter;
- BMFace *efa_vlist;
-
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
-
- vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
-
- while (vlist_iter) {
- if (vlist_iter->separate) {
- start_vlist = vlist_iter;
- }
-
- if (efa_index == vlist_iter->poly_index) {
- break;
- }
-
- vlist_iter = vlist_iter->next;
- }
-
- vlist_iter = start_vlist;
- while (vlist_iter) {
-
- if (vlist_iter != start_vlist && vlist_iter->separate) {
- break;
- }
-
- if (efa_index != vlist_iter->poly_index) {
- BMLoop *l_other;
- efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
- /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
-
- l_other = BM_iter_at_index(
- em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
-
- uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
- }
- vlist_iter = vlist_iter->next;
- }
-}
-
-/**
- * Flush the selection from face tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also
- * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
- * is best done in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_face(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Faces with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- 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);
- }
- }
- }
-}
-
-/**
- * Flush the selection from loop tags based on sticky and selection modes.
- *
- * needed because settings the selection a face is done in a number of places but it also needs
- * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
- * in a separate function.
- *
- * \note This function is very similar to #uv_select_flush_from_tag_loop,
- * be sure to update both upon changing.
- */
-static void uv_select_flush_from_tag_loop(SpaceImage *sima,
- Scene *scene,
- Object *obedit,
- const bool select)
-{
- /* Selecting UV Loops with some modes requires us to change
- * the selection in other faces (depending on the sticky mode).
- *
- * This only needs to be done when the Mesh is not used for
- * selection (so for sticky modes, vertex or location based). */
-
- const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
- /* Tag all verts as untouched, then touch the ones that have a face center
- * in the loop and select all MLoopUV's that use a touched vert. */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- 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)) {
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
-
- /* now select tagged verts */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
- else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
- struct UvVertMap *vmap;
- float limit[2];
- unsigned int efa_index;
-
- uvedit_pixel_to_float(sima, limit, 0.05);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
- if (vmap == NULL) {
- return;
- }
-
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
- /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
- uv_select_flush_from_tag_sticky_loc_internal(
- scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
- }
- }
- }
- BM_uv_vert_map_free(vmap);
- }
- else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
- 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(em, scene, l, select, false, cd_loop_uv_offset);
- }
- }
- }
- }
-}
-
-/** \} */
-
-#define UV_SELECT_ISLAND_LIMIT \
- float limit[2]; \
- uvedit_pixel_to_float(sima, limit, 0.05f)
-
-/* -------------------------------------------------------------------- */
-/** \name Box Select Operator
- * \{ */
-
-static int uv_box_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- rctf rectf;
- bool pinned;
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get rectangle from operator */
- WM_operator_properties_border_to_rctf(op, &rectf);
- UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
-
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- pinned = RNA_boolean_get(op->ptr, "pinned");
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- 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);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do actual selection */
- if (use_face_center && !pinned) {
- /* handle face selection mode */
- float cent[2];
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- /* assume not touched */
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
-
- if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (BLI_rctf_isect_pt_v(&rectf, cent)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- /* other selection modes */
- changed = true;
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- 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(em, scene, 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(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- }
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
-
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_box(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Box Select";
- ot->description = "Select UV vertices using box selection";
- ot->idname = "UV_OT_select_box";
-
- /* api callbacks */
- ot->invoke = WM_gesture_box_invoke;
- ot->exec = uv_box_select_exec;
- ot->modal = WM_gesture_box_modal;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_box_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
-
- WM_operator_properties_gesture_box(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Circle Select Operator
- * \{ */
-
-static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
-{
- /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
- float x, y;
- x = (uv[0] - offset[0]) * ellipse[0];
- y = (uv[1] - offset[1]) * ellipse[1];
- return ((x * x + y * y) < 1.0f);
-}
-
-static int uv_circle_select_exec(bContext *C, wmOperator *op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const ToolSettings *ts = scene->toolsettings;
- ARegion *region = CTX_wm_region(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
- int x, y, radius, width, height;
- float zoomx, zoomy, offset[2], ellipse[2];
-
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
-
- /* get operator properties */
- x = RNA_int_get(op->ptr, "x");
- y = RNA_int_get(op->ptr, "y");
- radius = RNA_int_get(op->ptr, "radius");
-
- /* compute ellipse size and location, not a circle since we deal
- * with non square image. ellipse is normalized, r = 1.0. */
- ED_space_image_get_size(sima, &width, &height);
- ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
-
- ellipse[0] = width * zoomx / radius;
- ellipse[1] = height * zoomy / radius;
-
- UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
-
- UV_SELECT_ISLAND_LIMIT;
-
- bool changed_multi = false;
-
- 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);
-
- const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
- WM_gesture_is_modal_first(op->customdata));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- bool changed = false;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* do selection */
- if (use_face_center) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
- if (uv_inside_circle(cent, offset, ellipse)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else {
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (uv_inside_circle(luv->uv, offset, ellipse)) {
- changed = true;
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
-}
-
-static void UV_OT_select_circle(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Circle Select";
- ot->description = "Select UV vertices using circle selection";
- ot->idname = "UV_OT_select_circle";
-
- /* api callbacks */
- ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
- ot->exec = uv_circle_select_exec;
- ot->poll = ED_operator_uvedit_space_image; /* requires space image */
- ot->cancel = WM_gesture_circle_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_circle(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Lasso Select Operator
- * \{ */
-
-static bool do_lasso_select_mesh_uv(bContext *C,
- const int mcords[][2],
- short moves,
- const eSelectOp sel_op)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
- ARegion *region = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
- (ts->selectmode == SCE_SELECT_FACE) :
- (ts->uv_selectmode == UV_SELECT_FACE));
- const bool select = (sel_op != SEL_OP_SUB);
- const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
-
- BMIter iter, liter;
-
- BMFace *efa;
- BMLoop *l;
- int screen_uv[2];
- bool changed_multi = false;
- rcti rect;
-
- UV_SELECT_ISLAND_LIMIT;
-
- BLI_lasso_boundbox(&rect, mcords, moves);
-
- 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);
-
- if (use_pre_deselect) {
- uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
- }
-
- /* don't indent to avoid diff noise! */
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
-
- bool changed = false;
-
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- if (use_face_center) { /* Face Center Sel */
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- /* assume not touched */
- if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
- float cent[2];
- uv_poly_center(efa, cent, cd_loop_uv_offset);
-
- if (UI_view2d_view_to_region_clip(
- &region->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- changed = true;
- }
- }
- }
-
- /* (de)selects all tagged faces and deals with sticky modes */
- if (changed) {
- uv_select_flush_from_tag_face(sima, scene, obedit, select);
- }
- }
- else { /* Vert Sel */
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
- bool has_selected = false;
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UI_view2d_view_to_region_clip(
- &region->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) &&
- BLI_rcti_isect_pt_v(&rect, screen_uv) &&
- BLI_lasso_is_point_inside(
- mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) {
- uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
- changed = true;
- BM_elem_flag_enable(l->v, BM_ELEM_TAG);
- has_selected = true;
- }
- }
- }
- if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
- UvNearestHit hit = {
- .ob = obedit,
- .efa = efa,
- };
- uv_select_linked_multi(
- scene, ima, objects, objects_len, limit, &hit, true, !select, false, false);
- }
- }
-
- if (sima->sticky == SI_STICKY_VERTEX) {
- uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
- }
- }
-
- if (changed || use_pre_deselect) {
- changed_multi = true;
-
- uv_select_sync_flush(ts, em, select);
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return changed_multi;
-}
-
-static int uv_lasso_select_exec(bContext *C, wmOperator *op)
-{
- int mcords_tot;
- const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
-
- if (mcords) {
- const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
- bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op);
- MEM_freeN((void *)mcords);
-
- return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
- }
-
- return OPERATOR_PASS_THROUGH;
-}
-
-static void UV_OT_select_lasso(wmOperatorType *ot)
-{
- ot->name = "Lasso Select UV";
- ot->description = "Select UVs using lasso selection";
- ot->idname = "UV_OT_select_lasso";
-
- ot->invoke = WM_gesture_lasso_invoke;
- ot->modal = WM_gesture_lasso_modal;
- ot->exec = uv_lasso_select_exec;
- ot->poll = ED_operator_uvedit_space_image;
- ot->cancel = WM_gesture_lasso_cancel;
-
- /* flags */
- ot->flag = OPTYPE_UNDO;
-
- /* properties */
- WM_operator_properties_gesture_lasso(ot);
- WM_operator_properties_select_operation_simple(ot);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Snap Cursor Operator
* \{ */
@@ -3992,10 +1075,12 @@ static void uv_snap_cursor_to_pixels(SpaceImage *sima)
uv_snap_to_pixel(sima->cursor, width, height);
}
-static bool uv_snap_cursor_to_selection(
- Scene *scene, Image *ima, Object **objects_edit, uint objects_len, SpaceImage *sima)
+static bool uv_snap_cursor_to_selection(Scene *scene,
+ Object **objects_edit,
+ uint objects_len,
+ SpaceImage *sima)
{
- return ED_uvedit_center_multi(scene, ima, objects_edit, objects_len, sima->cursor, sima->around);
+ return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
}
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
@@ -4011,13 +1096,12 @@ static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
break;
case 1: {
Scene *scene = CTX_data_scene(C);
- Image *ima = CTX_data_edit_image(C);
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_with_uvs(
view_layer, ((View3D *)NULL), &objects_len);
- changed = uv_snap_cursor_to_selection(scene, ima, objects, objects_len, sima);
+ changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima);
MEM_freeN(objects);
break;
}
@@ -4061,7 +1145,7 @@ static void UV_OT_snap_cursor(wmOperatorType *ot)
/** \name Snap Selection Operator
* \{ */
-static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, const float cursor[2])
+static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -4073,7 +1157,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4089,7 +1173,7 @@ static bool uv_snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, cons
return changed;
}
-static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const float offset[2])
+static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
@@ -4101,7 +1185,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4117,7 +1201,7 @@ static bool uv_snap_uvs_offset(Scene *scene, Image *ima, Object *obedit, const f
return changed;
}
-static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
+static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
@@ -4131,7 +1215,7 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
/* index every vert that has a selected UV using it, but only once so as to
* get unique indices and to count how much to malloc */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- if (uvedit_face_visible_test(scene, obedit, ima, f)) {
+ if (uvedit_face_visible_test(scene, f)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
@@ -4175,7 +1259,6 @@ static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
- Image *ima = sima->image;
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -4191,7 +1274,7 @@ static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit
h = (float)height;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4213,7 +1296,6 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Image *ima = CTX_data_edit_image(C);
const ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
const int target = RNA_enum_get(op->ptr, "target");
@@ -4225,7 +1307,7 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
if (target == 2) {
float center[2];
- if (!ED_uvedit_center_multi(scene, ima, objects, objects_len, center, sima->around)) {
+ if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) {
MEM_freeN(objects);
return OPERATOR_CANCELLED;
}
@@ -4247,13 +1329,13 @@ static int uv_snap_selection_exec(bContext *C, wmOperator *op)
changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
break;
case 1:
- changed = uv_snap_uvs_to_cursor(scene, ima, obedit, sima->cursor);
+ changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor);
break;
case 2:
- changed = uv_snap_uvs_offset(scene, ima, obedit, offset);
+ changed = uv_snap_uvs_offset(scene, obedit, offset);
break;
case 3:
- changed = uv_snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+ changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit);
break;
}
@@ -4304,7 +1386,6 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -4329,7 +1410,7 @@ static int uv_pin_exec(bContext *C, wmOperator *op)
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
+ if (!uvedit_face_visible_test(scene, efa)) {
continue;
}
@@ -4379,314 +1460,6 @@ static void UV_OT_pin(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Select Pinned UV's Operator
- * \{ */
-
-static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- const ToolSettings *ts = scene->toolsettings;
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
-
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
- view_layer, ((View3D *)NULL), &objects_len);
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- bool changed = false;
-
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
- }
-
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
-
- if (luv->flag & MLOOPUV_PINNED) {
- uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
- changed = true;
- }
- }
- }
-
- if (changed) {
- uv_select_tag_update_for_object(depsgraph, ts, obedit);
- }
- }
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static void UV_OT_select_pinned(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Selected Pinned";
- ot->description = "Select all pinned UV vertices";
- ot->idname = "UV_OT_select_pinned";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_pinned_exec;
- ot->poll = ED_operator_uvedit;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Select Overlap Operator
- * \{ */
-
-BLI_INLINE uint overlap_hash(const void *overlap_v)
-{
- const BVHTreeOverlap *overlap = overlap_v;
-
- /* Designed to treat (A,B) and (B,A) as the same. */
- int x = overlap->indexA;
- int y = overlap->indexB;
- if (x > y) {
- SWAP(int, x, y);
- }
- return BLI_hash_int_2d(x, y);
-}
-
-BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
-{
- const BVHTreeOverlap *a = a_v;
- const BVHTreeOverlap *b = b_v;
- return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
- (a->indexA == b->indexB && a->indexB == b->indexA));
-}
-
-struct UVOverlapData {
- int ob_index;
- int face_index;
- float tri[3][2];
-};
-
-static int uv_select_overlap(bContext *C, const bool extend)
-{
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Image *ima = CTX_data_edit_image(C);
-
- 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);
-
- /* Calculate maximum number of tree nodes and prepare initial selection. */
- uint uv_tri_len = 0;
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- BM_mesh_elem_table_ensure(em->bm, BM_FACE);
- BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
- BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
- if (!extend) {
- uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
- }
-
- BMIter iter;
- BMFace *efa;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
- uv_tri_len += efa->len - 2;
- }
- }
-
- struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
- "UvOverlapData");
- BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
-
- /* Use a global data index when inserting into the BVH. */
- int data_index = 0;
-
- int face_len_alloc = 3;
- float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
- uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMIter iter, liter;
- BMFace *efa;
- BMLoop *l;
-
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
-
- /* Triangulate each UV face and store it inside the BVH. */
- int face_index;
- BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
-
- if (!uvedit_face_visible_test_ex(scene->toolsettings, obedit, ima, efa)) {
- continue;
- }
-
- const uint face_len = efa->len;
- const uint tri_len = face_len - 2;
-
- if (face_len_alloc < face_len) {
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
- uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
- indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
- face_len_alloc = face_len;
- }
-
- int vert_index;
- BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
- MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- copy_v2_v2(uv_verts[vert_index], luv->uv);
- }
-
- BLI_polyfill_calc(uv_verts, face_len, 0, indices);
-
- for (int t = 0; t < tri_len; t++) {
- overlap_data[data_index].ob_index = ob_index;
- overlap_data[data_index].face_index = face_index;
-
- /* BVH needs 3D, overlap data uses 2D. */
- const float tri[3][3] = {
- {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
- {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
- };
-
- copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
- copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
- copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
-
- BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
- data_index++;
- }
- }
- }
- BLI_assert(data_index == uv_tri_len);
-
- MEM_freeN(uv_verts);
- MEM_freeN(indices);
-
- BLI_bvhtree_balance(uv_tree);
-
- uint tree_overlap_len;
- BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
-
- if (overlap != NULL) {
- GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
-
- for (int i = 0; i < tree_overlap_len; i++) {
- /* Skip overlaps against yourself. */
- if (overlap[i].indexA == overlap[i].indexB) {
- continue;
- }
-
- /* Skip overlaps that have already been tested. */
- if (!BLI_gset_add(overlap_set, &overlap[i])) {
- continue;
- }
-
- const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
- const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
- Object *obedit_a = objects[o_a->ob_index];
- Object *obedit_b = objects[o_b->ob_index];
- BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
- BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
- BMFace *face_a = em_a->bm->ftable[o_a->face_index];
- BMFace *face_b = em_b->bm->ftable[o_b->face_index];
- const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
- const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
-
- /* Skip if both faces are already selected. */
- if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
- uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
- continue;
- }
-
- /* Main tri-tri overlap test. */
- const float endpoint_bias = -1e-4f;
- const float(*t1)[2] = o_a->tri;
- const float(*t2)[2] = o_b->tri;
- float vi[2];
- bool result = (
- /* Don't use 'isect_tri_tri_v2' here
- * because it's important to ignore overlap at end-points. */
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
- isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
- isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
- isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
-
- if (result) {
- 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);
- }
- }
-
- BLI_gset_free(overlap_set, NULL);
- MEM_freeN(overlap);
- }
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
- }
-
- BLI_bvhtree_free(uv_tree);
-
- MEM_freeN(overlap_data);
- MEM_freeN(objects);
-
- return OPERATOR_FINISHED;
-}
-
-static int uv_select_overlap_exec(bContext *C, wmOperator *op)
-{
- bool extend = RNA_boolean_get(op->ptr, "extend");
- return uv_select_overlap(C, extend);
-}
-
-static void UV_OT_select_overlap(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Overlap";
- ot->description = "Select all UV faces which overlap each other";
- ot->idname = "UV_OT_select_overlap";
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- /* api callbacks */
- ot->exec = uv_select_overlap_exec;
- ot->poll = ED_operator_uvedit;
-
- /* properties */
- RNA_def_boolean(ot->srna,
- "extend",
- 0,
- "Extend",
- "Extend selection rather than clearing the existing selection");
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Hide Operator
* \{ */
@@ -4714,99 +1487,107 @@ static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop
static int uv_hide_exec(bContext *C, wmOperator *op)
{
- SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
const bool swap = RNA_boolean_get(op->ptr, "unselected");
- Image *ima = sima ? sima->image : NULL;
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ 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);
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_hide(em, swap)) {
- EDBM_update_generic(obedit->data, true, false);
- }
- return OPERATOR_FINISHED;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- int hide = 0;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
- continue;
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_hide(em, swap)) {
+ EDBM_update_generic(ob->data, true, false);
+ }
+ return OPERATOR_FINISHED;
}
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ int hide = 0;
- if (UV_SEL_TEST(luv, !swap)) {
- hide = 1;
- break;
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
}
- }
- if (hide) {
- /* note, a special case for edges could be used,
- * for now edges act like verts and get flushed */
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- /* check that every UV is selected */
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_face_select_set(em->bm, efa, false);
- }
- uvedit_face_select_disable(scene, em, efa, 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 (UV_SEL_TEST(luv, !swap)) {
+ hide = 1;
+ break;
}
- else {
- if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
+ }
+
+ if (hide) {
+ /* note, a special case for edges could be used,
+ * for now edges act like verts and get flushed */
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
+ /* check that every UV is selected */
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+ else {
+ if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
}
}
+ if (!swap) {
+ uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
}
- if (!swap) {
+ }
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ /* check if a UV is de-selected */
+ if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
+ BM_face_select_set(em->bm, efa, false);
uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
}
}
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- /* check if a UV is de-selected */
- if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
- BM_face_select_set(em->bm, efa, false);
- uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
- }
- }
- else {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- if (UV_SEL_TEST(luv, !swap)) {
- BM_vert_select_set(em->bm, l->v, false);
- if (!swap) {
- luv->flag &= ~MLOOPUV_VERTSEL;
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (UV_SEL_TEST(luv, !swap)) {
+ BM_vert_select_set(em->bm, l->v, false);
+ if (!swap) {
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
}
}
}
}
}
- }
- /* flush vertex selection changes */
- if (em->selectmode != SCE_SELECT_FACE) {
- EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
- }
+ /* flush vertex selection changes */
+ if (em->selectmode != SCE_SELECT_FACE) {
+ EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX | SCE_SELECT_EDGE);
+ }
+
+ BM_select_history_validate(em->bm);
- BM_select_history_validate(em->bm);
+ DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -4837,119 +1618,131 @@ static void UV_OT_hide(wmOperatorType *ot)
static int uv_reveal_exec(bContext *C, wmOperator *op)
{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceImage *sima = CTX_wm_space_image(C);
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
const ToolSettings *ts = scene->toolsettings;
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+
const int use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
const int stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
+ const bool select = RNA_boolean_get(op->ptr, "select");
- const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ 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);
- const bool select = RNA_boolean_get(op->ptr, "select");
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *ob = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
- /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
- * confuse our checks on selected verts. */
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
- /* call the mesh function if we are in mesh sync sel */
- if (ts->uv_flag & UV_SYNC_SELECTION) {
- if (EDBM_mesh_reveal(em, select)) {
- EDBM_update_generic(obedit->data, true, false);
- }
- return OPERATOR_FINISHED;
- }
- if (use_face_center) {
- if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
- }
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
- }
+ /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
+ * confuse our checks on selected verts. */
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (EDBM_mesh_reveal(em, select)) {
+ EDBM_update_generic(ob->data, true, false);
}
+ return OPERATOR_FINISHED;
}
- else {
- /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
- if (!stickymode) {
+ if (use_face_center) {
+ if (em->selectmode == SCE_SELECT_FACE) {
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- int totsel = 0;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
}
-
- if (!totsel) {
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ }
+ }
+ }
+ else {
+ /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
+ if (!stickymode) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ int totsel = 0;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
+ }
+
+ if (!totsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
}
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
+ !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
}
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
}
}
- }
- else if (em->selectmode == SCE_SELECT_FACE) {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else if (em->selectmode == SCE_SELECT_FACE) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
- }
- else {
- BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(efa, BM_ELEM_TAG);
- if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ else {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ SET_FLAG_FROM_TEST(luv->flag, select, MLOOPUV_VERTSEL);
+ }
}
+ /* BM_face_select_set(em->bm, efa, true); */
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
- /* BM_face_select_set(em->bm, efa, true); */
- BM_elem_flag_enable(efa, BM_ELEM_TAG);
}
}
- }
- /* re-select tagged faces */
- BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+ /* re-select tagged faces */
+ BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
+
+ DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
- DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -5050,11 +1843,12 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
{
+ Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- int ret = OPERATOR_CANCELLED;
const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
+ bool changed_multi = false;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -5065,111 +1859,76 @@ static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
Mesh *me = (Mesh *)ob->data;
BMEditMesh *em = me->edit_mesh;
BMesh *bm = em->bm;
-
- UvVertMap *vmap;
- BMEdge *editedge;
BMIter iter;
if (!EDBM_uv_check(em)) {
continue;
}
- ret = OPERATOR_FINISHED;
-
- /* This code sets editvert->tmp.l to the index. This will be useful later on. */
- BM_mesh_elem_table_ensure(bm, BM_FACE);
- vmap = BM_uv_vert_map_create(bm, limit, false, false);
-
- BM_ITER_MESH (editedge, &iter, bm, BM_EDGES_OF_MESH) {
- /* flags to determine if we uv is separated from first editface match */
- char separated1 = 0, separated2;
- /* set to denote edge must be flagged as seam */
- char faces_separated = 0;
- /* flag to keep track if uv1 is disconnected from first editface match */
- char v1coincident = 1;
- /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
- int commonFaces = 0;
-
- BMFace *efa1, *efa2;
-
- UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
- /* mv2cache stores the first of the list of coincident uv's for later comparison
- * mv2sep holds the last separator and is copied to mv2cache
- * when a hit is first found */
- UvMapVert *mv2cache = NULL, *mv2sep = NULL;
-
- mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)];
- if (mark_seams) {
- BM_elem_flag_disable(editedge, BM_ELEM_SEAM);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, f)) {
+ continue;
}
- for (mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
- if (mv1->separate && commonFaces) {
- v1coincident = 0;
+ BMLoop *l_iter;
+ BMLoop *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (l_iter == l_iter->radial_next) {
+ continue;
+ }
+ if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
+ continue;
}
- separated2 = 0;
- efa1 = BM_face_at_index(bm, mv1->poly_index);
- mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)];
+ const MLoopUV *luv_curr = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
+ const MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l_iter->next, cd_loop_uv_offset);
- for (mv2 = mvinit2; mv2; mv2 = mv2->next) {
- if (mv2->separate) {
- mv2sep = mv2;
+ bool mark = false;
+ BMLoop *l_other = l_iter->radial_next;
+ do {
+ const MLoopUV *luv_other_curr = BM_ELEM_CD_GET_VOID_P(l_other, cd_loop_uv_offset);
+ const MLoopUV *luv_other_next = BM_ELEM_CD_GET_VOID_P(l_other->next, cd_loop_uv_offset);
+ if (l_iter->v != l_other->v) {
+ SWAP(const MLoopUV *, luv_other_curr, luv_other_next);
}
- efa2 = BM_face_at_index(bm, mv2->poly_index);
- if (efa1 == efa2) {
- /* if v1 is not coincident no point in comparing */
- if (v1coincident) {
- /* have we found previously anything? */
- if (mv2cache) {
- /* flag seam unless proved to be coincident with previous hit */
- separated2 = 1;
- for (mviter = mv2cache; mviter; mviter = mviter->next) {
- if (mviter->separate && mviter != mv2cache) {
- break;
- }
- /* coincident with previous hit, do not flag seam */
- if (mviter == mv2) {
- separated2 = 0;
- }
- }
- }
- /* First hit case, store the hit in the cache */
- else {
- mv2cache = mv2sep;
- commonFaces = 1;
- }
- }
- else {
- separated1 = 1;
- }
+ if (!compare_ff(luv_curr->uv[0], luv_other_curr->uv[0], limit[0]) ||
+ !compare_ff(luv_curr->uv[1], luv_other_curr->uv[1], limit[1]) ||
- if (separated1 || separated2) {
- faces_separated = 1;
- break;
- }
+ !compare_ff(luv_next->uv[0], luv_other_next->uv[0], limit[0]) ||
+ !compare_ff(luv_next->uv[1], luv_other_next->uv[1], limit[1])) {
+ mark = true;
+ break;
}
- }
- }
+ } while ((l_other = l_other->radial_next) != l_iter);
- if (faces_separated) {
- if (mark_seams) {
- BM_elem_flag_enable(editedge, BM_ELEM_SEAM);
- }
- if (mark_sharp) {
- BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH);
+ if (mark) {
+ if (mark_seams) {
+ BM_elem_flag_enable(l_iter->e, BM_ELEM_SEAM);
+ }
+ if (mark_sharp) {
+ BM_elem_flag_disable(l_iter->e, BM_ELEM_SMOOTH);
+ }
+ changed = true;
}
- }
+ } while ((l_iter = l_iter->next) != l_first);
}
- BM_uv_vert_map_free(vmap);
-
- DEG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ if (changed) {
+ changed_multi = true;
+ DEG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+ }
}
MEM_freeN(objects);
- return ret;
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static void UV_OT_seams_from_islands(wmOperatorType *ot)
@@ -5228,10 +1987,12 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
- if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
- BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
- changed = true;
+ if (uvedit_face_visible_test(scene, efa)) {
+ BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
+ BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
+ changed = true;
+ }
}
}
}
@@ -5308,6 +2069,7 @@ static void UV_OT_mark_seam(wmOperatorType *ot)
void ED_operatortypes_uvedit(void)
{
+ /* uvedit_select.c */
WM_operatortype_append(UV_OT_select_all);
WM_operatortype_append(UV_OT_select);
WM_operatortype_append(UV_OT_select_loop);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 936ba750266..da8e0efa522 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -107,7 +107,7 @@ typedef struct PVert {
struct PEdge *edge;
float co[3];
float uv[2];
- unsigned char flag;
+ uchar flag;
} PVert;
@@ -126,7 +126,7 @@ typedef struct PEdge {
struct PEdge *next;
struct PFace *face;
float *orig_uv, old_uv[2];
- unsigned short flag;
+ ushort flag;
} PEdge;
@@ -141,7 +141,7 @@ typedef struct PFace {
} u;
struct PEdge *edge;
- unsigned char flag;
+ uchar flag;
} PFace;
enum PVertFlag {
@@ -197,7 +197,7 @@ typedef struct PChart {
} pack;
} u;
- unsigned char flag;
+ uchar flag;
struct PHandle *handle;
} PChart;
@@ -245,7 +245,7 @@ static int PHashSizes[] = {
1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
};
-#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((unsigned int)(ph)->cursize))
+#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((uint)(ph)->cursize))
#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39))
static PHash *phash_new(PHashLink **list, int sizehint)
@@ -511,7 +511,7 @@ static void p_chart_uv_transform(PChart *chart, float mat[2][2])
static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
{
PVert *v;
- unsigned int i = 0;
+ uint i = 0;
for (v = chart->verts; v; v = v->nextlink) {
copy_v2_v2(points[i++], v->uv);
@@ -521,7 +521,7 @@ static void p_chart_uv_to_array(PChart *chart, float (*points)[2])
static void UNUSED_FUNCTION(p_chart_uv_from_array)(PChart *chart, float (*points)[2])
{
PVert *v;
- unsigned int i = 0;
+ uint i = 0;
for (v = chart->verts; v; v = v->nextlink) {
copy_v2_v2(v->uv, points[i++]);
@@ -4409,8 +4409,8 @@ static void p_add_ngon(ParamHandle *handle,
PHandle *phandle = (PHandle *)handle;
MemArena *arena = phandle->polyfill_arena;
Heap *heap = phandle->polyfill_heap;
- unsigned int nfilltri = nverts - 2;
- unsigned int(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
+ uint nfilltri = nverts - 2;
+ uint(*tris)[3] = BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri);
float(*projverts)[2] = BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts);
/* Calc normal, flipped: to get a positive 2d cross product. */
@@ -4441,10 +4441,10 @@ static void p_add_ngon(ParamHandle *handle,
/* Add triangles. */
for (int j = 0; j < nfilltri; j++) {
- unsigned int *tri = tris[j];
- unsigned int v0 = tri[0];
- unsigned int v1 = tri[1];
- unsigned int v2 = tri[2];
+ uint *tri = tris[j];
+ uint v0 = tri[0];
+ uint v1 = tri[1];
+ uint v2 = tri[2];
ParamKey tri_vkeys[3] = {vkeys[v0], vkeys[v1], vkeys[v2]};
float *tri_co[3] = {co[v0], co[v1], co[v2]};
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h
index 2b80241e6e3..53188ea42bb 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.h
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.h
@@ -21,12 +21,12 @@
* \ingroup eduv
*/
+#include "BLI_sys_types.h" // for intptr_t support
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "BLI_sys_types.h" // for intptr_t support
-
typedef void ParamHandle; /* handle to a set of charts */
typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */
typedef enum ParamBool {
diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c
new file mode 100644
index 00000000000..cc9be9d48c1
--- /dev/null
+++ b/source/blender/editors/uvedit/uvedit_select.c
@@ -0,0 +1,3371 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup eduv
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_alloca.h"
+#include "BLI_blenlib.h"
+#include "BLI_hash.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_lasso_2d.h"
+#include "BLI_math.h"
+#include "BLI_polyfill_2d.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_editmesh.h"
+#include "BKE_layer.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_mapping.h"
+#include "BKE_report.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_select_utils.h"
+#include "ED_uvedit.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_view2d.h"
+
+#include "uvedit_intern.h"
+
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action);
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action);
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select);
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit);
+
+/* -------------------------------------------------------------------- */
+/** \name Visibility and Selection Utilities
+ * \{ */
+
+static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2])
+{
+ uvedit_pixel_to_float(sima, 0.05f, r_limit);
+}
+
+static void uvedit_vertex_select_tagged(BMEditMesh *em,
+ Scene *scene,
+ bool select,
+ int cd_loop_uv_offset)
+{
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ 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(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+}
+
+bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
+ }
+ else {
+ return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+}
+bool uvedit_face_visible_test(const Scene *scene, BMFace *efa)
+{
+ return uvedit_face_visible_test_ex(scene->toolsettings, efa);
+}
+
+bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (!(luv->flag & MLOOPUV_VERTSEL)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset)
+{
+ return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset);
+}
+
+bool uvedit_face_select_set(const struct Scene *scene,
+ struct BMEditMesh *em,
+ struct BMFace *efa,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
+ }
+ else {
+ return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
+ }
+}
+
+bool uvedit_face_select_enable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, true);
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)efa);
+ }
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_face_select_disable(const Scene *scene,
+ BMEditMesh *em,
+ BMFace *efa,
+ const int cd_loop_uv_offset)
+{
+ const ToolSettings *ts = scene->toolsettings;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BM_face_select_set(em->bm, efa, false);
+ }
+ else {
+ BMLoop *l;
+ MLoopUV *luv;
+ BMIter liter;
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
+ }
+ else if (ts->selectmode == SCE_SELECT_EDGE) {
+ return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test(l->v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
+ }
+}
+bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset)
+{
+ return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset);
+}
+
+void uvedit_edge_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+
+{
+ if (select) {
+ uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_edge_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ 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);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->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);
+ }
+
+ if (do_history) {
+ BM_select_history_store(em->bm, (BMElem *)l->e);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag |= MLOOPUV_VERTSEL;
+ luv2->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_edge_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ 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, false);
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BM_edge_select_set(em->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);
+ }
+ }
+ else {
+ MLoopUV *luv1, *luv2;
+
+ luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ luv1->flag &= ~MLOOPUV_VERTSEL;
+ luv2->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
+ }
+ else {
+ return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ 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);
+}
+
+void uvedit_uv_select_set(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ const bool select,
+ const bool do_history,
+ const int cd_loop_uv_offset)
+{
+ if (select) {
+ uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
+ }
+ else {
+ uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
+ }
+}
+
+void uvedit_uv_select_enable(BMEditMesh *em,
+ const Scene *scene,
+ 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);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, true);
+ }
+
+ if (do_history) {
+ BM_select_history_remove(em->bm, (BMElem *)l->v);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+}
+
+void uvedit_uv_select_disable(BMEditMesh *em,
+ const Scene *scene,
+ BMLoop *l,
+ 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, false);
+ }
+ else {
+ BM_vert_select_set(em->bm, l->v, false);
+ }
+ }
+ else {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Find Nearest Elements
+ * \{ */
+
+bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv, *luv_next;
+ int i;
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+
+ const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
+
+ if (dist_test_sq < hit->dist_sq) {
+ hit->efa = efa;
+
+ hit->l = l;
+ hit->luv = luv;
+ hit->luv_next = luv_next;
+ hit->lindex = i;
+
+ hit->dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_edge_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_edge(scene, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ bool found = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+
+ const float dist_test_sq = len_squared_v2v2(co, cent);
+
+ if (dist_test_sq < hit.dist_sq) {
+ hit.efa = efa;
+ hit.dist_sq = dist_test_sq;
+ found = true;
+ }
+ }
+ }
+ if (found) {
+ *hit_final = hit;
+ }
+ return found;
+}
+
+bool uv_find_nearest_face_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_face(scene, obedit, co, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset)
+{
+ const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
+ const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv;
+ const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
+
+ return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) &&
+ (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
+}
+
+bool uv_find_nearest_vert(Scene *scene,
+ Object *obedit,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+
+ /* this will fill in hit.vert1 and hit.vert2 */
+ float dist_sq_init = hit_final->dist_sq;
+ UvNearestHit hit = *hit_final;
+ if (uv_find_nearest_edge(scene, obedit, co, &hit)) {
+ hit.dist_sq = dist_sq_init;
+
+ hit.l = NULL;
+ hit.luv = hit.luv_next = NULL;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter;
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ BMIter liter;
+ BMLoop *l;
+ int i;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+ float dist_test_sq;
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
+ dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist;
+ dist_test_sq = square_f(dist_test_sq);
+ }
+ else {
+ dist_test_sq = len_squared_v2v2(co, luv->uv);
+ }
+
+ if (dist_test_sq <= hit.dist_sq) {
+ if (dist_test_sq == hit.dist_sq) {
+ if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
+ continue;
+ }
+ }
+
+ hit.dist_sq = dist_test_sq;
+
+ hit.l = l;
+ hit.luv = luv;
+ hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
+ hit.efa = efa;
+ hit.lindex = i;
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (found) {
+ *hit_final = hit;
+ }
+
+ return found;
+}
+
+bool uv_find_nearest_vert_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ float const co[2],
+ const float penalty_dist,
+ UvNearestHit *hit_final)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) {
+ hit_final->ob = obedit;
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool ED_uvedit_nearest_uv(
+ const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2])
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter;
+ BMFace *efa;
+ const float *uv_best = NULL;
+ float dist_best = *dist_sq;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(efa);
+ do {
+ const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv;
+ const float dist_test = len_squared_v2v2(co, uv);
+ if (dist_best > dist_test) {
+ dist_best = dist_test;
+ uv_best = uv;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ if (uv_best != NULL) {
+ copy_v2_v2(r_uv, uv_best);
+ *dist_sq = dist_best;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool ED_uvedit_nearest_uv_multi(const Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float co[2],
+ float *dist_sq,
+ float r_uv[2])
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) {
+ found = true;
+ }
+ }
+ return found;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select
+ * \{ */
+
+static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
+{
+ UvMapVert *iterv;
+ int count = 0;
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate && iterv != first) {
+ break;
+ }
+
+ count++;
+ }
+
+ if (count < 5) {
+ first->flag = 1;
+ }
+}
+
+static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
+{
+ UvMapVert *iterv, *first;
+ first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ for (iterv = first; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ first = iterv;
+ }
+ if (iterv->poly_index == BM_elem_index_get(efa)) {
+ return first;
+ }
+ }
+
+ return NULL;
+}
+
+static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em,
+ UvMapVert *first1,
+ UvMapVert *first2,
+ int *totface)
+{
+ UvMapVert *iterv1, *iterv2;
+ BMFace *efa;
+ int tot = 0;
+
+ /* count number of faces this edge has */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ /* if face already tagged, don't do this edge */
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ return false;
+ }
+
+ tot++;
+ break;
+ }
+ }
+ }
+
+ if (*totface == 0) { /* start edge */
+ *totface = tot;
+ }
+ else if (tot != *totface) { /* check for same number of faces as start edge */
+ return false;
+ }
+
+ /* tag the faces */
+ for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
+ if (iterv1->separate && iterv1 != first1) {
+ break;
+ }
+
+ for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
+ if (iterv2->separate && iterv2 != first2) {
+ break;
+ }
+
+ if (iterv1->poly_index == iterv2->poly_index) {
+ efa = BM_face_at_index(em->bm, iterv1->poly_index);
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int uv_select_edgeloop(
+ Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMIter iter, liter;
+ BMLoop *l;
+ UvVertMap *vmap;
+ UvMapVert *iterv_curr;
+ UvMapVert *iterv_next;
+ int starttotf;
+ bool looking, select;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* setup */
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+
+ if (!extend) {
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
+ }
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* set flags for first face and verts */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+
+ starttotf = 0;
+ uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
+
+ /* sorry, first edge isn't even ok */
+ looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
+
+ /* iterate */
+ while (looking) {
+ looking = false;
+
+ /* find correct valence edges which are not tagged yet, but connect to tagged one */
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ /* check face not hidden and not tagged */
+ if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) {
+ continue;
+ }
+ if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) {
+ continue;
+ }
+
+ /* check if vertex is tagged and has right valence */
+ if (iterv_curr->flag || iterv_next->flag) {
+ if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
+ looking = true;
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+
+ uv_select_edgeloop_vertex_loop_flag(iterv_curr);
+ uv_select_edgeloop_vertex_loop_flag(iterv_next);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* do the actual select/deselect */
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
+ iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
+ iterv_curr->flag = 1;
+ iterv_next->flag = 1;
+
+ if (extend) {
+ select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
+ }
+ else {
+ select = true;
+ }
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
+
+ if (iterv_curr->flag) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ /* cleanup */
+ BM_uv_vert_map_free(vmap);
+
+ return (select) ? 1 : -1;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked
+ * \{ */
+
+static void uv_select_linked_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ const float limit[2],
+ UvNearestHit *hit_final,
+ bool extend,
+ bool deselect,
+ bool toggle,
+ bool select_faces)
+{
+ /* loop over objects, or just use hit_final->ob */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ if (hit_final && ob_index != 0) {
+ break;
+ }
+ Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ int i, stacksize = 0, *stack;
+ uint a;
+ char *flag;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
+
+ /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
+ * this made *every* projection split the island into front/back islands.
+ * Keep 'use_winding' to false, see: T50970.
+ *
+ * Better solve this by having a delimit option for select-linked operator,
+ * keeping island-select working as is. */
+ vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
+
+ if (vmap == NULL) {
+ continue;
+ }
+
+ stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
+ flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
+
+ if (hit_final == NULL) {
+ /* Use existing selection */
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (uvedit_face_visible_test(scene, efa)) {
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (efa == hit_final->efa) {
+ stack[stacksize] = a;
+ stacksize++;
+ flag[a] = 1;
+ break;
+ }
+ }
+ }
+
+ while (stacksize > 0) {
+
+ stacksize--;
+ a = stack[stacksize];
+
+ efa = BM_face_at_index(em->bm, a);
+
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
+
+ /* make_uv_vert_map_EM sets verts tmp.l to the indices */
+ vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ startv = vlist;
+
+ for (iterv = vlist; iterv; iterv = iterv->next) {
+ if (iterv->separate) {
+ startv = iterv;
+ }
+ if (iterv->poly_index == a) {
+ break;
+ }
+ }
+
+ for (iterv = startv; iterv; iterv = iterv->next) {
+ if ((startv != iterv) && (iterv->separate)) {
+ break;
+ }
+ else if (!flag[iterv->poly_index]) {
+ flag[iterv->poly_index] = 1;
+ stack[stacksize] = iterv->poly_index;
+ stacksize++;
+ }
+ }
+ }
+ }
+
+ /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */
+ if ((toggle == true) && (extend == false) && (deselect == false)) {
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ bool found_selected = false;
+ if (!flag[a]) {
+ continue;
+ }
+
+ if (select_faces) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ found_selected = true;
+ }
+ }
+ else {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ found_selected = true;
+ }
+ }
+
+ if (found_selected) {
+ deselect = true;
+ break;
+ }
+ }
+ }
+ }
+
+#define SET_SELECTION(value) \
+ if (select_faces) { \
+ BM_face_select_set(em->bm, efa, value); \
+ } \
+ else { \
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \
+ luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \
+ } \
+ } \
+ (void)0
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
+ if (!flag[a]) {
+ if (!extend && !deselect && !toggle) {
+ SET_SELECTION(false);
+ }
+ continue;
+ }
+
+ if (!deselect) {
+ SET_SELECTION(true);
+ }
+ else {
+ SET_SELECTION(false);
+ }
+ }
+
+#undef SET_SELECTION
+
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ BM_uv_vert_map_free(vmap);
+ }
+}
+
+/**
+ * \warning This returns first selected UV,
+ * not ideal in many cases since there could be multiple.
+ */
+const float *uvedit_first_selected_uv_from_vertex(Scene *scene,
+ BMVert *eve,
+ const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+
+ 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)) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ return luv->uv;
+ }
+ }
+
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select More/Less Operator
+ * \{ */
+
+static int uv_select_more_less(bContext *C, const bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const ToolSettings *ts = scene->toolsettings;
+
+ 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);
+
+ const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (select) {
+ EDBM_select_more(em, true);
+ }
+ else {
+ EDBM_select_less(em, true);
+ }
+
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ continue;
+ }
+
+ if (is_uv_face_selectmode) {
+
+ /* clear tags */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, efa)) {
+
+#define IS_SEL 1
+#define IS_UNSEL 2
+
+ int sel_state = 0;
+
+ 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_VERTSEL) {
+ sel_state |= IS_SEL;
+ }
+ else {
+ sel_state |= IS_UNSEL;
+ }
+
+ /* if we have a mixed selection, tag to grow it */
+ if (sel_state == (IS_SEL | IS_UNSEL)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ break;
+ }
+ }
+
+#undef IS_SEL
+#undef IS_UNSEL
+ }
+ }
+ }
+ else {
+
+ /* clear tags */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_disable(l, BM_ELEM_TAG);
+ }
+ }
+
+ /* mark loops to be selected */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (uvedit_face_visible_test(scene, efa)) {
+ 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_VERTSEL) != 0) == select) {
+ BM_elem_flag_enable(l->next, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ if (is_uv_face_selectmode) {
+ /* Select tagged faces. */
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ else {
+ /* Select tagged loops. */
+ uv_select_flush_from_tag_loop(sima, scene, obedit, select);
+ }
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, true);
+}
+
+void UV_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select More";
+ ot->description = "Select more UV vertices connected to initial selection";
+ ot->idname = "UV_OT_select_more";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_more_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ return uv_select_more_less(C, false);
+}
+
+void UV_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->description = "Deselect UV vertices at the boundary of each selection region";
+ ot->idname = "UV_OT_select_less";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_less_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name (De)Select All Operator
+ * \{ */
+
+bool uvedit_select_is_any_selected(Scene *scene, Object *obedit)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
+ }
+ else {
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ 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) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len)
+{
+ bool found = false;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ if (uvedit_select_is_any_selected(scene, obedit)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static void uv_select_all_perform(Scene *scene, Object *obedit, int action)
+{
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT;
+ }
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ switch (action) {
+ case SEL_TOGGLE:
+ EDBM_select_toggle_all(em);
+ break;
+ case SEL_SELECT:
+ EDBM_flag_enable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_DESELECT:
+ EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ break;
+ case SEL_INVERT:
+ EDBM_select_swap(em);
+ EDBM_selectmode_flush(em);
+ break;
+ }
+ }
+ else {
+ 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) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ switch (action) {
+ case SEL_SELECT:
+ luv->flag |= MLOOPUV_VERTSEL;
+ break;
+ case SEL_DESELECT:
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ break;
+ case SEL_INVERT:
+ luv->flag ^= MLOOPUV_VERTSEL;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void uv_select_all_perform_multi(Scene *scene,
+ Object **objects,
+ const uint objects_len,
+ int action)
+{
+ if (action == SEL_TOGGLE) {
+ action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT :
+ SEL_SELECT;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_all_perform(scene, obedit, action);
+ }
+}
+
+static int uv_select_all_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ int action = RNA_enum_get(op->ptr, "action");
+
+ 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);
+
+ uv_select_all_perform_multi(scene, objects, objects_len, action);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->description = "Change selection of all UV vertices";
+ ot->idname = "UV_OT_select_all";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_all_exec;
+ ot->poll = ED_operator_uvedit;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Mouse Select Operator
+ * \{ */
+
+static bool uv_sticky_select(
+ float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen)
+{
+ int i;
+
+ /* this function test if some vertex needs to selected
+ * in addition to the existing ones due to sticky select */
+ if (sticky == SI_STICKY_DISABLE) {
+ return false;
+ }
+
+ for (i = 0; i < hitlen; i++) {
+ if (hitv[i] == v) {
+ if (sticky == SI_STICKY_LOC) {
+ if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) {
+ return true;
+ }
+ }
+ else if (sticky == SI_STICKY_VERTEX) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int uv_mouse_select_multi(bContext *C,
+ Object **objects,
+ uint objects_len,
+ const float co[2],
+ const bool extend,
+ const bool deselect_all,
+ const bool loop)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+ int i, selectmode, sticky, sync, *hitv = NULL;
+ bool select = true;
+ bool found_item = false;
+ /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ int flush = 0;
+ int hitlen = 0;
+ float limit[2], **hituv = NULL;
+
+ /* notice 'limit' is the same no matter the zoom level, since this is like
+ * remove doubles and could annoying if it joined points when zoomed out.
+ * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
+ * shift-selecting can consider an adjacent point close enough to add to
+ * the selection rather than de-selecting the closest. */
+
+ float penalty_dist;
+ {
+ float penalty[2];
+ uvedit_pixel_to_float(sima, 0.05f, limit);
+ uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty);
+ penalty_dist = len_v2(penalty);
+ }
+
+ /* retrieve operation mode */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ sync = 1;
+
+ if (ts->selectmode & SCE_SELECT_FACE) {
+ selectmode = UV_SELECT_FACE;
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ selectmode = UV_SELECT_EDGE;
+ }
+ else {
+ selectmode = UV_SELECT_VERTEX;
+ }
+
+ sticky = SI_STICKY_DISABLE;
+ }
+ else {
+ sync = 0;
+ selectmode = ts->uv_selectmode;
+ sticky = (sima) ? sima->sticky : 1;
+ }
+
+ /* find nearest element */
+ if (loop) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ }
+ else if (selectmode == UV_SELECT_VERTEX) {
+ /* find vertex */
+ found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 1 vertex as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hituv[hit.lindex] = hit.luv->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* find edge */
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ /* mark 2 edge vertices as being hit */
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
+
+ hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
+ hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
+ hituv[hit.lindex] = hit.luv->uv;
+ hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* find face */
+ found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+
+ if (found_item) {
+ BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* make active */
+ BM_mesh_active_face_set(em->bm, hit.efa);
+
+ /* mark all face vertices as being hit */
+
+ hitv = BLI_array_alloca(hitv, hit.efa->len);
+ hituv = BLI_array_alloca(hituv, hit.efa->len);
+ BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ hituv[i] = luv->uv;
+ hitv[i] = BM_elem_index_get(l->v);
+ }
+
+ hitlen = hit.efa->len;
+ }
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit);
+ found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist);
+ }
+
+ if (!found_item) {
+ if (deselect_all) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+ }
+
+ Object *obedit = hit.ob;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (loop) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+ flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend);
+ }
+ else if (selectmode == UV_SELECT_ISLAND) {
+ if (!extend) {
+ /* TODO(MULTI_EDIT): We only need to de-select non-active */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+ /* Current behavior of 'extend'
+ * is actually toggling, so pass extend flag as 'toggle' here */
+ uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false);
+ }
+ else if (extend) {
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* (de)select uv vertex */
+ select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* (de)select edge */
+ select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
+ uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* (de)select face */
+ select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
+ uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
+ flush = -1;
+ }
+
+ /* de-selecting an edge may deselect a face too - validate */
+ if (sync) {
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+
+ /* (de)select sticky uv nodes */
+ if (sticky != SI_STICKY_DISABLE) {
+
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
+
+ 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) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+
+ flush = select ? 1 : -1;
+ }
+ }
+ else {
+ /* deselect all */
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+
+ if (selectmode == UV_SELECT_VERTEX) {
+ /* select vertex */
+ uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_EDGE) {
+ /* select edge */
+ uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
+ flush = 1;
+ }
+ else if (selectmode == UV_SELECT_FACE) {
+ /* select face */
+ uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
+ }
+
+ /* select sticky uvs */
+ if (sticky != SI_STICKY_DISABLE) {
+ 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 (sticky == SI_STICKY_DISABLE) {
+ continue;
+ }
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (uv_sticky_select(
+ limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ }
+
+ flush = 1;
+ }
+ }
+ }
+ }
+
+ if (sync) {
+ /* flush for mesh selection */
+
+ /* before bmesh */
+#if 0
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (flush == 1) {
+ EDBM_select_flush(em);
+ }
+ else if (flush == -1) {
+ EDBM_deselect_flush(em);
+ }
+ }
+#else
+ if (flush != 0) {
+ if (loop) {
+ /* push vertex -> edge selection */
+ if (select) {
+ EDBM_select_flush(em);
+ }
+ else {
+ EDBM_deselect_flush(em);
+ }
+ }
+ else {
+ EDBM_selectmode_flush(em);
+ }
+ }
+#endif
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obiter = objects[ob_index];
+ uv_select_tag_update_for_object(depsgraph, ts, obiter);
+ }
+
+ return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
+}
+static int uv_mouse_select(
+ bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop)
+{
+ 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_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+ int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop);
+ MEM_freeN(objects);
+ return ret;
+}
+
+static int uv_select_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool loop = false;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_exec(C, op);
+}
+
+void UV_OT_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select";
+ ot->description = "Select UV vertices";
+ ot->idname = "UV_OT_select";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_exec;
+ ot->invoke = uv_select_invoke;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* properties */
+ PropertyRNA *prop;
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+ prop = RNA_def_boolean(ot->srna,
+ "deselect_all",
+ false,
+ "Deselect On Nothing",
+ "Deselect all when nothing under the cursor");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Loop Select Operator
+ * \{ */
+
+static int uv_select_loop_exec(bContext *C, wmOperator *op)
+{
+ float co[2];
+
+ RNA_float_get_array(op->ptr, "location", co);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool deselect_all = false;
+ const bool loop = true;
+
+ return uv_mouse_select(C, co, extend, deselect_all, loop);
+}
+
+static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ const ARegion *region = CTX_wm_region(C);
+ float co[2];
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+
+ return uv_select_loop_exec(C, op);
+}
+
+void UV_OT_select_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Loop Select";
+ ot->description = "Select a loop of connected UV vertices";
+ ot->idname = "UV_OT_select_loop";
+ ot->flag = OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_loop_exec;
+ ot->invoke = uv_select_loop_invoke;
+ 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(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked Operator
+ * \{ */
+
+static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ float limit[2];
+ bool extend = true;
+ bool deselect = false;
+ bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
+
+ UvNearestHit hit = UV_NEAREST_HIT_INIT;
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Select linked only works in face select mode when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (pick) {
+ extend = RNA_boolean_get(op->ptr, "extend");
+ deselect = RNA_boolean_get(op->ptr, "deselect");
+ }
+ uv_select_island_limit_default(sima, limit);
+
+ 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);
+
+ if (pick) {
+ float co[2];
+
+ if (event) {
+ /* invoke */
+ const ARegion *region = CTX_wm_region(C);
+
+ UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+ RNA_float_set_array(op->ptr, "location", co);
+ }
+ else {
+ /* exec */
+ RNA_float_get_array(op->ptr, "location", co);
+ }
+
+ if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) {
+ MEM_freeN(objects);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ if (!extend) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ uv_select_linked_multi(scene,
+ objects,
+ objects_len,
+ limit,
+ pick ? &hit : NULL,
+ extend,
+ deselect,
+ false,
+ select_faces);
+
+ /* weak!, but works */
+ Object **objects_free = objects;
+ if (pick) {
+ objects = &hit.ob;
+ objects_len = 1;
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
+ }
+
+ MEM_SAFE_FREE(objects_free);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_linked_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, false);
+}
+
+void UV_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->description = "Select all UV vertices linked to the active UV map";
+ ot->idname = "UV_OT_select_linked";
+
+ /* api callbacks */
+ ot->exec = uv_select_linked_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Linked (Cursor Pick) Operator
+ * \{ */
+
+static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ return uv_select_linked_internal(C, op, event, true);
+}
+
+static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
+{
+ return uv_select_linked_internal(C, op, NULL, true);
+}
+
+void UV_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked Pick";
+ ot->description = "Select all UV vertices linked under the mouse";
+ ot->idname = "UV_OT_select_linked_pick";
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->invoke = uv_select_linked_pick_invoke;
+ ot->exec = uv_select_linked_pick_exec;
+ 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_boolean(ot->srna,
+ "deselect",
+ 0,
+ "Deselect",
+ "Deselect linked UV vertices rather than selecting them");
+ RNA_def_float_vector(
+ ot->srna,
+ "location",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
+ -100.0f,
+ 100.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Split Operator
+ * \{ */
+
+/**
+ * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect
+ * but in this case they are not joined to begin with (only having the behavior of being joined)
+ * so its best to call this #uv_select_split() instead of just split(), but assigned to the same
+ * key as #MESH_OT_split - Campbell.
+ */
+static int uv_select_split_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
+ return OPERATOR_CANCELLED;
+ }
+
+ bool changed_multi = false;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
+
+ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+ bool is_sel = false;
+ bool is_unsel = false;
+
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+
+ /* are we all selected? */
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ is_sel = true;
+ }
+ else {
+ is_unsel = true;
+ }
+
+ /* we have mixed selection, bail out */
+ if (is_sel && is_unsel) {
+ break;
+ }
+ }
+
+ if (is_sel && is_unsel) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ luv->flag &= ~MLOOPUV_VERTSEL;
+ }
+
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ changed_multi = true;
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Split";
+ ot->description = "Select only entirely selected faces";
+ ot->idname = "UV_OT_select_split";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_split_exec;
+ ot->poll = ED_operator_uvedit; /* requires space image */
+}
+
+static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select)
+{
+ /* bmesh API handles flushing but not on de-select */
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ if (ts->selectmode != SCE_SELECT_FACE) {
+ if (select == false) {
+ EDBM_deselect_flush(em);
+ }
+ else {
+ EDBM_select_flush(em);
+ }
+ }
+
+ if (select == false) {
+ BM_select_history_validate(em->bm);
+ }
+ }
+}
+
+static void uv_select_tag_update_for_object(Depsgraph *depsgraph,
+ const ToolSettings *ts,
+ Object *obedit)
+{
+ if (ts->uv_flag & UV_SYNC_SELECTION) {
+ DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+ else {
+ Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
+ BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT);
+ /* Only for region redraw. */
+ WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select/Tag Flushing Utils
+ *
+ * Utility functions to flush the uv-selection from tags.
+ * \{ */
+
+/**
+ * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
+ */
+static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene,
+ BMEditMesh *em,
+ UvVertMap *vmap,
+ const uint efa_index,
+ BMLoop *l,
+ const bool select,
+ const int cd_loop_uv_offset)
+{
+ UvMapVert *start_vlist = NULL, *vlist_iter;
+ BMFace *efa_vlist;
+
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+
+ vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
+
+ while (vlist_iter) {
+ if (vlist_iter->separate) {
+ start_vlist = vlist_iter;
+ }
+
+ if (efa_index == vlist_iter->poly_index) {
+ break;
+ }
+
+ vlist_iter = vlist_iter->next;
+ }
+
+ vlist_iter = start_vlist;
+ while (vlist_iter) {
+
+ if (vlist_iter != start_vlist && vlist_iter->separate) {
+ break;
+ }
+
+ if (efa_index != vlist_iter->poly_index) {
+ BMLoop *l_other;
+ efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index);
+ /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
+
+ l_other = BM_iter_at_index(
+ em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index);
+
+ uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
+ }
+ vlist_iter = vlist_iter->next;
+ }
+}
+
+/**
+ * Flush the selection from face tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also
+ * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes
+ * is best done in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_face(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Faces with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ 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);
+ }
+ }
+ }
+}
+
+/**
+ * Flush the selection from loop tags based on sticky and selection modes.
+ *
+ * needed because settings the selection a face is done in a number of places but it also needs
+ * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done
+ * in a separate function.
+ *
+ * \note This function is very similar to #uv_select_flush_from_tag_loop,
+ * be sure to update both upon changing.
+ */
+static void uv_select_flush_from_tag_loop(SpaceImage *sima,
+ Scene *scene,
+ Object *obedit,
+ const bool select)
+{
+ /* Selecting UV Loops with some modes requires us to change
+ * the selection in other faces (depending on the sticky mode).
+ *
+ * This only needs to be done when the Mesh is not used for
+ * selection (so for sticky modes, vertex or location based). */
+
+ const ToolSettings *ts = scene->toolsettings;
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
+ /* Tag all verts as untouched, then touch the ones that have a face center
+ * in the loop and select all MLoopUV's that use a touched vert. */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ 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)) {
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ /* now select tagged verts */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+ else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
+ struct UvVertMap *vmap;
+ float limit[2];
+ uint efa_index;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
+ if (vmap == NULL) {
+ return;
+ }
+
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
+ /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
+
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
+ uv_select_flush_from_tag_sticky_loc_internal(
+ scene, em, vmap, efa_index, l, select, cd_loop_uv_offset);
+ }
+ }
+ }
+ BM_uv_vert_map_free(vmap);
+ }
+ else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+ 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(em, scene, l, select, false, cd_loop_uv_offset);
+ }
+ }
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Box Select Operator
+ * \{ */
+
+static int uv_box_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ rctf rectf;
+ bool pinned;
+ float limit[2];
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &rectf);
+ UI_view2d_region_to_view_rctf(&region->v2d, &rectf, &rectf);
+
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ pinned = RNA_boolean_get(op->ptr, "pinned");
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ 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);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do actual selection */
+ if (use_face_center && !pinned) {
+ /* handle face selection mode */
+ float cent[2];
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ /* assume not touched */
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+
+ if (uvedit_face_visible_test(scene, efa)) {
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (BLI_rctf_isect_pt_v(&rectf, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge && !pinned) {
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ 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);
+ bool luv_select_prev = uvedit_uv_select_test(scene, 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);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (BLI_rctf_isect_pt_v(&rectf, luv->uv) &&
+ BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ /* other selection modes */
+ changed = true;
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ 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(em, scene, 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(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_box(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Box Select";
+ ot->description = "Select UV vertices using box selection";
+ ot->idname = "UV_OT_select_box";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_box_invoke;
+ ot->exec = uv_box_select_exec;
+ ot->modal = WM_gesture_box_modal;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_box_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
+
+ WM_operator_properties_gesture_box(ot);
+ WM_operator_properties_select_operation_simple(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])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co[2] = {
+ (uv[0] - offset[0]) * ellipse[0],
+ (uv[1] - offset[1]) * ellipse[1],
+ };
+ 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])
+{
+ /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+ const float co_a[2] = {
+ (uv_a[0] - offset[0]) * ellipse[0],
+ (uv_a[1] - offset[1]) * ellipse[1],
+ };
+ const float co_b[2] = {
+ (uv_b[0] - offset[0]) * ellipse[0],
+ (uv_b[1] - offset[1]) * ellipse[1],
+ };
+ return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f;
+}
+
+static int uv_circle_select_exec(bContext *C, wmOperator *op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const ToolSettings *ts = scene->toolsettings;
+ const ARegion *region = CTX_wm_region(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+ int x, y, radius, width, height;
+ float zoomx, zoomy;
+ float limit[2], offset[2], ellipse[2];
+
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ /* get operator properties */
+ x = RNA_int_get(op->ptr, "x");
+ y = RNA_int_get(op->ptr, "y");
+ radius = RNA_int_get(op->ptr, "radius");
+
+ /* compute ellipse size and location, not a circle since we deal
+ * with non square image. ellipse is normalized, r = 1.0. */
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
+
+ ellipse[0] = width * zoomx / radius;
+ ellipse[1] = height * zoomy / radius;
+
+ UI_view2d_region_to_view(&region->v2d, x, y, &offset[0], &offset[1]);
+
+ uv_select_island_limit_default(sima, limit);
+
+ bool changed_multi = false;
+
+ 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);
+
+ const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
+ WM_gesture_is_modal_first(op->customdata));
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ bool changed = false;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* do selection */
+ if (use_face_center) {
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (uv_circle_select_is_point_inside(cent, offset, ellipse)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ 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);
+ bool luv_select_prev = uvedit_uv_select_test(scene, 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);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) {
+ changed = true;
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ 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(em, scene, l, select, false, cd_loop_uv_offset);
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void UV_OT_select_circle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Circle Select";
+ ot->description = "Select UV vertices using circle selection";
+ ot->idname = "UV_OT_select_circle";
+
+ /* api callbacks */
+ ot->invoke = WM_gesture_circle_invoke;
+ ot->modal = WM_gesture_circle_modal;
+ ot->exec = uv_circle_select_exec;
+ ot->poll = ED_operator_uvedit_space_image; /* requires space image */
+ ot->cancel = WM_gesture_circle_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_circle(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Lasso Select Operator
+ * \{ */
+
+static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region,
+ const rcti *clip_rect,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const float co_test[2])
+{
+ int co_screen[2];
+ if (UI_view2d_view_to_region_clip(
+ &region->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) &&
+ BLI_rcti_isect_pt_v(clip_rect, co_screen) &&
+ BLI_lasso_is_point_inside(
+ mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) {
+ return true;
+ }
+ return false;
+}
+
+static bool do_lasso_select_mesh_uv(bContext *C,
+ const int mcoords[][2],
+ const int mcoords_len,
+ const eSelectOp sel_op)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const ARegion *region = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_FACE) :
+ (ts->uv_selectmode == UV_SELECT_FACE));
+ const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ?
+ (ts->selectmode == SCE_SELECT_EDGE) :
+ (ts->uv_selectmode == UV_SELECT_EDGE));
+
+ const bool select = (sel_op != SEL_OP_SUB);
+ const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op);
+
+ BMIter iter, liter;
+
+ BMFace *efa;
+ BMLoop *l;
+ float limit[2];
+ bool changed_multi = false;
+ rcti rect;
+
+ uv_select_island_limit_default(sima, limit);
+
+ BLI_lasso_boundbox(&rect, mcoords, mcoords_len);
+
+ 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);
+
+ if (use_pre_deselect) {
+ uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT);
+ }
+
+ /* don't indent to avoid diff noise! */
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+
+ bool changed = false;
+
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ if (use_face_center) { /* Face Center Sel */
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ BM_elem_flag_disable(efa, BM_ELEM_TAG);
+ /* assume not touched */
+ if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
+ float cent[2];
+ uv_poly_center(efa, cent, cd_loop_uv_offset);
+ if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) {
+ BM_elem_flag_enable(efa, BM_ELEM_TAG);
+ changed = true;
+ }
+ }
+ }
+
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (changed) {
+ uv_select_flush_from_tag_face(sima, scene, obedit, select);
+ }
+ }
+ else if (use_edge) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ 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);
+ bool luv_select_prev = uvedit_uv_select_test(scene, 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);
+ const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
+ if ((select != luv_select) || (select != luv_select_prev)) {
+ if (do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv->uv) &&
+ do_lasso_select_mesh_uv_is_point_inside(
+ region, &rect, mcoords, mcoords_len, luv_prev->uv)) {
+ uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
+ uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG);
+ }
+ }
+ l_prev = l;
+ luv_prev = luv;
+ luv_select_prev = luv_select;
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+ else { /* Vert Sel */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
+
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test(scene, efa)) {
+ continue;
+ }
+ bool has_selected = false;
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
+ 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(em, scene, l, select, false, cd_loop_uv_offset);
+ changed = true;
+ BM_elem_flag_enable(l->v, BM_ELEM_TAG);
+ has_selected = true;
+ }
+ }
+ }
+ if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) {
+ UvNearestHit hit = {
+ .ob = obedit,
+ .efa = efa,
+ };
+ uv_select_linked_multi(
+ scene, objects, objects_len, limit, &hit, true, !select, false, false);
+ }
+ }
+
+ if (sima->sticky == SI_STICKY_VERTEX) {
+ uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
+ }
+ }
+
+ if (changed || use_pre_deselect) {
+ changed_multi = true;
+
+ uv_select_sync_flush(ts, em, select);
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return changed_multi;
+}
+
+static int uv_lasso_select_exec(bContext *C, wmOperator *op)
+{
+ int mcoords_len;
+ const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len);
+
+ if (mcoords) {
+ const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
+ bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op);
+ MEM_freeN((void *)mcoords);
+
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+void UV_OT_select_lasso(wmOperatorType *ot)
+{
+ ot->name = "Lasso Select UV";
+ ot->description = "Select UVs using lasso selection";
+ ot->idname = "UV_OT_select_lasso";
+
+ ot->invoke = WM_gesture_lasso_invoke;
+ ot->modal = WM_gesture_lasso_modal;
+ ot->exec = uv_lasso_select_exec;
+ ot->poll = ED_operator_uvedit_space_image;
+ ot->cancel = WM_gesture_lasso_cancel;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_gesture_lasso(ot);
+ WM_operator_properties_select_operation_simple(ot);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Pinned UV's Operator
+ * \{ */
+
+static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ const ToolSettings *ts = scene->toolsettings;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ MLoopUV *luv;
+
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+ bool changed = false;
+
+ 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) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+
+ if (luv->flag & MLOOPUV_PINNED) {
+ uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ uv_select_tag_update_for_object(depsgraph, ts, obedit);
+ }
+ }
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_pinned(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Selected Pinned";
+ ot->description = "Select all pinned UV vertices";
+ ot->idname = "UV_OT_select_pinned";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_pinned_exec;
+ ot->poll = ED_operator_uvedit;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Select Overlap Operator
+ * \{ */
+
+BLI_INLINE uint overlap_hash(const void *overlap_v)
+{
+ const BVHTreeOverlap *overlap = overlap_v;
+
+ /* Designed to treat (A,B) and (B,A) as the same. */
+ int x = overlap->indexA;
+ int y = overlap->indexB;
+ if (x > y) {
+ SWAP(int, x, y);
+ }
+ return BLI_hash_int_2d(x, y);
+}
+
+BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v)
+{
+ const BVHTreeOverlap *a = a_v;
+ const BVHTreeOverlap *b = b_v;
+ return !((a->indexA == b->indexA && a->indexB == b->indexB) ||
+ (a->indexA == b->indexB && a->indexB == b->indexA));
+}
+
+struct UVOverlapData {
+ int ob_index;
+ int face_index;
+ float tri[3][2];
+};
+
+static int uv_select_overlap(bContext *C, const bool extend)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ 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_with_uvs(
+ view_layer, ((View3D *)NULL), &objects_len);
+
+ /* Calculate maximum number of tree nodes and prepare initial selection. */
+ uint uv_tri_len = 0;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ BM_mesh_elem_table_ensure(em->bm, BM_FACE);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ if (!extend) {
+ uv_select_all_perform(scene, obedit, SEL_DESELECT);
+ }
+
+ BMIter iter;
+ BMFace *efa;
+ BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
+ continue;
+ }
+ uv_tri_len += efa->len - 2;
+ }
+ }
+
+ struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len,
+ "UvOverlapData");
+ BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6);
+
+ /* Use a global data index when inserting into the BVH. */
+ int data_index = 0;
+
+ int face_len_alloc = 3;
+ float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords");
+ uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris");
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMIter iter, liter;
+ BMFace *efa;
+ BMLoop *l;
+
+ const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
+
+ /* Triangulate each UV face and store it inside the BVH. */
+ int face_index;
+ BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) {
+
+ if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) {
+ continue;
+ }
+
+ const uint face_len = efa->len;
+ const uint tri_len = face_len - 2;
+
+ if (face_len_alloc < face_len) {
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+ uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords");
+ indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris");
+ face_len_alloc = face_len;
+ }
+
+ int vert_index;
+ BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) {
+ MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ copy_v2_v2(uv_verts[vert_index], luv->uv);
+ }
+
+ BLI_polyfill_calc(uv_verts, face_len, 0, indices);
+
+ for (int t = 0; t < tri_len; t++) {
+ overlap_data[data_index].ob_index = ob_index;
+ overlap_data[data_index].face_index = face_index;
+
+ /* BVH needs 3D, overlap data uses 2D. */
+ const float tri[3][3] = {
+ {UNPACK2(uv_verts[indices[t][0]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][1]]), 0.0f},
+ {UNPACK2(uv_verts[indices[t][2]]), 0.0f},
+ };
+
+ copy_v2_v2(overlap_data[data_index].tri[0], tri[0]);
+ copy_v2_v2(overlap_data[data_index].tri[1], tri[1]);
+ copy_v2_v2(overlap_data[data_index].tri[2], tri[2]);
+
+ BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3);
+ data_index++;
+ }
+ }
+ }
+ BLI_assert(data_index == uv_tri_len);
+
+ MEM_freeN(uv_verts);
+ MEM_freeN(indices);
+
+ BLI_bvhtree_balance(uv_tree);
+
+ uint tree_overlap_len;
+ BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL);
+
+ if (overlap != NULL) {
+ GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len);
+
+ for (int i = 0; i < tree_overlap_len; i++) {
+ /* Skip overlaps against yourself. */
+ if (overlap[i].indexA == overlap[i].indexB) {
+ continue;
+ }
+
+ /* Skip overlaps that have already been tested. */
+ if (!BLI_gset_add(overlap_set, &overlap[i])) {
+ continue;
+ }
+
+ const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA];
+ const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB];
+ Object *obedit_a = objects[o_a->ob_index];
+ Object *obedit_b = objects[o_b->ob_index];
+ BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a);
+ BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b);
+ BMFace *face_a = em_a->bm->ftable[o_a->face_index];
+ BMFace *face_b = em_b->bm->ftable[o_b->face_index];
+ const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV);
+ const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV);
+
+ /* Skip if both faces are already selected. */
+ if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) &&
+ uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) {
+ continue;
+ }
+
+ /* Main tri-tri overlap test. */
+ const float endpoint_bias = -1e-4f;
+ const float(*t1)[2] = o_a->tri;
+ const float(*t2)[2] = o_b->tri;
+ float vi[2];
+ bool result = (
+ /* Don't use 'isect_tri_tri_v2' here
+ * because it's important to ignore overlap at end-points. */
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 ||
+ isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 ||
+ isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 ||
+ isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0);
+
+ if (result) {
+ 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);
+ }
+ }
+
+ BLI_gset_free(overlap_set, NULL);
+ MEM_freeN(overlap);
+ }
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]);
+ }
+
+ BLI_bvhtree_free(uv_tree);
+
+ MEM_freeN(overlap_data);
+ MEM_freeN(objects);
+
+ return OPERATOR_FINISHED;
+}
+
+static int uv_select_overlap_exec(bContext *C, wmOperator *op)
+{
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ return uv_select_overlap(C, extend);
+}
+
+void UV_OT_select_overlap(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Overlap";
+ ot->description = "Select all UV faces which overlap each other";
+ ot->idname = "UV_OT_select_overlap";
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* api callbacks */
+ ot->exec = uv_select_overlap_exec;
+ ot->poll = ED_operator_uvedit;
+
+ /* properties */
+ RNA_def_boolean(ot->srna,
+ "extend",
+ 0,
+ "Extend",
+ "Extend selection rather than clearing the existing selection");
+}
+
+/** \} */
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index cf23cac38a7..594847b7249 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -75,20 +75,20 @@ typedef struct StitchPreviewer {
/* here we'll store the preview triangle indices of the mesh */
float *preview_polys;
/* uvs per polygon. */
- unsigned int *uvs_per_polygon;
+ uint *uvs_per_polygon;
/*number of preview polygons */
- unsigned int num_polys;
+ uint num_polys;
/* preview data. These will be either the previewed vertices or edges
* depending on stitch mode settings */
float *preview_stitchable;
float *preview_unstitchable;
/* here we'll store the number of elements to be drawn */
- unsigned int num_stitchable;
- unsigned int num_unstitchable;
- unsigned int preview_uvs;
+ uint num_stitchable;
+ uint num_unstitchable;
+ uint preview_uvs;
/* ...and here we'll store the static island triangles */
float *static_tris;
- unsigned int num_static_tris;
+ uint num_static_tris;
} StitchPreviewer;
struct IslandStitchData;
@@ -119,16 +119,16 @@ typedef struct IslandStitchData {
/* just for averaging UVs */
typedef struct UVVertAverage {
float uv[2];
- unsigned short count;
+ ushort count;
} UVVertAverage;
typedef struct UvEdge {
/** index to uv buffer */
- unsigned int uv1;
- unsigned int uv2;
+ uint uv1;
+ uint uv2;
/** general use flag
* (Used to check if edge is boundary here, and propagates to adjacency elements) */
- unsigned char flag;
+ uchar flag;
/** element that guarantees element->face
* has the edge on element->tfindex and element->tfindex+1 is the second uv */
UvElement *element;
@@ -172,7 +172,7 @@ typedef struct StitchState {
int selection_size;
/* store number of primitives per face so that we can allocate the active island buffer later */
- unsigned int *tris_per_island;
+ uint *tris_per_island;
/* preview data */
StitchPreviewer *stitch_preview;
} StitchState;
@@ -299,9 +299,9 @@ static void stitch_update_header(StitchStateContainer *ssc, bContext *C)
"shift select vertices");
char msg[UI_MAX_DRAW_STR];
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
- if (sa) {
+ if (area) {
BLI_snprintf(msg,
sizeof(msg),
str,
@@ -544,7 +544,7 @@ static void stitch_island_calculate_edge_rotation(UvEdge *edge,
StitchStateContainer *ssc,
StitchState *state,
UVVertAverage *uv_average,
- unsigned int *uvfinal_map,
+ uint *uvfinal_map,
IslandStitchData *island_stitch_data)
{
BMesh *bm = state->em->bm;
@@ -1032,7 +1032,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
char stitch_midpoints = ssc->midpoints;
/* used to map uv indices to uvaverage indices for selection */
- unsigned int *uvfinal_map = NULL;
+ uint *uvfinal_map = NULL;
/* per face preview position in preview buffer */
PreviewPosition *preview_position = NULL;
@@ -1229,7 +1229,7 @@ static int stitch_process_data(StitchStateContainer *ssc,
BMIter liter;
BMLoop *l;
MLoopUV *luv;
- unsigned int buffer_index = 0;
+ uint buffer_index = 0;
/* initialize the preview buffers */
preview->preview_polys = MEM_mallocN(preview->preview_uvs * sizeof(float) * 2,
@@ -1575,7 +1575,7 @@ static int stitch_process_data_all(StitchStateContainer *ssc, Scene *scene, int
}
/* Stitch hash initialization functions */
-static unsigned int uv_edge_hash(const void *key)
+static uint uv_edge_hash(const void *key)
{
const UvEdge *edge = key;
return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
@@ -1760,14 +1760,14 @@ static void stitch_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), void
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
int j, index = 0;
- unsigned int num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
+ uint num_line = 0, num_tri, tri_idx = 0, line_idx = 0;
StitchState *state = ssc->states[ob_index];
StitchPreviewer *stitch_preview = state->stitch_preview;
GPUVertBuf *vbo, *vbo_line;
float col[4];
static GPUVertFormat format = {0};
- static unsigned int pos_id;
+ static uint pos_id;
if (format.attr_len == 0) {
pos_id = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
}
@@ -2438,7 +2438,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
{
Scene *scene = CTX_data_scene(C);
SpaceImage *sima = CTX_wm_space_image(C);
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
StitchStateContainer *ssc = (StitchStateContainer *)op->customdata;
@@ -2492,7 +2492,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished)
MEM_freeN(objs_selection_count);
}
- if (sa) {
+ if (area) {
ED_workspace_status_text(C, NULL);
}
@@ -2550,12 +2550,11 @@ static StitchState *stitch_select(bContext *C,
float co[2];
UvNearestHit hit = UV_NEAREST_HIT_INIT;
ARegion *region = CTX_wm_region(C);
- Image *ima = CTX_data_edit_image(C);
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
if (ssc->mode == STITCH_VERT) {
- if (uv_find_nearest_vert_multi(scene, ima, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
+ if (uv_find_nearest_vert_multi(scene, ssc->objects, ssc->objects_len, co, 0.0f, &hit)) {
/* Add vertex to selection, deselect all common uv's of vert other than selected and
* update the preview. This behavior was decided so that you can do stuff like deselect
* the opposite stitchable vertex and the initial still gets deselected */
@@ -2576,7 +2575,7 @@ static StitchState *stitch_select(bContext *C,
return state;
}
}
- else if (uv_find_nearest_edge_multi(scene, ima, ssc->objects, ssc->objects_len, co, &hit)) {
+ else if (uv_find_nearest_edge_multi(scene, ssc->objects, ssc->objects_len, co, &hit)) {
/* find StitchState from hit->ob */
StitchState *state = NULL;
for (uint ob_index = 0; ob_index < ssc->objects_len; ob_index++) {
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 8ded2c16be8..c4dcaaaa8b2 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -708,7 +708,7 @@ static bool minimize_stretch_init(bContext *C, wmOperator *op)
static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
{
MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
@@ -724,9 +724,9 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
param_flush(ms->handle);
- if (sa) {
+ if (area) {
BLI_snprintf(str, sizeof(str), TIP_("Minimize Stretch. Blend %.2f"), ms->blend);
- ED_area_status_text(sa, str);
+ ED_area_status_text(area, str);
ED_workspace_status_text(C, TIP_("Press + and -, or scroll wheel to set blending"));
}
@@ -749,12 +749,12 @@ static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interac
static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
{
MinStretch *ms = op->customdata;
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
const Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
- ED_area_status_text(sa, NULL);
+ ED_area_status_text(area, NULL);
ED_workspace_status_text(C, NULL);
if (ms->timer) {