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:
authorYimingWu <xp8110@outlook.com>2019-10-24 15:36:28 +0300
committerYimingWu <xp8110@outlook.com>2019-10-24 15:36:28 +0300
commite910924b37a3fdffeb38ac14c656c16f107a9c0d (patch)
treeab626478bbb650837fd54140cfbb30a04edb6a26 /source/blender/editors
parentf60406ff257c3309418413b5af76373010fb2a6f (diff)
parent42eef8f81a6aea27094985347ab802dc6bb91a61 (diff)
Merge remote-tracking branch 'origin/master' into soc-2019-npr
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c2
-rw-r--r--source/blender/editors/animation/anim_filter.c4
-rw-r--r--source/blender/editors/animation/anim_markers.c69
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c269
-rw-r--r--source/blender/editors/animation/drivers.c55
-rw-r--r--source/blender/editors/animation/keyframes_draw.c3
-rw-r--r--source/blender/editors/animation/keyframing.c2
-rw-r--r--source/blender/editors/armature/armature_select.c9
-rw-r--r--source/blender/editors/armature/pose_edit.c47
-rw-r--r--source/blender/editors/armature/pose_select.c3
-rw-r--r--source/blender/editors/armature/pose_slide.c26
-rw-r--r--source/blender/editors/armature/pose_transform.c221
-rw-r--r--source/blender/editors/armature/pose_utils.c9
-rw-r--r--source/blender/editors/curve/curve_ops.c3
-rw-r--r--source/blender/editors/curve/editcurve.c9
-rw-r--r--source/blender/editors/curve/editcurve_add.c1
-rw-r--r--source/blender/editors/curve/editcurve_paint.c8
-rw-r--r--source/blender/editors/curve/editcurve_select.c10
-rw-r--r--source/blender/editors/curve/editcurve_undo.c2
-rw-r--r--source/blender/editors/curve/editfont.c6
-rw-r--r--source/blender/editors/curve/editfont_undo.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c16
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c4
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gpencil/annotate_paint.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c75
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c29
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h7
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_merge.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_ops_versioning.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c263
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c297
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c106
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c2
-rw-r--r--source/blender/editors/include/ED_anim_api.h20
-rw-r--r--source/blender/editors/include/ED_armature.h10
-rw-r--r--source/blender/editors/include/ED_fileselect.h2
-rw-r--r--source/blender/editors/include/ED_gpencil.h7
-rw-r--r--source/blender/editors/include/ED_image.h2
-rw-r--r--source/blender/editors/include/ED_keyframing.h13
-rw-r--r--source/blender/editors/include/ED_mesh.h14
-rw-r--r--source/blender/editors/include/ED_object.h10
-rw-r--r--source/blender/editors/include/ED_paint.h33
-rw-r--r--source/blender/editors/include/ED_particle.h10
-rw-r--r--source/blender/editors/include/ED_screen.h10
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_interface.h5
-rw-r--r--source/blender/editors/include/UI_resources.h3
-rw-r--r--source/blender/editors/interface/CMakeLists.txt1
-rw-r--r--source/blender/editors/interface/interface.c9
-rw-r--r--source/blender/editors/interface/interface_anim.c2
-rw-r--r--source/blender/editors/interface/interface_context_menu.c39
-rw-r--r--source/blender/editors/interface/interface_draw.c12
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c1
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c4
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c2
-rw-r--r--source/blender/editors/interface/interface_eyedropper_gpencil_color.c324
-rw-r--r--source/blender/editors/interface/interface_handlers.c21
-rw-r--r--source/blender/editors/interface/interface_icons.c1
-rw-r--r--source/blender/editors/interface/interface_icons_event.c7
-rw-r--r--source/blender/editors/interface/interface_intern.h6
-rw-r--r--source/blender/editors/interface/interface_layout.c52
-rw-r--r--source/blender/editors/interface/interface_ops.c9
-rw-r--r--source/blender/editors/interface/interface_query.c46
-rw-r--r--source/blender/editors/interface/interface_region_menu_popup.c2
-rw-r--r--source/blender/editors/interface/interface_region_popover.c3
-rw-r--r--source/blender/editors/interface/interface_region_popup.c2
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/interface/interface_widgets.c10
-rw-r--r--source/blender/editors/interface/resources.c10
-rw-r--r--source/blender/editors/interface/view2d.c2
-rw-r--r--source/blender/editors/interface/view2d_ops.c12
-rw-r--r--source/blender/editors/io/io_alembic.c5
-rw-r--r--source/blender/editors/lattice/editlattice_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c3
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c2
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c1
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c6
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c20
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c1
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c24
-rw-r--r--source/blender/editors/mesh/editmesh_select.c6
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c202
-rw-r--r--source/blender/editors/mesh/mesh_data.c141
-rw-r--r--source/blender/editors/mesh/meshtools.c38
-rw-r--r--source/blender/editors/metaball/mball_edit.c6
-rw-r--r--source/blender/editors/object/object_add.c32
-rw-r--r--source/blender/editors/object/object_bake.c4
-rw-r--r--source/blender/editors/object/object_bake_api.c8
-rw-r--r--source/blender/editors/object/object_collection.c8
-rw-r--r--source/blender/editors/object/object_edit.c60
-rw-r--r--source/blender/editors/object/object_modifier.c4
-rw-r--r--source/blender/editors/object/object_relations.c11
-rw-r--r--source/blender/editors/object/object_remesh.c268
-rw-r--r--source/blender/editors/object/object_select.c4
-rw-r--r--source/blender/editors/object/object_transform.c3
-rw-r--r--source/blender/editors/physics/particle_edit.c350
-rw-r--r--source/blender/editors/physics/particle_edit_undo.c27
-rw-r--r--source/blender/editors/physics/particle_object.c6
-rw-r--r--source/blender/editors/physics/rigidbody_constraint.c8
-rw-r--r--source/blender/editors/physics/rigidbody_object.c2
-rw-r--r--source/blender/editors/render/render_internal.c2
-rw-r--r--source/blender/editors/render/render_preview.c4
-rw-r--r--source/blender/editors/render/render_shading.c14
-rw-r--r--source/blender/editors/render/render_view.c11
-rw-r--r--source/blender/editors/scene/scene_edit.c5
-rw-r--r--source/blender/editors/screen/area.c34
-rw-r--r--source/blender/editors/screen/area_query.c2
-rw-r--r--source/blender/editors/screen/area_utils.c1
-rw-r--r--source/blender/editors/screen/glutil.c2
-rw-r--r--source/blender/editors/screen/screen_context.c8
-rw-r--r--source/blender/editors/screen/screen_draw.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c80
-rw-r--r--source/blender/editors/screen/screen_ops.c64
-rw-r--r--source/blender/editors/screen/screen_user_menu.c24
-rw-r--r--source/blender/editors/screen/workspace_edit.c10
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt2
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c406
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve_undo.c1
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c23
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c22
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c88
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c78
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_undo.c625
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h33
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c10
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c69
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c75
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_color_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c17
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c2246
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h35
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c109
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c1
-rw-r--r--source/blender/editors/sound/sound_ops.c3
-rw-r--r--source/blender/editors/space_action/action_edit.c8
-rw-r--r--source/blender/editors/space_action/action_select.c182
-rw-r--r--source/blender/editors/space_clip/clip_draw.c284
-rw-r--r--source/blender/editors/space_clip/clip_intern.h1
-rw-r--r--source/blender/editors/space_clip/clip_ops.c137
-rw-r--r--source/blender/editors/space_clip/space_clip.c1
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c4
-rw-r--r--source/blender/editors/space_clip/tracking_ops_solve.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops_utils.c4
-rw-r--r--source/blender/editors/space_console/space_console.c4
-rw-r--r--source/blender/editors/space_file/file_intern.h6
-rw-r--r--source/blender/editors/space_file/file_ops.c179
-rw-r--r--source/blender/editors/space_file/file_panels.c54
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_file/filesel.c118
-rw-r--r--source/blender/editors/space_file/space_file.c122
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c14
-rw-r--r--source/blender/editors/space_graph/graph_draw.c4
-rw-r--r--source/blender/editors/space_graph/graph_edit.c10
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt2
-rw-r--r--source/blender/editors/space_image/image_edit.c18
-rw-r--r--source/blender/editors/space_image/image_intern.h3
-rw-r--r--source/blender/editors/space_image/image_ops.c358
-rw-r--r--source/blender/editors/space_image/image_undo.c1058
-rw-r--r--source/blender/editors/space_image/space_image.c2
-rw-r--r--source/blender/editors/space_nla/nla_select.c47
-rw-r--r--source/blender/editors/space_node/drawnode.c46
-rw-r--r--source/blender/editors/space_node/node_add.c2
-rw-r--r--source/blender/editors/space_node/node_draw.c10
-rw-r--r--source/blender/editors/space_node/node_group.c116
-rw-r--r--source/blender/editors/space_node/node_relationships.c2
-rw-r--r--source/blender/editors/space_node/node_select.c108
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c8
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_script/script_edit.c3
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c16
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c50
-rw-r--r--source/blender/editors/space_text/space_text.c4
-rw-r--r--source/blender/editors/space_text/text_format_lua.c34
-rw-r--r--source/blender/editors/space_text/text_format_osl.c10
-rw-r--r--source/blender/editors/space_text/text_format_pov.c10
-rw-r--r--source/blender/editors/space_text/text_format_pov_ini.c6
-rw-r--r--source/blender/editors/space_text/text_format_py.c10
-rw-r--r--source/blender/editors/space_text/text_ops.c4
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c34
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_draw_legacy.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_armature.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_camera.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_empty.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_forcefield.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_light.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c22
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c29
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c14
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c23
-rw-r--r--source/blender/editors/transform/transform.c10
-rw-r--r--source/blender/editors/transform/transform.h1
-rw-r--r--source/blender/editors/transform/transform_convert.c27
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c8
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c3
-rw-r--r--source/blender/editors/transform/transform_convert_object.c12
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c4
-rw-r--r--source/blender/editors/transform/transform_generics.c18
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c57
-rw-r--r--source/blender/editors/transform/transform_input.c4
-rw-r--r--source/blender/editors/transform/transform_ops.c4
-rw-r--r--source/blender/editors/transform/transform_orientations.c1
-rw-r--r--source/blender/editors/transform/transform_snap_object.c5
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c14
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c8
232 files changed, 7038 insertions, 4243 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index d80b96f0d74..8951677b32f 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -3411,7 +3411,7 @@ static void acf_nlatrack_color(bAnimContext *UNUSED(ac), bAnimListElem *ale, flo
}
/* set color for nla track */
- UI_GetThemeColorShade3fv(TH_HEADER, ((nonSolo == false) ? 20 : -20), r_color);
+ UI_GetThemeColorShade3fv(TH_NLA_TRACK, ((nonSolo == false) ? 20 : -20), r_color);
}
/* name for nla track entries */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index afd2cdc2a2b..0fc137295d0 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -3339,7 +3339,7 @@ static void ANIM_OT_channel_select_keys(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Select Channel keyframes";
+ ot->name = "Select Channel Keyframes";
ot->idname = "ANIM_OT_channel_select_keys";
ot->description = "Select all keyframes of channel under mouse";
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 48493c9e961..f73c8a5b71a 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1818,7 +1818,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac,
!(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* Layer visibility - we check both object and base,
* since these may not be in sync yet. */
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
continue;
}
@@ -3017,7 +3017,7 @@ static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_m
*/
if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
/* layer visibility - we check both object and base, since these may not be in sync yet */
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return false;
}
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 8c873eb6b45..36583ecf060 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -486,7 +486,7 @@ static void draw_marker(
float name_y = UI_DPI_FAC * 18;
/* Give an offset to the marker name when selected,
* or when near the current frame (5 frames range, starting from the current one). */
- if ((marker->flag & SELECT) || (IN_RANGE_INCL(marker->frame, cfra - 4, cfra))) {
+ if ((marker->flag & SELECT) || (cfra - 4 <= marker->frame && marker->frame <= cfra)) {
name_y += UI_DPI_FAC * 10;
}
draw_marker_name(fstyle, marker, xpos, name_y);
@@ -1148,33 +1148,48 @@ static void deselect_markers(ListBase *markers)
}
/* select/deselect TimeMarker at current frame */
-static void select_timeline_marker_frame(ListBase *markers, int frame, bool extend)
+static int select_timeline_marker_frame(ListBase *markers,
+ int frame,
+ bool extend,
+ bool wait_to_deselect_others)
{
- TimeMarker *marker, *marker_first = NULL;
+ TimeMarker *marker, *marker_selected = NULL;
+ int ret_val = OPERATOR_FINISHED;
+
+ if (extend) {
+ wait_to_deselect_others = false;
+ }
/* support for selection cycling */
for (marker = markers->first; marker; marker = marker->next) {
if (marker->frame == frame) {
if (marker->flag & SELECT) {
- marker_first = marker->next;
+ marker_selected = marker->next;
break;
}
}
}
- /* if extend is not set, then deselect markers */
- if (extend == false) {
- deselect_markers(markers);
+ if (wait_to_deselect_others && marker_selected) {
+ ret_val = OPERATOR_RUNNING_MODAL;
}
+ /* if extend is not set, then deselect markers */
+ else {
+ if (extend == false) {
+ deselect_markers(markers);
+ }
- LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
- /* this way a not-extend select will always give 1 selected marker */
- if (marker->frame == frame) {
- marker->flag ^= SELECT;
- break;
+ LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_selected) {
+ /* this way a not-extend select will always give 1 selected marker */
+ if (marker->frame == frame) {
+ marker->flag ^= SELECT;
+ break;
+ }
}
+ LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_selected);
}
- LISTBASE_CIRCULAR_FORWARD_END(markers, marker, marker_first);
+
+ return ret_val;
}
static void select_marker_camera_switch(
@@ -1221,17 +1236,17 @@ static void select_marker_camera_switch(
#endif
}
-static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera)
+static int ed_marker_select(
+ bContext *C, const int mval[2], bool extend, bool camera, bool wait_to_deselect_others)
{
ListBase *markers = ED_context_get_markers(C);
- ARegion *ar = CTX_wm_region(C);
View2D *v2d = UI_view2d_fromcontext(C);
+ int ret_val = OPERATOR_FINISHED;
- float mouse_region_x = event->x - ar->winrct.xmin;
- if (region_position_is_over_marker(v2d, markers, mouse_region_x)) {
- float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mouse_region_x);
+ if (region_position_is_over_marker(v2d, markers, mval[0])) {
+ float frame_at_mouse_position = UI_view2d_region_to_view_x(v2d, mval[0]);
int cfra = ED_markers_find_nearest_marker_time(markers, frame_at_mouse_position);
- select_timeline_marker_frame(markers, cfra, extend);
+ ret_val = select_timeline_marker_frame(markers, cfra, extend, wait_to_deselect_others);
select_marker_camera_switch(C, camera, extend, markers, cfra);
}
@@ -1243,17 +1258,22 @@ static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
/* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_val | OPERATOR_PASS_THROUGH;
}
-static int ed_marker_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int ed_marker_select_exec(bContext *C, wmOperator *op)
{
const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
bool camera = false;
#ifdef DURIAN_CAMERA_SWITCH
camera = RNA_boolean_get(op->ptr, "camera");
#endif
- return ed_marker_select(C, event, extend, camera);
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
+
+ return ed_marker_select(C, mval, extend, camera, wait_to_deselect_others);
}
static void MARKER_OT_select(wmOperatorType *ot)
@@ -1266,12 +1286,15 @@ static void MARKER_OT_select(wmOperatorType *ot)
ot->idname = "MARKER_OT_select";
/* api callbacks */
- ot->invoke = ed_marker_select_invoke;
ot->poll = ed_markers_poll_markers_exist;
+ ot->exec = ed_marker_select_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
#ifdef DURIAN_CAMERA_SWITCH
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index bd4886817cd..30bf837f6c0 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -36,6 +36,7 @@
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "DEG_depsgraph_query.h"
#include "GPU_batch.h"
@@ -67,6 +68,37 @@ typedef struct MPathTarget {
/* ........ */
+/* update scene for current frame */
+static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
+{
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
+}
+
+Depsgraph *animviz_depsgraph_build(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ ListBase *targets)
+{
+ /* Allocate dependency graph. */
+ Depsgraph *depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_VIEWPORT);
+
+ /* Make a flat array of IDs for the DEG API. */
+ const int num_ids = BLI_listbase_count(targets);
+ ID **ids = MEM_malloc_arrayN(sizeof(ID *), num_ids, "animviz IDS");
+ int current_id_index = 0;
+ for (MPathTarget *mpt = targets->first; mpt != NULL; mpt = mpt->next) {
+ ids[current_id_index++] = &mpt->ob->id;
+ }
+
+ /* Build graph from all requested IDs. */
+ DEG_graph_build_from_ids(depsgraph, bmain, scene, view_layer, ids, num_ids);
+ MEM_freeN(ids);
+
+ /* Update once so we can access pointers of evaluated animation data. */
+ motionpaths_calc_update_scene(bmain, depsgraph);
+ return depsgraph;
+}
+
/* get list of motion paths to be baked for the given object
* - assumes the given list is ready to be used
*/
@@ -106,24 +138,6 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets)
/* ........ */
-/* update scene for current frame */
-static void motionpaths_calc_update_scene(Main *bmain, struct Depsgraph *depsgraph)
-{
- /* Do all updates
- * - if this is too slow, resort to using a more efficient way
- * that doesn't force complete update, but for now, this is the
- * most accurate way!
- *
- * TODO(segey): Bring back partial updates, which became impossible
- * with the new depsgraph due to unsorted nature of bases.
- *
- * TODO(sergey): Use evaluation context dedicated to motion paths.
- */
- BKE_scene_graph_update_for_newframe(depsgraph, bmain);
-}
-
-/* ........ */
-
/* perform baking for the targets on the current frame */
static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
{
@@ -201,6 +215,135 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe)
}
}
+/* Get pointer to animviz settings for the given target. */
+static bAnimVizSettings *animviz_target_settings_get(MPathTarget *mpt)
+{
+ if (mpt->pchan != NULL) {
+ return &mpt->ob->pose->avs;
+ }
+ return &mpt->ob->avs;
+}
+
+static void motionpath_get_global_framerange(ListBase *targets, int *r_sfra, int *r_efra)
+{
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+ for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
+ *r_sfra = min_ii(*r_sfra, mpt->mpath->start_frame);
+ *r_efra = max_ii(*r_efra, mpt->mpath->end_frame);
+ }
+}
+
+static int motionpath_get_prev_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame <= mpt->mpath->start_frame) {
+ return INT_MAX;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_prev(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->start_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_prev_prev_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_prev_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_prev_keyframe(mpt, fcu_keys, frame);
+}
+
+static int motionpath_get_next_keyframe(MPathTarget *mpt, DLRBT_Tree *fcu_keys, int current_frame)
+{
+ /* If the current frame is outside of the configured motion path range we ignore update of this
+ * motion path by using invalid frame range where start frame is above the end frame. */
+ if (current_frame >= mpt->mpath->end_frame) {
+ return INT_MIN;
+ }
+
+ float current_frame_float = current_frame;
+ DLRBT_Node *node = BLI_dlrbTree_search_next(fcu_keys, compare_ak_cfraPtr, &current_frame_float);
+ if (node == NULL) {
+ return mpt->mpath->end_frame;
+ }
+
+ ActKeyColumn *key_data = (ActKeyColumn *)node;
+ return key_data->cfra;
+}
+
+static int motionpath_get_next_next_keyframe(MPathTarget *mpt,
+ DLRBT_Tree *fcu_keys,
+ int current_frame)
+{
+ int frame = motionpath_get_next_keyframe(mpt, fcu_keys, current_frame);
+ return motionpath_get_next_keyframe(mpt, fcu_keys, frame);
+}
+
+static bool motionpath_check_can_use_keyframe_range(MPathTarget *UNUSED(mpt),
+ AnimData *adt,
+ ListBase *fcurve_list)
+{
+ if (adt == NULL || fcurve_list == NULL) {
+ return false;
+ }
+ /* NOTE: We might needed to do a full frame range update if there is a specific setup of NLA
+ * or drivers or modifiers on the f-curves. */
+ return true;
+}
+
+static void motionpath_calculate_update_range(MPathTarget *mpt,
+ AnimData *adt,
+ ListBase *fcurve_list,
+ int current_frame,
+ int *r_sfra,
+ int *r_efra)
+{
+ /* Similar to the case when there is only a single keyframe: need to update en entire range to
+ * a constant value. */
+ if (!motionpath_check_can_use_keyframe_range(mpt, adt, fcurve_list)) {
+ *r_sfra = mpt->mpath->start_frame;
+ *r_efra = mpt->mpath->end_frame;
+ return;
+ }
+
+ *r_sfra = INT_MAX;
+ *r_efra = INT_MIN;
+
+ /* NOTE: Iterate over individual f-curves, and check their keyframes individually and pick a
+ * widest range from them. This is because it's possible to have more narrow keyframe on a
+ * channel which wasn't edited.
+ * Could be optimized further by storing some flags about which channels has been modified so
+ * we ignore all others (which can potentially make an update range unnecessary wide). */
+ for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
+ DLRBT_Tree fcu_keys;
+ BLI_dlrbTree_init(&fcu_keys);
+ fcurve_to_keylist(adt, fcu, &fcu_keys, 0);
+
+ int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, current_frame);
+ int fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, current_frame);
+
+ /* Extend range furher, since accelleration compensation propagates even further away. */
+ if (fcu->auto_smoothing != FCURVE_SMOOTH_NONE) {
+ fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, &fcu_keys, fcu_sfra);
+ fcu_efra = motionpath_get_next_next_keyframe(mpt, &fcu_keys, fcu_efra);
+ }
+
+ if (fcu_sfra <= fcu_efra) {
+ *r_sfra = min_ii(*r_sfra, fcu_sfra);
+ *r_efra = max_ii(*r_efra, fcu_efra);
+ }
+
+ BLI_dlrbTree_free(&fcu_keys);
+ }
+}
+
/* Perform baking of the given object's and/or its bones' transforms to motion paths
* - scene: current scene
* - ob: object whose flagged motionpaths should get calculated
@@ -211,39 +354,36 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
Main *bmain,
Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only)
+ eAnimvizCalcRange range,
+ bool restore)
{
- /* sanity check */
+ /* Sanity check. */
if (ELEM(NULL, targets, targets->first)) {
return;
}
- /* Compute frame range to bake within.
- * TODO: this method could be improved...
- * 1) max range for standard baking
- * 2) minimum range for recalc baking (i.e. between keyframes, but how?) */
- int sfra = INT_MAX;
- int efra = INT_MIN;
-
- for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- /* try to increase area to do (only as much as needed) */
- sfra = MIN2(sfra, mpt->mpath->start_frame);
- efra = MAX2(efra, mpt->mpath->end_frame);
- }
-
- if (efra <= sfra) {
- return;
- }
-
- /* Limit frame range if we are updating just the current frame. */
- /* set frame values */
- int cfra = CFRA;
- if (current_frame_only) {
- if (cfra < sfra || cfra > efra) {
- return;
- }
- sfra = efra = cfra;
+ const int cfra = CFRA;
+ int sfra = INT_MAX, efra = INT_MIN;
+ switch (range) {
+ case ANIMVIZ_CALC_RANGE_CURRENT_FRAME:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ if (cfra < sfra || cfra > efra) {
+ return;
+ }
+ sfra = efra = cfra;
+ break;
+ case ANIMVIZ_CALC_RANGE_CHANGED:
+ /* Nothing to do here, will be handled later when iterating through the targets. */
+ break;
+ case ANIMVIZ_CALC_RANGE_FULL:
+ motionpath_get_global_framerange(targets, &sfra, &efra);
+ if (sfra > efra) {
+ return;
+ }
+ break;
}
/* get copies of objects/bones to get the calculated results from
@@ -271,16 +411,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* build list of all keyframes in active action for object or pchan */
BLI_dlrbTree_init(&mpt->keys);
+ ListBase *fcurve_list = NULL;
if (adt) {
- bAnimVizSettings *avs;
-
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* it is assumed that keyframes for bones are all grouped in a single group
* unless an option is set to always use the whole action
@@ -289,13 +423,28 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
bActionGroup *agrp = BKE_action_group_find_name(adt->action, mpt->pchan->name);
if (agrp) {
+ fcurve_list = &agrp->channels;
agroup_to_keylist(adt, agrp, &mpt->keys, 0);
}
}
else {
+ fcurve_list = &adt->action->curves;
action_to_keylist(adt, adt->action, &mpt->keys, 0);
}
}
+
+ if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
+ int mpt_sfra, mpt_efra;
+ motionpath_calculate_update_range(mpt, adt, fcurve_list, cfra, &mpt_sfra, &mpt_efra);
+ if (mpt_sfra <= mpt_efra) {
+ sfra = min_ii(sfra, mpt_sfra);
+ efra = max_ii(efra, mpt_efra);
+ }
+ }
+ }
+
+ if (sfra > efra) {
+ return;
}
/* calculate path over requested range */
@@ -306,7 +455,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
efra,
efra - sfra + 1);
for (CFRA = sfra; CFRA <= efra; CFRA++) {
- if (current_frame_only) {
+ if (range == ANIMVIZ_CALC_RANGE_CURRENT_FRAME) {
/* For current frame, only update tagged. */
BKE_scene_graph_update_tagged(depsgraph, bmain);
}
@@ -324,7 +473,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
* may be a temporary one that works on a subset of the data.
* We always have to restore the current frame though. */
CFRA = cfra;
- if (!current_frame_only && restore) {
+ if (range != ANIMVIZ_CALC_RANGE_CURRENT_FRAME && restore) {
motionpaths_calc_update_scene(bmain, depsgraph);
}
@@ -334,16 +483,10 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
/* clear recalc flags from targets */
for (MPathTarget *mpt = targets->first; mpt; mpt = mpt->next) {
- bAnimVizSettings *avs;
bMotionPath *mpath = mpt->mpath;
/* get pointer to animviz settings for each target */
- if (mpt->pchan) {
- avs = &mpt->ob->pose->avs;
- }
- else {
- avs = &mpt->ob->avs;
- }
+ bAnimVizSettings *avs = animviz_target_settings_get(mpt);
/* clear the flag requesting recalculation of targets */
avs->recalc &= ~ANIMVIZ_RECALC_PATHS;
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 7b9e6a10f44..64f7fe034dc 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -62,13 +62,11 @@
/* Get (or add relevant data to be able to do so) F-Curve from the driver stack,
* for the given Animation Data block. This assumes that all the destinations are valid.
- *
- * - add: 0 - don't add anything if not found,
- * 1 - add new Driver FCurve (with keyframes for visual tweaking),
- * 2 - add new Driver FCurve (with generator, for script backwards compatibility)
- * -1 - add new Driver FCurve without driver stuff (for pasting)
*/
-FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_index, short add)
+FCurve *verify_driver_fcurve(ID *id,
+ const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
AnimData *adt;
FCurve *fcu;
@@ -80,7 +78,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
/* init animdata if none available yet */
adt = BKE_animdata_from_id(id);
- if ((adt == NULL) && (add)) {
+ if (adt == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
adt = BKE_animdata_add_id(id);
}
if (adt == NULL) {
@@ -94,9 +92,9 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
*/
fcu = list_find_fcurve(&adt->drivers, rna_path, array_index);
- if ((fcu == NULL) && (add)) {
+ if (fcu == NULL && creation_mode != DRIVER_FCURVE_LOOKUP_ONLY) {
/* use default settings to make a F-Curve */
- fcu = alloc_driver_fcurve(rna_path, array_index, add);
+ fcu = alloc_driver_fcurve(rna_path, array_index, creation_mode);
/* just add F-Curve to end of driver list */
BLI_addtail(&adt->drivers, fcu);
@@ -106,12 +104,14 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
return fcu;
}
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add)
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode)
{
FCurve *fcu = MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
/* store path - make copy, and store that */
if (rna_path) {
@@ -119,18 +119,12 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
}
fcu->array_index = array_index;
- /* If add is negative, don't init this data yet,
- * since it will be filled in by the pasted driver. */
- if (add > 0) {
- BezTriple *bezt;
- size_t i;
-
+ if (!ELEM(creation_mode, DRIVER_FCURVE_LOOKUP_ONLY, DRIVER_FCURVE_EMPTY)) {
/* add some new driver data */
fcu->driver = MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
/* F-Modifier or Keyframes? */
- // FIXME: replace these magic numbers with defines
- if (add == 2) {
+ if (creation_mode == DRIVER_FCURVE_GENERATOR) {
/* Python API Backwards compatibility hack:
* Create FModifier so that old scripts won't break
* for now before 2.7 series -- (September 4, 2013)
@@ -142,14 +136,10 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index,
* - These are configured to 0,0 and 1,1 to give a 1-1 mapping
* which can be easily tweaked from there.
*/
- insert_vert_fcurve(fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
- insert_vert_fcurve(fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST);
-
- /* configure this curve to extrapolate */
- for (i = 0, bezt = fcu->bezt; (i < fcu->totvert) && bezt; i++, bezt++) {
- bezt->h1 = bezt->h2 = HD_VECT;
- }
-
+ insert_vert_fcurve(
+ fcu, 0.0f, 0.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
+ insert_vert_fcurve(
+ fcu, 1.0f, 1.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_FAST | INSERTKEY_NO_USERPREF);
fcu->extend = FCURVE_EXTRAPOLATE_LINEAR;
calchandles_fcurve(fcu);
}
@@ -177,7 +167,8 @@ static int add_driver_with_target(ReportList *UNUSED(reports),
int driver_type)
{
FCurve *fcu;
- short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1;
+ short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? DRIVER_FCURVE_GENERATOR :
+ DRIVER_FCURVE_KEYFRAMES;
const char *prop_name = RNA_property_identifier(src_prop);
/* Create F-Curve with Driver */
@@ -593,7 +584,7 @@ bool ANIM_remove_driver(ReportList *UNUSED(reports),
* Note: here is one of the places where we don't want new F-Curve + Driver added!
* so 'add' var must be 0
*/
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
if (fcu) {
BLI_remlink(&adt->drivers, fcu);
free_fcurve(fcu);
@@ -653,7 +644,7 @@ bool ANIM_copy_driver(
}
/* try to get F-Curve with Driver */
- fcu = verify_driver_fcurve(id, rna_path, array_index, 0);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_LOOKUP_ONLY);
/* clear copy/paste buffer first (for consistency with other copy/paste buffers) */
ANIM_drivers_copybuf_free();
@@ -711,7 +702,7 @@ bool ANIM_paste_driver(
}
/* create Driver F-Curve, but without data which will be copied across... */
- fcu = verify_driver_fcurve(id, rna_path, array_index, -1);
+ fcu = verify_driver_fcurve(id, rna_path, array_index, DRIVER_FCURVE_EMPTY);
if (fcu) {
/* copy across the curve data from the buffer curve
@@ -855,7 +846,7 @@ void ANIM_copy_as_driver(struct ID *target_id, const char *target_path, const ch
ANIM_driver_vars_copybuf_free();
/* Create a dummy driver F-Curve. */
- FCurve *fcu = alloc_driver_fcurve(NULL, 0, 1);
+ FCurve *fcu = alloc_driver_fcurve(NULL, 0, DRIVER_FCURVE_KEYFRAMES);
ChannelDriver *driver = fcu->driver;
/* Create a variable. */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index c174ce83bea..479e7192b0e 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -545,8 +545,7 @@ int actkeyblock_get_valid_hold(ActKeyColumn *ac)
return 0;
}
- const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD |
- ACTKEYBLOCK_FLAG_ANY_HOLD);
+ const int hold_mask = (ACTKEYBLOCK_FLAG_ANY_HOLD | ACTKEYBLOCK_FLAG_STATIC_HOLD);
return (ac->block.flag & ~ac->block.conflict) & hold_mask;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 0f8b8742659..8203a9131fa 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -202,7 +202,7 @@ FCurve *verify_fcurve(Main *bmain,
fcu = MEM_callocN(sizeof(FCurve), "FCurve");
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
- fcu->auto_smoothing = FCURVE_SMOOTH_CONT_ACCEL;
+ fcu->auto_smoothing = U.auto_smoothing_new;
if (BLI_listbase_is_empty(&act->curves)) {
fcu->flag |= FCURVE_ACTIVE; /* first one added active */
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index eff621d7b71..c37f9ce126b 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -251,12 +251,13 @@ void *get_bone_from_selectbuffer(Base **bases,
/* x and y are mouse coords (area space) */
void *get_nearest_bone(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];
short hits;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
// rect.xmin = ... mouseco!
rect.xmin = rect.xmax = xy[0];
@@ -648,8 +649,9 @@ bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint ba
bool ED_armature_edit_deselect_all_visible_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -674,12 +676,13 @@ static int ebone_select_flag(EditBone *ebone)
bool ED_armature_edit_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
EditBone *nearBone = NULL;
int selmask;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index 8f4896c0b82..ad115896a43 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -182,12 +182,25 @@ static bool pose_has_protected_selected(Object *ob, short warn)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange pose_path_convert_range(ePosePathCalcRange range)
+{
+ switch (range) {
+ case POSE_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case POSE_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case POSE_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the object with pose/action: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool current_frame_only)
+void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, ePosePathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -195,12 +208,12 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+
+ Depsgraph *depsgraph;
bool free_depsgraph = false;
+ ListBase targets = {NULL, NULL};
/* set flag to force recalc, then grab the relevant bones to target */
ob->pose->avs.recalc |= ANIMVIZ_RECALC_PATHS;
animviz_get_object_motionpaths(ob, &targets);
@@ -210,7 +223,21 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
TIMEIT_START(pose_path_calc);
#endif
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, !free_depsgraph, current_frame_only);
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, pose_path_convert_range(range), !free_depsgraph);
#ifdef DEBUG_TIME
TIMEIT_END(pose_path_calc);
@@ -218,13 +245,13 @@ void ED_pose_recalculate_paths(bContext *C, Scene *scene, Object *ob, bool curre
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != POSE_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag armature object for copy on write - so paths will draw/redraw.
* For currently frame only we update evaluated object directly. */
DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE);
}
- /* Free temporary depsgraph instance */
+ /* Free temporary depsgraph. */
if (free_depsgraph) {
DEG_graph_free(depsgraph);
}
@@ -293,7 +320,7 @@ static int pose_calculate_paths_exec(bContext *C, wmOperator *op)
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
#ifdef DEBUG_TIME
TIMEIT_END(recalc_pose_paths);
@@ -371,7 +398,7 @@ static int pose_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
/* calculate the bones that now have motionpaths... */
/* TODO: only make for the selected bones? */
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index a59067e60c1..c3a7d45f598 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -368,8 +368,9 @@ bool ED_pose_deselect_all_multi_ex(Base **bases,
bool ED_pose_deselect_all_multi(bContext *C, int select_mode, const bool ignore_visibility)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_mode(vc.view_layer,
vc.v3d,
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 6274eb549da..7ed41b5b4d0 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -368,30 +368,14 @@ static void pose_slide_apply_val(tPoseSlideOp *pso, FCurve *fcu, Object *ob, flo
switch (pso->mode) {
case POSESLIDE_PUSH: /* make the current pose more pronounced */
{
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be larger than denominator to 'expand' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (-((sVal * w2) + (eVal * w1)) + ((*val) * 6.0f)) / 5.0f;
- }
+ /* Slide the pose away from the breakdown pose in the timeline */
+ (*val) -= ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
break;
}
case POSESLIDE_RELAX: /* make the current pose more like its surrounding ones */
{
- /* perform a weighted average here, favoring the middle pose
- * - numerator should be smaller than denominator to 'relax' the result
- * - perform this weighting a number of times given by the percentage...
- */
- /* TODO: maybe a sensitivity ctrl on top of this is needed */
- int iters = (int)ceil(10.0f * pso->percentage);
-
- while (iters-- > 0) {
- (*val) = (((sVal * w2) + (eVal * w1)) + ((*val) * 5.0f)) / 6.0f;
- }
+ /* Slide the pose towards the breakdown pose in the timeline */
+ (*val) += ((sVal * w2) + (eVal * w1) - (*val)) * pso->percentage;
break;
}
case POSESLIDE_BREAKDOWN: /* make the current pose slide around between the endpoints */
@@ -1003,7 +987,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, tPoseSlideOp *p
pose_slide_refresh(C, pso);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* header print */
pose_slide_draw_status(pso);
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 52a3f7711c4..55c9b661074 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -543,16 +543,14 @@ static void set_pose_keys(Object *ob)
* \param chan: Bone that pose to paste comes from
* \param selOnly: Only paste on selected bones
* \param flip: Flip on x-axis
- * \return Whether the bone that we pasted to if we succeeded
+ * \return The channel of the bone that was pasted to, or NULL if no paste was performed.
*/
static bPoseChannel *pose_bone_do_paste(Object *ob,
bPoseChannel *chan,
const bool selOnly,
const bool flip)
{
- bPoseChannel *pchan;
char name[MAXBONENAME];
- short paste_ok;
/* get the name - if flipping, we must flip this first */
if (flip) {
@@ -567,131 +565,126 @@ static bPoseChannel *pose_bone_do_paste(Object *ob,
* 2) if selection-masking is on, channel is selected -
* only selected bones get pasted on, allowing making both sides symmetrical.
*/
- pchan = BKE_pose_channel_find_name(ob->pose, name);
-
- if (selOnly) {
- paste_ok = ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, name);
+ if (pchan == NULL) {
+ return NULL;
}
- else {
- paste_ok = (pchan != NULL);
+ if (selOnly && (pchan->bone->flag & BONE_SELECTED) == 0) {
+ return NULL;
}
- /* continue? */
- if (paste_ok) {
- /* only loc rot size
- * - only copies transform info for the pose
- */
- copy_v3_v3(pchan->loc, chan->loc);
- copy_v3_v3(pchan->size, chan->size);
- pchan->flag = chan->flag;
-
- /* check if rotation modes are compatible (i.e. do they need any conversions) */
- if (pchan->rotmode == chan->rotmode) {
- /* copy the type of rotation in use */
- if (pchan->rotmode > 0) {
- copy_v3_v3(pchan->eul, chan->eul);
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- copy_v3_v3(pchan->rotAxis, chan->rotAxis);
- pchan->rotAngle = chan->rotAngle;
- }
- else {
- copy_qt_qt(pchan->quat, chan->quat);
- }
- }
- else if (pchan->rotmode > 0) {
- /* quat/axis-angle to euler */
- if (chan->rotmode == ROT_MODE_AXISANGLE) {
- axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
- }
- else {
- quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
- }
+ /* only loc rot size
+ * - only copies transform info for the pose
+ */
+ copy_v3_v3(pchan->loc, chan->loc);
+ copy_v3_v3(pchan->size, chan->size);
+ pchan->flag = chan->flag;
+
+ /* check if rotation modes are compatible (i.e. do they need any conversions) */
+ if (pchan->rotmode == chan->rotmode) {
+ /* copy the type of rotation in use */
+ if (pchan->rotmode > 0) {
+ copy_v3_v3(pchan->eul, chan->eul);
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- /* quat/euler to axis angle */
- if (chan->rotmode > 0) {
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
- }
- else {
- quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
- }
+ copy_v3_v3(pchan->rotAxis, chan->rotAxis);
+ pchan->rotAngle = chan->rotAngle;
}
else {
- /* euler/axis-angle to quat */
- if (chan->rotmode > 0) {
- eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
- }
- else {
- axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
- }
+ copy_qt_qt(pchan->quat, chan->quat);
+ }
+ }
+ else if (pchan->rotmode > 0) {
+ /* quat/axis-angle to euler */
+ if (chan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_eulO(pchan->eul, pchan->rotmode, chan->rotAxis, chan->rotAngle);
+ }
+ else {
+ quat_to_eulO(pchan->eul, pchan->rotmode, chan->quat);
+ }
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ /* quat/euler to axis angle */
+ if (chan->rotmode > 0) {
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
+ }
+ else {
+ quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
+ }
+ }
+ else {
+ /* euler/axis-angle to quat */
+ if (chan->rotmode > 0) {
+ eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
}
+ else {
+ axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
+ }
+ }
- /* B-Bone posing options should also be included... */
- pchan->curve_in_x = chan->curve_in_x;
- pchan->curve_in_y = chan->curve_in_y;
- pchan->curve_out_x = chan->curve_out_x;
- pchan->curve_out_y = chan->curve_out_y;
-
- pchan->roll1 = chan->roll1;
- pchan->roll2 = chan->roll2;
- pchan->ease1 = chan->ease1;
- pchan->ease2 = chan->ease2;
- pchan->scale_in_x = chan->scale_in_x;
- pchan->scale_in_y = chan->scale_in_y;
- pchan->scale_out_x = chan->scale_out_x;
- pchan->scale_out_y = chan->scale_out_y;
-
- /* paste flipped pose? */
- if (flip) {
- pchan->loc[0] *= -1;
-
- pchan->curve_in_x *= -1;
- pchan->curve_out_x *= -1;
- pchan->roll1 *= -1; // XXX?
- pchan->roll2 *= -1; // XXX?
-
- /* has to be done as eulers... */
- if (pchan->rotmode > 0) {
- pchan->eul[1] *= -1;
- pchan->eul[2] *= -1;
- }
- else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
- float eul[3];
+ /* B-Bone posing options should also be included... */
+ pchan->curve_in_x = chan->curve_in_x;
+ pchan->curve_in_y = chan->curve_in_y;
+ pchan->curve_out_x = chan->curve_out_x;
+ pchan->curve_out_y = chan->curve_out_y;
+
+ pchan->roll1 = chan->roll1;
+ pchan->roll2 = chan->roll2;
+ pchan->ease1 = chan->ease1;
+ pchan->ease2 = chan->ease2;
+ pchan->scale_in_x = chan->scale_in_x;
+ pchan->scale_in_y = chan->scale_in_y;
+ pchan->scale_out_x = chan->scale_out_x;
+ pchan->scale_out_y = chan->scale_out_y;
+
+ /* paste flipped pose? */
+ if (flip) {
+ pchan->loc[0] *= -1;
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
- eul[1] *= -1;
- eul[2] *= -1;
- eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
- }
- else {
- float eul[3];
+ pchan->curve_in_x *= -1;
+ pchan->curve_out_x *= -1;
+ pchan->roll1 *= -1; // XXX?
+ pchan->roll2 *= -1; // XXX?
- normalize_qt(pchan->quat);
- quat_to_eul(eul, pchan->quat);
- eul[1] *= -1;
- eul[2] *= -1;
- eul_to_quat(pchan->quat, eul);
- }
+ /* has to be done as eulers... */
+ if (pchan->rotmode > 0) {
+ pchan->eul[1] *= -1;
+ pchan->eul[2] *= -1;
}
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ float eul[3];
- /* ID properties */
- if (chan->prop) {
- if (pchan->prop) {
- /* if we have existing properties on a bone, just copy over the values of
- * matching properties (i.e. ones which will have some impact) on to the
- * target instead of just blinding replacing all [
- */
- IDP_SyncGroupValues(pchan->prop, chan->prop);
- }
- else {
- /* no existing properties, so assume that we want copies too? */
- pchan->prop = IDP_CopyProperty(chan->prop);
- }
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
+ }
+ else {
+ float eul[3];
+
+ normalize_qt(pchan->quat);
+ quat_to_eul(eul, pchan->quat);
+ eul[1] *= -1;
+ eul[2] *= -1;
+ eul_to_quat(pchan->quat, eul);
+ }
+ }
+
+ /* ID properties */
+ if (chan->prop) {
+ if (pchan->prop) {
+ /* if we have existing properties on a bone, just copy over the values of
+ * matching properties (i.e. ones which will have some impact) on to the
+ * target instead of just blinding replacing all [
+ */
+ IDP_SyncGroupValues(pchan->prop, chan->prop);
+ }
+ else {
+ /* no existing properties, so assume that we want copies too? */
+ pchan->prop = IDP_CopyProperty(chan->prop);
}
}
- /* return whether paste went ahead */
return pchan;
}
@@ -831,7 +824,7 @@ static int pose_paste_exec(bContext *C, wmOperator *op)
/* Recalculate paths if any of the bones have paths... */
if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob, false);
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
/* Notifiers for updates, */
@@ -1112,7 +1105,7 @@ static int pose_clear_transform_generic_exec(bContext *C,
/* now recalculate paths */
if ((ob_iter->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS)) {
- ED_pose_recalculate_paths(C, scene, ob_iter, false);
+ ED_pose_recalculate_paths(C, scene, ob_iter, POSE_PATH_CALC_RANGE_FULL);
}
BLI_freelistN(&dsources);
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index fbaf2c896d0..8d2d7d790d2 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -32,6 +32,7 @@
#include "DNA_scene_types.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_idprop.h"
#include "BKE_layer.h"
@@ -223,6 +224,11 @@ void poseAnim_mapping_refresh(bContext *C, Scene *UNUSED(scene), Object *ob)
{
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+
+ AnimData *adt = BKE_animdata_from_id(&ob->id);
+ if (adt && adt->action) {
+ DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH);
+ }
}
/* reset changes made to current pose */
@@ -327,7 +333,8 @@ void poseAnim_mapping_autoKeyframe(bContext *C, Scene *scene, ListBase *pfLinks,
if (ob->id.tag & LIB_TAG_DOIT) {
if (ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS) {
// ED_pose_clear_paths(C, ob); // XXX for now, don't need to clear
- ED_pose_recalculate_paths(C, scene, ob, false);
+ /* TODO(sergey): Should ensure we can use more narrow update range here. */
+ ED_pose_recalculate_paths(C, scene, ob, POSE_PATH_CALC_RANGE_FULL);
}
}
}
diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c
index 3d2ac009072..81c9c759188 100644
--- a/source/blender/editors/curve/curve_ops.c
+++ b/source/blender/editors/curve/curve_ops.c
@@ -33,10 +33,7 @@
#include "WM_types.h"
#include "ED_curve.h"
-#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
-#include "ED_transform.h"
#include "curve_intern.h"
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 7e878d0f905..994d844287c 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -56,13 +56,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_keyframes_edit.h"
#include "ED_object.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_transform_snap_object_context.h"
#include "ED_types.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "ED_curve.h"
@@ -4876,6 +4874,7 @@ void CURVE_OT_make_segment(wmOperatorType *ot)
bool ED_curve_editnurb_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt = NULL;
@@ -4884,7 +4883,7 @@ bool ED_curve_editnurb_select_pick(
short hand;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, mval);
if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) {
@@ -5635,9 +5634,10 @@ static int add_vertex_exec(bContext *C, wmOperator *op)
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && !RNA_struct_property_is_set(op->ptr, "location")) {
Curve *cu;
@@ -7136,7 +7136,6 @@ static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
copy_v3_v3(curve->loc, loc);
copy_v3_v3(curve->size, size);
- zero_v3(curve->rot);
curve->texflag &= ~CU_AUTOSPACE;
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index 4912ae5451d..d97223de9b8 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -44,7 +44,6 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_undo.h"
#include "ED_view3d.h"
#include "ED_curve.h"
diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c
index c7c19aa2d02..4c4bac6a249 100644
--- a/source/blender/editors/curve/editcurve_paint.c
+++ b/source/blender/editors/curve/editcurve_paint.c
@@ -31,7 +31,6 @@
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_report.h"
-#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -575,9 +574,10 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
BLI_assert(op->customdata == NULL);
struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
if (is_invoke) {
- ED_view3d_viewcontext_init(C, &cdd->vc);
+ ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph);
if (ELEM(NULL, cdd->vc.ar, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
MEM_freeN(cdd);
BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
@@ -586,7 +586,7 @@ static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
}
else {
cdd->vc.bmain = CTX_data_main(C);
- cdd->vc.depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ cdd->vc.depsgraph = depsgraph;
cdd->vc.scene = CTX_data_scene(C);
cdd->vc.view_layer = CTX_data_view_layer(C);
cdd->vc.obedit = CTX_data_edit_object(C);
@@ -1064,7 +1064,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
cdd->draw_handle_view = ED_region_draw_cb_activate(
cdd->vc.ar->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
- WM_cursor_modal_set(cdd->vc.win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH);
{
View3D *v3d = cdd->vc.v3d;
diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c
index d0abcf32107..9df79a082e1 100644
--- a/source/blender/editors/curve/editcurve_select.c
+++ b/source/blender/editors/curve/editcurve_select.c
@@ -37,7 +37,6 @@
#include "BKE_fcurve.h"
#include "BKE_layer.h"
#include "BKE_report.h"
-#include "BKE_object.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -278,8 +277,9 @@ bool ED_curve_deselect_all_multi_ex(Base **bases, int bases_len)
bool ED_curve_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -684,6 +684,7 @@ void CURVE_OT_select_linked(wmOperatorType *ot)
static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu;
BezTriple *bezt;
@@ -693,7 +694,7 @@ static int select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, NULL, &basact)) {
@@ -1960,6 +1961,7 @@ static void curve_select_shortest_path_surf(Nurb *nu, int vert_src, int vert_dst
static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Nurb *nu_dst;
BezTriple *bezt_dst;
@@ -1969,7 +1971,7 @@ static int edcu_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE
Base *basact = NULL;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
copy_v2_v2_int(vc.mval, event->mval);
if (!ED_curve_pick_vert(&vc, 1, &nu_dst, &bezt_dst, &bp_dst, NULL, &basact)) {
diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c
index 835abd1a630..f21b4f06246 100644
--- a/source/blender/editors/curve/editcurve_undo.c
+++ b/source/blender/editors/curve/editcurve_undo.c
@@ -40,9 +40,7 @@
#include "DEG_depsgraph.h"
-#include "ED_object.h"
#include "ED_undo.h"
-#include "ED_util.h"
#include "ED_curve.h"
#include "WM_types.h"
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 781eb2634fb..e11807d818f 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -60,7 +60,6 @@
#include "ED_curve.h"
#include "ED_object.h"
#include "ED_screen.h"
-#include "ED_util.h"
#include "ED_view3d.h"
#include "UI_interface.h"
@@ -1877,6 +1876,7 @@ void ED_curve_editfont_make(Object *obedit)
memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo));
+ ef->pos = cu->pos;
if (ef->pos > ef->len) {
ef->pos = ef->len;
}
@@ -1884,7 +1884,6 @@ void ED_curve_editfont_make(Object *obedit)
cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
/* Other vars */
- ef->pos = cu->pos;
ef->selstart = cu->selstart;
ef->selend = cu->selend;
@@ -2201,6 +2200,7 @@ void FONT_OT_unlink(wmOperatorType *ot)
bool ED_curve_editfont_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
ViewContext vc;
@@ -2212,7 +2212,7 @@ bool ED_curve_editfont_select_pick(
const float dist = ED_view3d_select_dist_px();
float dist_sq_best = dist * dist;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c
index 2f8f15bc6c7..ae858ec4c24 100644
--- a/source/blender/editors/curve/editfont_undo.c
+++ b/source/blender/editors/curve/editfont_undo.c
@@ -29,7 +29,6 @@
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_font.h"
@@ -39,7 +38,6 @@
#include "ED_object.h"
#include "ED_curve.h"
-#include "ED_util.h"
#include "WM_types.h"
#include "WM_api.h"
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 765362b374e..8a3a078bdd2 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -645,6 +645,8 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.clay_strips
brush.sculpt.crease
brush.sculpt.draw
+ brush.sculpt.draw_sharp
+ brush.sculpt.elastic_deform
brush.sculpt.fill
brush.sculpt.flatten
brush.sculpt.grab
@@ -653,6 +655,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
brush.sculpt.mask
brush.sculpt.nudge
brush.sculpt.pinch
+ brush.sculpt.pose
brush.sculpt.rotate
brush.sculpt.scrape
brush.sculpt.simplify
@@ -736,6 +739,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.border_hide
ops.sculpt.border_mask
ops.sculpt.lasso_mask
+ ops.sculpt.mesh_filter
ops.transform.bone_envelope
ops.transform.bone_size
ops.transform.edge_slide
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 1a132c2957a..ecbc503e084 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c
@@ -258,9 +258,9 @@ static int gizmo_button2d_test_select(bContext *C, wmGizmo *gz, const int mval[2
static int gizmo_button2d_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
static void gizmo_button2d_free(wmGizmo *gz)
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 ba3b8c2602e..ef4fd23b64d 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c
@@ -752,30 +752,30 @@ static int gizmo_cage2d_get_cursor(wmGizmo *gz)
int highlight_part = gz->highlight_part;
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
switch (highlight_part) {
case ED_GIZMO_CAGE2D_PART_TRANSLATE:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X:
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y:
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
/* TODO diagonal cursor */
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y:
case ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y:
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
case ED_GIZMO_CAGE2D_PART_ROTATE:
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
default:
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
}
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 406f76bc65e..723be3cfe6b 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/cage3d_gizmo.c
@@ -424,10 +424,10 @@ static void gizmo_cage3d_draw(const bContext *C, wmGizmo *gz)
static int gizmo_cage3d_get_cursor(wmGizmo *gz)
{
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
typedef struct RectTransformInteraction {
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 37ee95d5058..5342f8695b2 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -412,7 +412,7 @@ static void gizmo_move_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
static int gizmo_move_cursor_get(wmGizmo *UNUSED(gz))
{
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
/* -------------------------------------------------------------------- */
diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c
index 22f1753a810..7a10547f35c 100644
--- a/source/blender/editors/gpencil/annotate_paint.c
+++ b/source/blender/editors/gpencil/annotate_paint.c
@@ -1560,10 +1560,10 @@ static int gpencil_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_draw_cursor_set(tGPsdata *p)
{
if (p->paintmode == GP_PAINTMODE_ERASER) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_ERASER);
}
else {
- WM_cursor_modal_set(p->win, BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(p->win, WM_CURSOR_PAINT_BRUSH);
}
}
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 2a2e7c21df4..af9cadfb938 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -52,6 +52,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_modifier.h"
#include "BKE_material.h"
#include "BKE_object_deform.h"
#include "BKE_report.h"
@@ -109,6 +110,7 @@ typedef struct tGP_BrushEditData {
/* Is the brush currently painting? */
bool is_painting;
bool is_weight_mode;
+ bool is_transformed;
/* Start of new sculpt stroke */
bool first;
@@ -532,7 +534,7 @@ static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
// XXX: screen-space strokes in 3D space will suffer!
if (gso->sa->spacetype == SPACE_VIEW3D) {
RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
+ float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -657,7 +659,7 @@ static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
* See: gpencil_paint.c :: gp_stroke_convertcoords()
*/
RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
+ const float *rvec = gso->object->loc;
float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
float mval_f[2];
@@ -1326,9 +1328,12 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
gso->vrgroup = -1;
}
+ /* Check if some modifier can transform the stroke. */
+ gso->is_transformed = BKE_gpencil_has_transform_modifiers(ob);
}
else {
gso->vrgroup = -1;
+ gso->is_transformed = false;
}
gso->sa = CTX_wm_area(C);
@@ -1397,7 +1402,7 @@ static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
gpsculpt_brush_header_set(C, gso);
/* setup cursor drawing */
- // WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ // WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_CROSS);
if (gso->sa->spacetype != SPACE_VIEW3D) {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
}
@@ -1463,7 +1468,7 @@ static bool gpsculpt_brush_poll(bContext *C)
/* Init Sculpt Stroke ---------------------------------- */
-static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
+static void gpsculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
{
bGPdata *gpd = gso->gpd;
@@ -1487,9 +1492,11 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* - This is useful when animating as it saves that "uh-oh" moment when you realize you've
* spent too much time editing the wrong frame.
*/
- // XXX: should this be allowed when framelock is enabled?
if (gpf->framenum != cfra) {
BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* Need tag to recalculate evaluated data to avoid crashes. */
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
}
}
}
@@ -1504,12 +1511,17 @@ static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
* For strokes with one point only this is impossible to calculate because there isn't a
* valid reference point.
*/
-static float gpsculpt_rotation_eval_get(GP_SpaceConversion *gsc,
+static float gpsculpt_rotation_eval_get(tGP_BrushEditData *gso,
bGPDstroke *gps_eval,
bGPDspoint *pt_eval,
int idx_eval)
{
+ /* If multiframe or no modifiers, return 0. */
+ if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) {
+ return 0.0f;
+ }
+ GP_SpaceConversion *gsc = &gso->gsc;
bGPDstroke *gps_orig = gps_eval->runtime.gps_orig;
bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
bGPDspoint *pt_prev_eval = NULL;
@@ -1564,12 +1576,16 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
gso->gp_brush->size * gso->pressure :
gso->gp_brush->size;
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
bGPDspoint *pt1, *pt2;
bGPDspoint *pt = NULL;
int pc1[2] = {0};
int pc2[2] = {0};
int i;
+ int index;
bool include_last = false;
bool changed = false;
float rot_eval = 0.0f;
@@ -1579,6 +1595,7 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
/* only check if point is inside */
@@ -1586,9 +1603,9 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
round_v2i_v2fl(mval_i, gso->mval);
if (len_v2v2_int(mval_i, pc1) <= radius) {
/* apply operation to this point */
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, 0);
- changed = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, 0);
+ changed = apply(gso, gps_active, rot_eval, 0, radius, pc1);
}
}
}
@@ -1631,9 +1648,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
/* To each point individually... */
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- ok = apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
}
/* Only do the second point if this is the last segment,
@@ -1646,9 +1665,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
*/
if (i + 1 == gps->totpoints - 1) {
pt = &gps->points[i + 1];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i + 1);
- ok |= apply(gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc2);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i + 1;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i + 1);
+ ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
include_last = false;
}
}
@@ -1665,10 +1686,11 @@ static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
* (but wasn't added then, to avoid double-ups).
*/
pt = &gps->points[i];
- if (pt->runtime.pt_orig != NULL) {
- rot_eval = gpsculpt_rotation_eval_get(&gso->gsc, gps, pt, i);
- changed |= apply(
- gso, gps->runtime.gps_orig, rot_eval, pt->runtime.idx_orig, radius, pc1);
+ pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+ index = (!is_multiedit) ? pt->runtime.idx_orig : i;
+ if (pt_active != NULL) {
+ rot_eval = gpsculpt_rotation_eval_get(gso, gps, pt, i);
+ changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
include_last = false;
}
}
@@ -1688,6 +1710,7 @@ static bool gpsculpt_brush_do_frame(bContext *C,
{
bool changed = false;
Object *ob = CTX_data_active_object(C);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* skip strokes that are invalid for current view */
@@ -1720,18 +1743,19 @@ static bool gpsculpt_brush_do_frame(bContext *C,
case GP_SCULPT_TYPE_GRAB: /* Grab points */
{
- if (gps->runtime.gps_orig != NULL) {
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ if (gps_active != NULL) {
if (gso->first) {
/* First time this brush stroke is being applied:
* 1) Prepare data buffers (init/clear) for this stroke
* 2) Use the points now under the cursor
*/
- gp_brush_grab_stroke_init(gso, gps->runtime.gps_orig);
+ gp_brush_grab_stroke_init(gso, gps_active);
changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
}
else {
/* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps->runtime.gps_orig, diff_mat);
+ gp_brush_grab_apply_cached(gso, gps_active, diff_mat);
changed |= true;
}
}
@@ -1862,8 +1886,7 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
}
/* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(
- C, gso, gpl, (gpf == gpl->actframe) ? gpf_eval : gpf, diff_mat);
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
}
}
}
@@ -2079,7 +2102,7 @@ static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
/* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
/* apply first dab... */
gso->is_painting = true;
@@ -2194,7 +2217,7 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even
gso->is_painting = true;
gso->first = true;
- gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_init_stroke(C, gso);
gpsculpt_brush_apply_event(C, op, event);
break;
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index d72f61c64b1..67ffc6adc9f 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -492,51 +492,44 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
bGPdata *gpd_src = (bGPdata *)ob_src->data;
bGPDlayer *gpl_src = BKE_gpencil_layer_getactive(gpd_src);
- /* sanity checks */
+ /* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
- /* cannot copy itself and check destination type */
+ /* Cannot copy itself and check destination type. */
if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
- /* make copy of layer */
- bGPDlayer *gpl_dst = MEM_dupallocN(gpl_src);
- gpl_dst->prev = gpl_dst->next = NULL;
- BLI_addtail(&gpd_dst->layers, gpl_dst);
- BLI_uniquename(&gpd_dst->layers,
- gpl_dst,
- DATA_("GP_Layer"),
- '.',
- offsetof(bGPDlayer, info),
- sizeof(gpl_dst->info));
+ /* Create new layer. */
+ bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
+ /* Need to copy some variables (not all). */
+ gpl_dst->onion_flag = gpl_src->onion_flag;
+ gpl_dst->thickness = gpl_src->thickness;
+ gpl_dst->line_change = gpl_src->line_change;
+ copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
+ gpl_dst->opacity = gpl_src->opacity;
- /* copy frames */
- BLI_listbase_clear(&gpl_dst->frames);
+ /* Create all frames. */
for (bGPDframe *gpf_src = gpl_src->frames.first; gpf_src; gpf_src = gpf_src->next) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
- /* make a copy of source frame */
- bGPDframe *gpf_dst = MEM_dupallocN(gpf_src);
- gpf_dst->prev = gpf_dst->next = NULL;
- BLI_addtail(&gpl_dst->frames, gpf_dst);
+ /* Create new frame. */
+ bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
- /* copy strokes */
- BLI_listbase_clear(&gpf_dst->strokes);
+ /* Copy strokes. */
for (bGPDstroke *gps_src = gpf_src->strokes.first; gps_src; gps_src = gps_src->next) {
- /* make copy of source stroke */
+ /* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src);
- /* check if material is in destination object,
- * otherwise add the slot with the material
- */
+ /* Check if material is in destination object,
+ * otherwise add the slot with the material. */
Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
if (ma_src != NULL) {
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
@@ -545,7 +538,7 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
gps_dst->mat_nr = idx;
}
- /* add new stroke to frame */
+ /* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
@@ -568,7 +561,7 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
};
/* identifiers */
- ot->name = "Duplicate Layer to new Object";
+ ot->name = "Duplicate Layer to New Object";
ot->idname = "GPENCIL_OT_layer_duplicate_object";
ot->description = "Make a copy of the active Grease Pencil layer to new object";
@@ -799,7 +792,7 @@ static int gp_frame_clean_loose_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_frame_clean_loose(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Clean Loose points";
+ ot->name = "Clean Loose Points";
ot->idname = "GPENCIL_OT_frame_clean_loose";
ot->description = "Remove loose points";
@@ -1587,7 +1580,9 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
/* ******************* Brush create presets ************************** */
static int gp_brush_presets_create_exec(bContext *C, wmOperator *UNUSED(op))
{
- BKE_brush_gpencil_presets(C);
+ Main *bmain = CTX_data_main(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ BKE_brush_gpencil_presets(bmain, ts);
/* notifiers */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index a5e9fe9b166..91ecbed7b5b 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -237,11 +237,38 @@ static int gpencil_selectmode_toggle_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
const int mode = RNA_int_get(op->ptr, "mode");
+ bool changed = false;
+
+ if (ts->gpencil_selectmode_edit == mode) {
+ return OPERATOR_FINISHED;
+ }
/* Just set mode */
ts->gpencil_selectmode_edit = mode;
+ /* If the mode is Stroke, extend selection. */
+ if ((ob) && (ts->gpencil_selectmode_edit == GP_SELECTMODE_STROKE)) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+ /* Extend selection to all points in all selected strokes. */
+ CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) {
+ if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) {
+ changed = true;
+ bGPDspoint *pt;
+ for (int i = 0; i < gps->totpoints; i++) {
+ pt = &gps->points[i];
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+ }
+ }
+ CTX_DATA_END;
+ if (changed) {
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_SELECTED, NULL);
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
@@ -328,7 +355,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op)
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_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
BKE_paint_toolslots_brush_validate(bmain, &ts->gp_paint->paint);
}
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index ea93f861c6e..993ec15248f 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1394,7 +1394,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE
tgpf->ar->type, gpencil_fill_draw_3d, tgpf, REGION_DRAW_POST_VIEW);
}
- WM_cursor_modal_set(CTX_wm_window(C), BC_PAINTBRUSHCURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH);
gpencil_fill_status_indicators(C, tgpf);
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 0bbabafb2b0..7ff6243b0d2 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -214,6 +214,8 @@ typedef struct tGPDprimitive {
int sel_cp;
/** flag to determine operations in progress */
int flag;
+ /** flag to determine operations previous mode */
+ int prev_flag;
/** recorded mouse-position */
float mval[2];
/** previous recorded mouse-position */
@@ -467,6 +469,7 @@ enum {
GP_STROKE_CIRCLE = 2,
GP_STROKE_ARC = 3,
GP_STROKE_CURVE = 4,
+ GP_STROKE_POLYLINE = 5,
};
enum {
@@ -672,7 +675,9 @@ struct GP_EditableStrokes_Iter {
ED_gpencil_parent_location(depsgraph_, obact_, gpd_, gpl, gpstroke_iter.diff_mat); \
invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \
/* get evaluated frame with modifiers applied */ \
- bGPDframe *gpf_eval_ = &obeval_->runtime.gpencil_evaluated_frames[idx_eval]; \
+ bGPDframe *gpf_eval_ = (!is_multiedit_) ? \
+ &obeval_->runtime.gpencil_evaluated_frames[idx_eval] : \
+ gpf_; \
/* loop over strokes */ \
for (bGPDstroke *gps = gpf_eval_->strokes.first; gps; gps = gps->next) { \
/* skip strokes that are invalid for current view */ \
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 86de9a75a56..1438c33a972 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -560,7 +560,7 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent
tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW);
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EW_SCROLL);
/* update shift indicator in header */
gpencil_interpolate_status_indicators(C, tgpi);
diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c
index 930911ffac5..36cef3ccdc0 100644
--- a/source/blender/editors/gpencil/gpencil_merge.c
+++ b/source/blender/editors/gpencil/gpencil_merge.c
@@ -35,6 +35,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
+#include "BKE_main.h"
#include "BKE_material.h"
#include "WM_api.h"
@@ -97,6 +98,7 @@ static void gpencil_insert_points_to_stroke(bGPDstroke *gps,
static bGPDstroke *gpencil_prepare_stroke(bContext *C, wmOperator *op, int totpoints)
{
+ Main *bmain = CTX_data_main(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
@@ -111,7 +113,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_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
Brush *brush = paint->brush;
diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c
index af49587f9ad..3d56cb0fcb1 100644
--- a/source/blender/editors/gpencil/gpencil_ops_versioning.c
+++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c
@@ -54,6 +54,9 @@
#include "ED_object.h"
#include "ED_gpencil.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
#include "gpencil_intern.h"
/* Free all of a gp-colors */
@@ -111,6 +114,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op)
ob = BKE_object_add_for_data(
bmain, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false);
zero_v3(ob->loc);
+ 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) {
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 0a4b068a926..f29e782c618 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -598,6 +598,7 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
float sco[2] = {0.0f};
float a[2], b[2], c[2], d[2];
float pressure = 0.0f;
+ float strength = 0.0f;
const float average_fac = 1.0f / steps;
/* Compute smoothed coordinate by taking the ones nearby */
@@ -605,21 +606,25 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(a, &pta->x);
madd_v2_v2fl(sco, a, average_fac);
pressure += pta->pressure * average_fac;
+ strength += pta->strength * average_fac;
}
if (ptb) {
copy_v2_v2(b, &ptb->x);
madd_v2_v2fl(sco, b, average_fac);
pressure += ptb->pressure * average_fac;
+ strength += ptb->strength * average_fac;
}
if (ptc) {
copy_v2_v2(c, &ptc->x);
madd_v2_v2fl(sco, c, average_fac);
pressure += ptc->pressure * average_fac;
+ strength += ptc->strength * average_fac;
}
if (ptd) {
copy_v2_v2(d, &ptd->x);
madd_v2_v2fl(sco, d, average_fac);
pressure += ptd->pressure * average_fac;
+ strength += ptd->strength * average_fac;
}
/* Based on influence factor, blend between original and optimal smoothed coordinate. */
@@ -627,10 +632,156 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx)
copy_v2_v2(&ptc->x, c);
/* Interpolate pressure. */
ptc->pressure = interpf(ptc->pressure, pressure, inf);
+ /* Interpolate strength. */
+ ptc->strength = interpf(ptc->strength, strength, inf);
+}
+
+/* Helper: Apply smooth to segment from Index to Index */
+static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int to_idx)
+{
+ const short num_points = to_idx - from_idx;
+ /* Do nothing if not enough points to smooth out */
+ if ((num_points < 3) || (inf == 0.0f)) {
+ return;
+ }
+
+ if (from_idx <= 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ const float average_fac = 0.25f;
+
+ for (int i = from_idx; i < to_idx + 1; i++) {
+
+ tGPspoint *pta = i >= 3 ? &points[i - 3] : NULL;
+ tGPspoint *ptb = i >= 2 ? &points[i - 2] : NULL;
+ tGPspoint *ptc = i >= 1 ? &points[i - 1] : &points[i];
+ tGPspoint *ptd = &points[i];
+
+ float sco[2] = {0.0f};
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ if (pta) {
+ madd_v2_v2fl(sco, &pta->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ if (ptb) {
+ madd_v2_v2fl(sco, &ptb->x, average_fac);
+ }
+ else {
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+ }
+
+ madd_v2_v2fl(sco, &ptc->x, average_fac);
+
+ madd_v2_v2fl(sco, &ptd->x, average_fac);
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate. */
+ interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf);
+ }
+}
+
+/* Smooth all the sections created with fake events to avoid abrupt transitions.
+ *
+ * As the fake events add points between two real events, this produces a straight line, but if
+ * there is 3 or more real points that used fakes, the stroke is not smooth and produces abrupt
+ * angles.
+ * This function reads these segments and finds the real points and smooth with the surrounding
+ * points. */
+static void gp_smooth_fake_segments(tGPsdata *p)
+{
+ bGPdata *gpd = p->gpd;
+ Brush *brush = p->brush;
+
+ if (brush->gpencil_settings->input_samples < 2) {
+ return;
+ }
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ tGPspoint *pt = NULL;
+ /* Index where segment starts. */
+ int from_idx = 0;
+ /* Index where segment ends. */
+ int to_idx = 0;
+
+ bool doit = false;
+ /* Loop all points except the extremes. */
+ for (int i = 1; i < gpd->runtime.sbuffer_used - 1; i++) {
+ pt = &points[i];
+ bool is_fake = (bool)(pt->tflag & GP_TPOINT_FAKE);
+ to_idx = i;
+
+ /* Detect fake points in the stroke. */
+ if ((!doit) && (is_fake)) {
+ from_idx = i;
+ doit = true;
+ }
+ /* If detect control point after fake points, select a segment with same length in both sides,
+ * except if it is more than stroke length. */
+ if ((doit) && (!is_fake)) {
+ if (i + (i - from_idx) < gpd->runtime.sbuffer_used - 1) {
+ to_idx = i + (i - from_idx);
+ /* Smooth this segments (need loop to get cumulative smooth). */
+ for (int r = 0; r < 5; r++) {
+ gp_smooth_segment(gpd, 0.1f, from_idx, to_idx);
+ }
+ }
+ else {
+ break;
+ }
+ /* Reset to new segments. */
+ from_idx = i;
+ doit = false;
+ }
+ }
+}
+
+/* Smooth the section added with fake events when pen moves very fast. */
+static void gp_smooth_fake_events(tGPsdata *p, int size_before, int size_after)
+{
+ bGPdata *gpd = p->gpd;
+ const short totpoints = size_after - size_before - 1;
+ /* Do nothing if not enough data to smooth out. */
+ if (totpoints < 1) {
+ return;
+ }
+
+ /* Back two points to get smoother effect. */
+ size_before -= 2;
+ CLAMP_MIN(size_before, 1);
+
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Extreme points. */
+ const tGPspoint *pta = &points[size_before - 1];
+ const tGPspoint *ptb = &points[size_after - 1];
+ tGPspoint *pt1, *pt2;
+ int i;
+
+ /* Get total length of the segment to smooth. */
+ float totlen = 0.0f;
+ for (i = size_before; i < size_after; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ totlen += len_v2v2(&pt1->x, &pt2->x);
+ }
+ /* Smooth interpolating the position of the points. */
+ float pointlen = 0.0f;
+ for (i = size_before; i < size_after - 1; i++) {
+ pt1 = &points[i - 1];
+ pt2 = &points[i];
+ pointlen += len_v2v2(&pt1->x, &pt2->x);
+ pt2->pressure = interpf(ptb->pressure, pta->pressure, pointlen / totlen);
+ pt2->strength = interpf(ptb->strength, pta->strength, pointlen / totlen);
+ }
}
/* 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)
+static short gp_stroke_addpoint(
+ tGPsdata *p, const float mval[2], float pressure, double curtime, bool is_fake)
{
bGPdata *gpd = p->gpd;
Brush *brush = p->brush;
@@ -689,6 +840,14 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
+ /* Set if point was created by fake events. */
+ if (is_fake) {
+ pt->tflag |= GP_TPOINT_FAKE;
+ }
+ else {
+ pt->tflag &= ~GP_TPOINT_FAKE;
+ }
+
/* store settings */
/* pressure */
if (brush->gpencil_settings->flag & GP_BRUSH_USE_PRESSURE) {
@@ -846,7 +1005,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
bGPDspoint *pts;
MDeformVert *dvert = NULL;
- /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
+ /* First time point is adding to temporary buffer (need to allocate new point in stroke) */
if (gpd->runtime.sbuffer_used == 0) {
gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
if (gps->dvert != NULL) {
@@ -937,6 +1096,22 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
(!is_depth);
int i, totelem;
+ /* For very low pressure at the end, truncate stroke. */
+ if (p->paintmode == GP_PAINTMODE_DRAW) {
+ int last_i = gpd->runtime.sbuffer_used - 1;
+ while (last_i > 0) {
+ ptc = (tGPspoint *)gpd->runtime.sbuffer + last_i;
+ if (ptc->pressure > 0.001f) {
+ break;
+ }
+ else {
+ gpd->runtime.sbuffer_used = last_i - 1;
+ CLAMP_MIN(gpd->runtime.sbuffer_used, 1);
+ }
+
+ last_i--;
+ }
+ }
/* Since strokes are so fine,
* when using their depth we need a margin otherwise they might get missed. */
int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
@@ -1187,6 +1362,9 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
}
}
+ /* Smooth any point created with fake events when the mouse/pen move very fast. */
+ gp_smooth_fake_segments(p);
+
pt = gps->points;
dvert = gps->dvert;
@@ -1834,6 +2012,7 @@ static void gp_set_default_eraser(Main *bmain, Brush *brush_dft)
/* initialize a drawing brush */
static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
{
+ Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = CTX_data_tool_settings(C);
@@ -1842,7 +2021,7 @@ 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_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
changed = true;
}
/* be sure curves are initializated */
@@ -2489,10 +2668,10 @@ static void gpencil_draw_cursor_set(tGPsdata *p)
#if 0
Brush *brush = p->brush;
if ((p->paintmode == GP_PAINTMODE_ERASER) || (brush->gpencil_tool == GPAINT_TOOL_ERASE)) {
- WM_cursor_modal_set(p->win, BC_CROSSCURSOR); /* XXX need a better cursor */
+ WM_cursor_modal_set(p->win, WM_CURSOR_CROSS); /* XXX need a better cursor */
}
else {
- WM_cursor_modal_set(p->win, CURSOR_NONE);
+ WM_cursor_modal_set(p->win, WM_CURSOR_NONE);
}
#endif
}
@@ -2569,7 +2748,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p)
/* ------------------------------- */
/* create a new stroke point at the point indicated by the painting context */
-static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
+static void gpencil_draw_apply(
+ bContext *C, wmOperator *op, tGPsdata *p, Depsgraph *depsgraph, bool is_fake)
{
bGPdata *gpd = p->gpd;
tGPspoint *pt = NULL;
@@ -2598,7 +2778,7 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
}
/* try to add point */
- short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
/* handle errors while adding point */
if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) {
@@ -2612,12 +2792,12 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra
/* XXX We only need to reuse previous point if overflow! */
if (ok == GP_STROKEADD_OVERFLOW) {
p->inittime = p->ocurtime;
- gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime);
+ gp_stroke_addpoint(p, p->mvalo, p->opressure, p->ocurtime, is_fake);
}
else {
p->inittime = p->curtime;
}
- gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
+ gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime, is_fake);
}
else if (ok == GP_STROKEADD_INVALID) {
/* the painting operation cannot continue... */
@@ -2823,8 +3003,13 @@ static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide)
}
/* handle draw event */
-static void gpencil_draw_apply_event(
- bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
+static void gpencil_draw_apply_event(bContext *C,
+ wmOperator *op,
+ const wmEvent *event,
+ Depsgraph *depsgraph,
+ float x,
+ float y,
+ const bool is_fake)
{
tGPsdata *p = op->customdata;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
@@ -2977,10 +3162,10 @@ static void gpencil_draw_apply_event(
/* create fake events */
float tmp[2];
copy_v2_v2(tmp, p->mval);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
if (len_v2v2(p->mval, p->mvalo)) {
sub_v2_v2v2(pt, p->mval, p->mvalo);
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], false);
}
copy_v2_v2(p->mval, tmp);
}
@@ -3011,7 +3196,7 @@ static void gpencil_draw_apply_event(
RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
/* apply the current latest drawing point */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, is_fake);
/* force refresh */
/* just active area for now, since doing whole screen is too slow */
@@ -3077,7 +3262,7 @@ static int gpencil_draw_exec(bContext *C, wmOperator *op)
}
/* apply this data as necessary now (as per usual) */
- gpencil_draw_apply(C, op, p, depsgraph);
+ gpencil_draw_apply(C, op, p, depsgraph, false);
}
RNA_END;
@@ -3211,7 +3396,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (paintmode != GP_PAINTMODE_ERASER) {
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
if ((gpl) && ((gpl->flag & GP_LAYER_LOCKED) || (gpl->flag & GP_LAYER_HIDE))) {
- BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hide");
+ BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
}
@@ -3250,8 +3435,6 @@ 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... */
-
/* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
gpencil_draw_toggle_eraser_cursor(C, p, true);
@@ -3272,7 +3455,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
p->status = GP_STATUS_PAINTING;
/* handle the initial drawing - i.e. for just doing a simple dot */
- gpencil_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(
+ C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f, false);
op->flag |= OP_IS_MODAL_CURSOR_REGION;
}
else {
@@ -3389,24 +3573,21 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
BLI_insertlinkbefore(&gpf->strokes, gpf->strokes.first, gps);
}
-/* add events for missing mouse movements when the artist draw very fast */
-static void gpencil_add_missing_events(bContext *C,
- wmOperator *op,
- const wmEvent *event,
- tGPsdata *p)
+/* Add fake events for missing mouse movements when the artist draw very fast */
+static bool gpencil_add_fake_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
{
Brush *brush = p->brush;
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
int input_samples = brush->gpencil_settings->input_samples;
-
+ bool added_events = false;
/* ensure sampling when using circular guide */
if (guide->use_guide && (guide->type == GP_GUIDE_CIRCULAR)) {
input_samples = GP_MAX_INPUT_SAMPLES;
}
if (input_samples == 0) {
- return;
+ return added_events;
}
RegionView3D *rv3d = p->ar->regiondata;
@@ -3456,7 +3637,8 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, 0.5f);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
else if (dist >= factor) {
int slices = 2 + (int)((dist - 1.0) / factor);
@@ -3465,9 +3647,11 @@ static void gpencil_add_missing_events(bContext *C,
interp_v2_v2v2(pt, a, b, n * i);
sub_v2_v2v2(pt, b, pt);
/* create fake event */
- gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]);
+ gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1], true);
+ added_events = true;
}
}
+ return added_events;
}
/* events handling during interactive drawing part of operator */
@@ -3476,6 +3660,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
tGPsdata *p = op->customdata;
ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
+ tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
+
/* default exit state - pass through to support MMB view nav, etc. */
int estate = OPERATOR_PASS_THROUGH;
@@ -3500,7 +3686,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* special mode for editing control points */
if (p->paintmode == GP_PAINTMODE_SET_CP) {
wmWindow *win = p->win;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
bool drawmode = false;
switch (event->type) {
@@ -3598,7 +3784,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
@@ -3772,11 +3959,23 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* handle drawing event */
/* printf("\t\tGP - add point\n"); */
+ int size_before = p->gpd->runtime.sbuffer_used;
+ bool added_events = false;
if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) {
- gpencil_add_missing_events(C, op, event, p);
+ added_events = gpencil_add_fake_events(C, op, event, p);
}
- gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f);
+ gpencil_draw_apply_event(C, op, event, CTX_data_depsgraph_pointer(C), 0.0f, 0.0f, false);
+ int size_after = p->gpd->runtime.sbuffer_used;
+
+ /* Last point of the event is always real (not fake). */
+ tGPspoint *pt = &points[size_after - 1];
+ pt->tflag &= ~GP_TPOINT_FAKE;
+
+ /* Smooth the fake events to get smoother strokes, specially at ends. */
+ if (added_events) {
+ gp_smooth_fake_events(p, size_before, size_after);
+ }
/* finish painting operation if anything went wrong just now */
if (p->status == GP_STATUS_ERROR) {
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 8d4c75d2e8c..bf7b2edb025 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -90,6 +90,7 @@
#define IN_MOVE 3
#define IN_BRUSH_SIZE 4
#define IN_BRUSH_STRENGTH 5
+#define IN_POLYLINE 6
#define SELECT_NONE 0
#define SELECT_START 1
@@ -184,6 +185,29 @@ static void gpencil_primitive_to_square(tGPDprimitive *tgpi, const float x, cons
}
}
+/* Helper to constrain a primitive */
+static void gpencil_primitive_constrain(tGPDprimitive *tgpi, bool line_mode)
+{
+ float x = tgpi->end[0] - tgpi->origin[0];
+ float y = tgpi->end[1] - tgpi->origin[1];
+
+ if (line_mode) {
+ float angle = fabsf(atan2f(y, x));
+ if (angle < 0.4f || angle > (M_PI - 0.4f)) {
+ tgpi->end[1] = tgpi->origin[1];
+ }
+ else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
+ tgpi->end[0] = tgpi->origin[0];
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+ else {
+ gpencil_primitive_to_square(tgpi, x, y);
+ }
+ }
+
/* Helper to rotate point around origin */
static void gp_rotate_v2_v2v2fl(float v[2],
const float p[2],
@@ -404,6 +428,11 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
"adjust subdivision number, Shift to align, Alt to center, E: extrude"),
UI_MAX_DRAW_STR);
}
+ else if (tgpi->type == GP_STROKE_POLYLINE) {
+ BLI_strncpy(msg_str,
+ TIP_("Line: ESC to cancel, LMB to set, Enter/MMB to confirm, Shift to align"),
+ UI_MAX_DRAW_STR);
+ }
else if (tgpi->type == GP_STROKE_BOX) {
BLI_strncpy(msg_str,
TIP_("Rectangle: ESC to cancel, LMB set origin, Enter/MMB to confirm, WHEEL/+- "
@@ -429,7 +458,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi
UI_MAX_DRAW_STR);
}
- if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX)) {
+ if (ELEM(tgpi->type, GP_STROKE_CIRCLE, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_BOX, GP_STROKE_POLYLINE)) {
if (hasNumInput(&tgpi->num)) {
char str_offs[NUM_STR_REP_LEN];
@@ -528,7 +557,7 @@ static void gp_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D)
}
/* create a line */
-static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
+static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, bool editable)
{
const int totpoints = (tgpi->tot_edges + tgpi->tot_stored_edges);
const float step = 1.0f / (float)(tgpi->tot_edges - 1);
@@ -540,15 +569,22 @@ static void gp_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D)
a += step;
}
- float color[4];
- UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
- gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
- if (tgpi->tot_stored_edges) {
- UI_GetThemeColor4fv(TH_REDALERT, color);
- gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ if (editable) {
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_PRIMARY, color);
+ gp_primitive_set_cp(tgpi, tgpi->end, color, BIG_SIZE_CTL);
+ if (tgpi->tot_stored_edges) {
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
+ }
+ else {
+ gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ }
}
else {
- gp_primitive_set_cp(tgpi, tgpi->start, color, BIG_SIZE_CTL);
+ float color[4];
+ UI_GetThemeColor4fv(TH_REDALERT, color);
+ gp_primitive_set_cp(tgpi, tgpi->start, color, SMALL_SIZE_CTL);
}
}
@@ -693,7 +729,10 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi)
gp_primitive_rectangle(tgpi, points2D);
break;
case GP_STROKE_LINE:
- gp_primitive_line(tgpi, points2D);
+ gp_primitive_line(tgpi, points2D, true);
+ break;
+ case GP_STROKE_POLYLINE:
+ gp_primitive_line(tgpi, points2D, false);
break;
case GP_STROKE_CIRCLE:
gp_primitive_circle(tgpi, points2D);
@@ -1041,6 +1080,7 @@ static void gpencil_primitive_update(bContext *C, wmOperator *op, tGPDprimitive
gp_primitive_update_strokes(C, tgpi);
}
+/* Initialise mouse points */
static void gpencil_primitive_interaction_begin(tGPDprimitive *tgpi, const wmEvent *event)
{
copy_v2fl_v2i(tgpi->mval, event->mval);
@@ -1134,7 +1174,7 @@ 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_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* Set Draw brush. */
@@ -1164,6 +1204,10 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op)
/* set default edge count */
switch (tgpi->type) {
+ case GP_STROKE_POLYLINE: {
+ RNA_int_set(op->ptr, "edges", 8);
+ break;
+ }
case GP_STROKE_LINE: {
RNA_int_set(op->ptr, "edges", 8);
break;
@@ -1214,7 +1258,7 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent *
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* set cursor to indicate modal */
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
/* update sindicator in header */
gpencil_primitive_status_indicators(C, tgpi);
@@ -1319,21 +1363,57 @@ static void gpencil_primitive_edit_event_handling(
if (tgpi->flag == IN_CURVE_EDIT) {
if ((a < BIG_SIZE_CTL && tgpi->tot_stored_edges == 0) || b < BIG_SIZE_CTL) {
move = MOVE_ENDS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
else if (tgpi->curve) {
move = MOVE_CP;
- WM_cursor_modal_set(win, BC_HANDCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_HAND);
}
else {
- WM_cursor_modal_set(win, BC_CROSSCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
}
}
else if (tgpi->flag == IN_PROGRESS) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
switch (event->type) {
+ case LEFTMOUSE: {
+ if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ /* set control points and enter edit mode */
+ if ((ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ gpencil_primitive_add_segment(tgpi);
+ copy_v2_v2(tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->origin, tgpi->start);
+ gp_primitive_update_cps(tgpi);
+
+ tgpi->flag = IN_POLYLINE;
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
+ }
+ else {
+ tgpi->flag = IN_CURVE_EDIT;
+ gp_primitive_update_cps(tgpi);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ }
+ else if ((event->val == KM_PRESS) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
+ /* find nearest cp based on stroke end points */
+ if (move == MOVE_ENDS) {
+ tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
+ }
+ else if (move == MOVE_CP) {
+ tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
+ }
+ else {
+ tgpi->sel_cp = SELECT_NONE;
+ }
+ break;
+ }
+ else {
+ tgpi->sel_cp = SELECT_NONE;
+ }
+ break;
+ }
case MOUSEMOVE: {
if ((event->val == KM_PRESS) && tgpi->sel_cp != SELECT_NONE) {
if (tgpi->sel_cp == SELECT_START && tgpi->tot_stored_edges == 0) {
@@ -1366,31 +1446,6 @@ static void gpencil_primitive_edit_event_handling(
}
break;
}
- case LEFTMOUSE: {
- if ((event->val == KM_PRESS)) {
- /* find nearest cp based on stroke end points */
- if (move == MOVE_ENDS) {
- tgpi->sel_cp = (a < b) ? SELECT_START : SELECT_END;
- }
- else if (move == MOVE_CP) {
- tgpi->sel_cp = (c < d) ? SELECT_CP1 : SELECT_CP2;
- }
- else {
- tgpi->sel_cp = SELECT_NONE;
- }
- break;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
- /* set control points and enter edit mode */
- tgpi->flag = IN_CURVE_EDIT;
- gp_primitive_update_cps(tgpi);
- gpencil_primitive_update(C, op, tgpi);
- }
- else {
- tgpi->sel_cp = SELECT_NONE;
- }
- break;
- }
case MKEY: {
if ((event->val == KM_PRESS) && (tgpi->curve) && (ELEM(tgpi->orign_type, GP_STROKE_ARC))) {
tgpi->flip ^= 1;
@@ -1402,7 +1457,7 @@ static void gpencil_primitive_edit_event_handling(
case EKEY: {
if (tgpi->flag == IN_CURVE_EDIT && !ELEM(tgpi->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gpencil_primitive_add_segment(tgpi);
copy_v2_v2(tgpi->start, tgpi->end);
copy_v2_v2(tgpi->origin, tgpi->start);
@@ -1524,6 +1579,96 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
copy_v2_v2(tgpi->mvalo, tgpi->mval);
return OPERATOR_RUNNING_MODAL;
}
+ else if (tgpi->flag == IN_POLYLINE) {
+
+ switch (event->type) {
+
+ case ESCKEY: {
+ /* return to normal cursor and header status */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_primitive_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+ case LEFTMOUSE: {
+ if (event->val == KM_PRESS) {
+ WM_cursor_modal_set(win, WM_CURSOR_CROSS);
+ gpencil_primitive_add_segment(tgpi);
+
+ gpencil_primitive_update(C, op, tgpi);
+ copy_v2_v2(tgpi->start, tgpi->end);
+ copy_v2_v2(tgpi->origin, tgpi->end);
+ }
+ break;
+ }
+ case SPACEKEY: /* confirm */
+ case MIDDLEMOUSE:
+ case RETKEY:
+ case RIGHTMOUSE: {
+ if (event->val == KM_PRESS) {
+ tgpi->flag = IDLE;
+ tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0;
+ gp_primitive_update_strokes(C, tgpi);
+ gpencil_primitive_interaction_end(C, op, win, tgpi);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ }
+ case MOUSEMOVE: {
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
+ copy_v2_v2(tgpi->end, tgpi->mval);
+
+ if (event->shift) {
+ gpencil_primitive_constrain(tgpi, true);
+ }
+
+ gpencil_primitive_update(C, op, tgpi);
+ break;
+ }
+ case PADPLUSKEY:
+ case WHEELUPMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges + 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case PADMINUS:
+ case WHEELDOWNMOUSE: {
+ if ((event->val != KM_RELEASE)) {
+ tgpi->tot_edges = tgpi->tot_edges - 1;
+ CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES);
+ RNA_int_set(op->ptr, "edges", tgpi->tot_edges);
+ gpencil_primitive_update(C, op, tgpi);
+ }
+ break;
+ }
+ case FKEY: /* brush thickness/ brush strength */
+ {
+ if ((event->val == KM_PRESS)) {
+ if (event->shift) {
+ tgpi->prev_flag = tgpi->flag;
+ tgpi->flag = IN_BRUSH_STRENGTH;
+ }
+ else {
+ tgpi->prev_flag = tgpi->flag;
+ tgpi->flag = IN_BRUSH_SIZE;
+ }
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
+ }
+ break;
+ }
+ }
+
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
else if (tgpi->flag == IN_BRUSH_SIZE) {
switch (event->type) {
case MOUSEMOVE:
@@ -1534,11 +1679,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case MIDDLEMOUSE:
case LEFTMOUSE:
tgpi->brush_size = 0;
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
break;
case RIGHTMOUSE:
if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
gpencil_primitive_size(tgpi, true);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1557,11 +1702,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case MIDDLEMOUSE:
case LEFTMOUSE:
tgpi->brush_strength = 0.0f;
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
break;
case RIGHTMOUSE:
if (event->val == KM_RELEASE) {
- tgpi->flag = IN_CURVE_EDIT;
+ tgpi->flag = tgpi->prev_flag;
gpencil_primitive_strength(tgpi, true);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1570,7 +1715,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
copy_v2_v2(tgpi->mvalo, tgpi->mval);
return OPERATOR_RUNNING_MODAL;
}
- else if (tgpi->flag != IDLE) {
+ else if (!ELEM(tgpi->flag, IDLE) && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
gpencil_primitive_edit_event_handling(C, op, win, event, tgpi);
}
@@ -1581,24 +1726,38 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
/* TODO: Ignore if not in main region yet */
tgpi->flag = IN_PROGRESS;
gpencil_primitive_interaction_begin(tgpi, event);
+ if (ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
+ tgpi->flag = IN_POLYLINE;
+ gpencil_primitive_update(C, op, tgpi);
+ return OPERATOR_RUNNING_MODAL;
+ }
}
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
- tgpi->flag = IN_CURVE_EDIT;
- }
- else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS)) {
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
+ (!ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
/* set control points and enter edit mode */
tgpi->flag = IN_CURVE_EDIT;
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
- (tgpi->type != GP_STROKE_CURVE)) {
+ (!ELEM(tgpi->type, GP_STROKE_CURVE, GP_STROKE_POLYLINE))) {
/* stop drawing primitive */
tgpi->flag = IDLE;
gpencil_primitive_interaction_end(C, op, win, tgpi);
/* done! */
return OPERATOR_FINISHED;
}
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_PROGRESS) &&
+ (ELEM(tgpi->type, GP_STROKE_POLYLINE))) {
+ /* set control points and enter edit mode */
+ tgpi->flag = IN_POLYLINE;
+ gpencil_primitive_update(C, op, tgpi);
+ copy_v2_v2(tgpi->mvalo, tgpi->mval);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else if ((event->val == KM_RELEASE) && (tgpi->flag == IN_MOVE)) {
+ tgpi->flag = IN_CURVE_EDIT;
+ }
else {
if (G.debug & G_DEBUG) {
printf("GP Add Primitive Modal: LEFTMOUSE %d, Status = %d\n", event->val, tgpi->flag);
@@ -1618,7 +1777,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
/* exception to cancel current stroke when we have previous strokes in buffer */
if (tgpi->tot_stored_edges > 0) {
tgpi->flag = IDLE;
- tgpi->tot_edges = 0;
+ tgpi->tot_edges = tgpi->tot_stored_edges ? 1 : 0;
gp_primitive_update_strokes(C, tgpi);
gpencil_primitive_interaction_end(C, op, win, tgpi);
/* done! */
@@ -1665,7 +1824,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
tgpi->flag = IN_MOVE;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
}
@@ -1673,12 +1832,14 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
{
if ((event->val == KM_PRESS)) {
if (event->shift) {
+ tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_STRENGTH;
}
else {
+ tgpi->prev_flag = tgpi->flag;
tgpi->flag = IN_BRUSH_SIZE;
}
- WM_cursor_modal_set(win, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NS_SCROLL);
}
break;
}
@@ -1704,7 +1865,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
case TABKEY: {
if (tgpi->flag == IN_CURVE_EDIT) {
tgpi->flag = IN_PROGRESS;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
gp_primitive_update_cps(tgpi);
gpencil_primitive_update(C, op, tgpi);
}
@@ -1712,7 +1873,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
case MOUSEMOVE: /* calculate new position */
{
- if (tgpi->flag == IN_CURVE_EDIT) {
+ if (ELEM(tgpi->flag, IN_CURVE_EDIT)) {
break;
}
/* only handle mousemove if not doing numinput */
@@ -1725,26 +1886,11 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e
}
/* Keep square if shift key */
if (event->shift) {
- float x = tgpi->end[0] - tgpi->origin[0];
- float y = tgpi->end[1] - tgpi->origin[1];
- if (tgpi->type == GP_STROKE_LINE || tgpi->curve) {
- float angle = fabsf(atan2f(y, x));
- if (angle < 0.4f || angle > (M_PI - 0.4f)) {
- tgpi->end[1] = tgpi->origin[1];
- }
- else if (angle > (M_PI_2 - 0.4f) && angle < (M_PI_2 + 0.4f)) {
- tgpi->end[0] = tgpi->origin[0];
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
- }
- else {
- gpencil_primitive_to_square(tgpi, x, y);
- }
+ gpencil_primitive_constrain(
+ tgpi, (ELEM(tgpi->type, GP_STROKE_LINE, GP_STROKE_POLYLINE) || tgpi->curve));
}
/* Center primitive if alt key */
- if (event->alt) {
+ if (event->alt && !ELEM(tgpi->type, GP_STROKE_POLYLINE)) {
tgpi->start[0] = tgpi->origin[0] - (tgpi->end[0] - tgpi->origin[0]);
tgpi->start[1] = tgpi->origin[1] - (tgpi->end[1] - tgpi->origin[1]);
}
@@ -1796,6 +1942,7 @@ void GPENCIL_OT_primitive(wmOperatorType *ot)
static EnumPropertyItem primitive_type[] = {
{GP_STROKE_BOX, "BOX", 0, "Box", ""},
{GP_STROKE_LINE, "LINE", 0, "Line", ""},
+ {GP_STROKE_POLYLINE, "POLYLINE", 0, "Polyline", ""},
{GP_STROKE_CIRCLE, "CIRCLE", 0, "Circle", ""},
{GP_STROKE_ARC, "ARC", 0, "Arc", ""},
{GP_STROKE_CURVE, "CURVE", 0, "Curve", ""},
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index b7b73c1b501..be265ed4bd5 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -832,7 +832,8 @@ void GPENCIL_OT_select_less(wmOperatorType *ot)
* from gpencil_paint.c #gp_stroke_eraser_dostroke().
* It would be great to de-duplicate the logic here sometime, but that can wait.
*/
-static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
+static bool gp_stroke_do_circle_sel(bGPdata *gpd,
+ bGPDlayer *gpl,
bGPDstroke *gps,
GP_SpaceConversion *gsc,
const int mx,
@@ -844,12 +845,14 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
const int selectmode,
const float scale)
{
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
bGPDspoint *pt1 = NULL;
bGPDspoint *pt2 = NULL;
- bGPDstroke *gps_orig = gps->runtime.gps_orig;
int x0 = 0, y0 = 0, x1 = 0, y1 = 0;
int i;
bool changed = false;
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
+ bGPDspoint *pt_active = NULL;
if (gps->totpoints == 1) {
bGPDspoint pt_temp;
@@ -862,12 +865,12 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
if (((x0 - mx) * (x0 - mx) + (y0 - my) * (y0 - my)) <= radius * radius) {
/* change selection */
if (select) {
- gps_orig->points->flag |= GP_SPOINT_SELECT;
- gps_orig->flag |= GP_STROKE_SELECT;
+ gps_active->points->flag |= GP_SPOINT_SELECT;
+ gps_active->flag |= GP_STROKE_SELECT;
}
else {
- gps_orig->points->flag &= ~GP_SPOINT_SELECT;
- gps_orig->flag &= ~GP_STROKE_SELECT;
+ gps_active->points->flag &= ~GP_SPOINT_SELECT;
+ gps_active->flag &= ~GP_STROKE_SELECT;
}
return true;
@@ -907,20 +910,24 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
*/
hit = true;
if (select) {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag |= GP_SPOINT_SELECT;
}
changed = true;
}
else {
- if (pt1->runtime.pt_orig != NULL) {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
- if (pt2->runtime.pt_orig != NULL) {
- pt2->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active = (!is_multiedit) ? pt2->runtime.pt_orig : pt2;
+ if (pt_active != NULL) {
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
changed = true;
}
@@ -935,28 +942,29 @@ static bool gp_stroke_do_circle_sel(bGPDlayer *gpl,
/* if stroke mode expand selection */
if ((hit) && (selectmode == GP_SELECTMODE_STROKE)) {
for (i = 0, pt1 = gps->points; i < gps->totpoints; i++, pt1++) {
- if (pt1->runtime.pt_orig != NULL) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if (pt_active != NULL) {
if (select) {
- pt1->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt1->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
}
}
/* expand selection to segment */
- if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) &&
- (pt1->runtime.pt_orig != NULL)) {
+ pt_active = (!is_multiedit) ? pt1->runtime.pt_orig : pt1;
+ if ((hit) && (selectmode == GP_SELECTMODE_SEGMENT) && (select) && (pt_active != NULL)) {
float r_hita[3], r_hitb[3];
bool hit_select = (bool)(pt1->flag & GP_SPOINT_SELECT);
ED_gpencil_select_stroke_segment(
- gpl, gps_orig, pt1->runtime.pt_orig, hit_select, false, scale, r_hita, r_hitb);
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
return changed;
@@ -1016,8 +1024,18 @@ static int gpencil_circle_select_exec(bContext *C, wmOperator *op)
/* find visible strokes, and select if hit */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
- changed |= gp_stroke_do_circle_sel(
- gpl, gps, &gsc, mx, my, radius, select, &rect, gpstroke_iter.diff_mat, selectmode, scale);
+ changed |= gp_stroke_do_circle_sel(gpd,
+ gpl,
+ gps,
+ &gsc,
+ mx,
+ my,
+ radius,
+ select,
+ &rect,
+ gpstroke_iter.diff_mat,
+ selectmode,
+ scale);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1090,6 +1108,8 @@ 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;
@@ -1125,36 +1145,32 @@ static int gpencil_generic_select_exec(bContext *C,
/* select/deselect points */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
bool hit = false;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? 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);
if (strokemode == false) {
- const bool is_select = (pt->runtime.pt_orig->flag & GP_SPOINT_SELECT) != 0;
+ const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0;
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(pt->runtime.pt_orig->flag, sel_op_result, GP_SPOINT_SELECT);
+ SET_FLAG_FROM_TEST(pt_active->flag, sel_op_result, GP_SPOINT_SELECT);
changed = true;
/* expand selection to segment */
if ((sel_op_result != -1) && (segmentmode)) {
- bool hit_select = (bool)(pt->runtime.pt_orig->flag & GP_SPOINT_SELECT);
+ bool hit_select = (bool)(pt_active->flag & GP_SPOINT_SELECT);
float r_hita[3], r_hitb[3];
- ED_gpencil_select_stroke_segment(gpl,
- gps->runtime.gps_orig,
- pt->runtime.pt_orig,
- hit_select,
- false,
- scale,
- r_hita,
- r_hitb);
+ ED_gpencil_select_stroke_segment(
+ gpl, gps_active, pt_active, hit_select, false, scale, r_hita, r_hitb);
}
}
}
@@ -1168,19 +1184,21 @@ 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->runtime.gps_orig);
+ const bool is_select = BKE_gpencil_stroke_select_check(gps_active);
const bool is_inside = hit;
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 (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
+ bGPDspoint *pt_active = (!is_multiedit) ? pt->runtime.pt_orig : pt;
+
if (sel_op_result) {
- pt->runtime.pt_orig->flag |= GP_SPOINT_SELECT;
+ pt_active->flag |= GP_SPOINT_SELECT;
}
else {
- pt->runtime.pt_orig->flag &= ~GP_SPOINT_SELECT;
+ pt_active->flag &= ~GP_SPOINT_SELECT;
}
}
changed = true;
@@ -1188,7 +1206,7 @@ static int gpencil_generic_select_exec(bContext *C,
}
/* Ensure that stroke selection is in sync with its points */
- BKE_gpencil_stroke_sync_selection(gps->runtime.gps_orig);
+ BKE_gpencil_stroke_sync_selection(gps_active);
}
GP_EVALUATED_STROKES_END(gpstroke_iter);
@@ -1369,6 +1387,7 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
ToolSettings *ts = CTX_data_tool_settings(C);
const float scale = ts->gp_sculpt.isect_threshold;
+ 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;
@@ -1414,13 +1433,14 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* XXX: maybe we should go from the top of the stack down instead... */
GP_EVALUATED_STROKES_BEGIN(gpstroke_iter, C, gpl, gps)
{
+ bGPDstroke *gps_active = (!is_multiedit) ? gps->runtime.gps_orig : gps;
bGPDspoint *pt;
int i;
/* firstly, check for hit-point */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
int xy[2];
- if (pt->runtime.pt_orig == NULL) {
+ if ((!is_multiedit) && (pt->runtime.pt_orig == NULL)) {
continue;
}
@@ -1437,8 +1457,8 @@ static int gpencil_select_exec(bContext *C, wmOperator *op)
/* only use this point if it is a better match than the current hit - T44685 */
if (pt_distance < hit_distance) {
hit_layer = gpl;
- hit_stroke = gps->runtime.gps_orig;
- hit_point = pt->runtime.pt_orig;
+ hit_stroke = gps_active;
+ hit_point = (!is_multiedit) ? pt->runtime.pt_orig : pt;
hit_distance = pt_distance;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 89a2a987f60..b194d28a8b8 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -1391,7 +1391,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_presets(C);
+ BKE_brush_gpencil_presets(bmain, ts);
}
/* ensure a color exists and is assigned to object */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index cb6c66ed795..bf9b69f12e1 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -834,12 +834,28 @@ void ED_drivers_editor_init(struct bContext *C, struct ScrArea *sa);
/* ************************************************ */
+typedef enum eAnimvizCalcRange {
+ /* Update motion paths at the current frame only. */
+ ANIMVIZ_CALC_RANGE_CURRENT_FRAME,
+
+ /* Try to limit updates to a close neighborhood of the current frame. */
+ ANIMVIZ_CALC_RANGE_CHANGED,
+
+ /* Update an entire range of the motion paths. */
+ ANIMVIZ_CALC_RANGE_FULL,
+} eAnimvizCalcRange;
+
+struct Depsgraph *animviz_depsgraph_build(struct Main *bmain,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct ListBase *targets);
+
void animviz_calc_motionpaths(struct Depsgraph *depsgraph,
struct Main *bmain,
struct Scene *scene,
ListBase *targets,
- bool restore,
- bool current_frame_only);
+ eAnimvizCalcRange range,
+ bool restore);
void animviz_get_object_motionpaths(struct Object *ob, ListBase *targets);
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 173ba65fc47..7ac42967dda 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -284,10 +284,18 @@ bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool
bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select_tag_update(struct Object *ob);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum ePosePathCalcRange {
+ POSE_PATH_CALC_RANGE_CURRENT_FRAME,
+ POSE_PATH_CALC_RANGE_CHANGED,
+ POSE_PATH_CALC_RANGE_FULL,
+} ePosePathCalcRange;
void ED_pose_recalculate_paths(struct bContext *C,
struct Scene *scene,
struct Object *ob,
- bool current_frame_only);
+ ePosePathCalcRange range);
+
struct Object *ED_pose_object_from_context(struct bContext *C);
/* meshlaplacian.c */
diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h
index 37090ce3421..83890c1621c 100644
--- a/source/blender/editors/include/ED_fileselect.h
+++ b/source/blender/editors/include/ED_fileselect.h
@@ -98,6 +98,8 @@ struct rcti;
struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile);
short ED_fileselect_set_params(struct SpaceFile *sfile);
+void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile);
+void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, int temp_win_size[]);
void ED_fileselect_reset_params(struct SpaceFile *sfile);
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 63ddc669ab2..0ff1b8bb40b 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -71,8 +71,15 @@ typedef struct tGPspoint {
float uv_rot; /* uv rotation for dor mode */
float rnd[3]; /* rnd value */
bool rnd_dirty; /* rnd flag */
+ short tflag; /* Internal flag */
} tGPspoint;
+/* tGPspoint->flag */
+typedef enum etGPspoint_tFlag {
+ /* Created by Fake event (used when mouse/pen move very fast while drawing). */
+ GP_TPOINT_FAKE = (1 << 0),
+} etGPspoint_tFlag;
+
/* used to sort by zdepth gpencil objects in viewport */
/* TODO: this could be a system parameter in userprefs screen */
#define GP_CACHE_BLOCK_SIZE 16
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 7d69f86dbf8..69742af9f50 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -77,6 +77,7 @@ void ED_image_mouse_pos(struct SpaceImage *sima,
struct ARegion *ar,
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 *ar, float x, float y, float *xr, float *yr);
void ED_image_point_pos__reverse(struct SpaceImage *sima,
@@ -94,6 +95,7 @@ bool ED_space_image_paint_curve(const struct bContext *C);
bool ED_space_image_check_show_maskedit(struct SpaceImage *sima, struct ViewLayer *view_layer);
bool ED_space_image_maskedit_poll(struct bContext *C);
bool ED_space_image_maskedit_mask_poll(struct bContext *C);
+bool ED_space_image_cursor_poll(struct bContext *C);
void ED_image_draw_info(struct Scene *scene,
struct ARegion *ar,
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 42e5add2ef0..16b3c9c240a 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -310,15 +310,24 @@ extern EnumPropertyItem prop_driver_create_mapping_types[];
/* -------- */
+typedef enum eDriverFCurveCreationMode {
+ DRIVER_FCURVE_LOOKUP_ONLY = 0, /* Don't add anything if not found. */
+ DRIVER_FCURVE_KEYFRAMES = 1, /* Add with keyframes, for visual tweaking. */
+ DRIVER_FCURVE_GENERATOR = 2, /* Add with generator, for script backwards compatibility. */
+ DRIVER_FCURVE_EMPTY = 3 /* Add without data, for pasting. */
+} eDriverFCurveCreationMode;
+
/* Low-level call to add a new driver F-Curve. This shouldn't be used directly for most tools,
* although there are special cases where this approach is preferable.
*/
struct FCurve *verify_driver_fcurve(struct ID *id,
const char rna_path[],
const int array_index,
- short add);
+ eDriverFCurveCreationMode creation_mode);
-struct FCurve *alloc_driver_fcurve(const char rna_path[], const int array_index, short add);
+struct FCurve *alloc_driver_fcurve(const char rna_path[],
+ const int array_index,
+ eDriverFCurveCreationMode creation_mode);
/* -------- */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index d8d62ad6f08..fc7b0d8be8f 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -380,17 +380,17 @@ float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vert
void ED_vgroup_vert_active_mirror(struct Object *ob, int def_nr);
/* mesh_data.c */
-#if 0
-void ED_mesh_geometry_add(
- struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
-#endif
-void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_verts_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_verts_remove(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_loops_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+void ED_mesh_polys_remove(struct Mesh *mesh, struct ReportList *reports, int count);
+
+void ED_mesh_geometry_clear(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index c481c19a552..38d75aa57e9 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -238,9 +238,17 @@ void ED_object_single_user(struct Main *bmain, struct Scene *scene, struct Objec
/* object motion paths */
void ED_objects_clear_paths(struct bContext *C, bool only_selected);
+
+/* Corresponds to eAnimvizCalcRange. */
+typedef enum eObjectPathCalcRange {
+ OBJECT_PATH_CALC_RANGE_CURRENT_FRAME,
+ OBJECT_PATH_CALC_RANGE_CHANGED,
+ OBJECT_PATH_CALC_RANGE_FULL,
+} eObjectPathCalcRange;
+
void ED_objects_recalculate_paths(struct bContext *C,
struct Scene *scene,
- bool current_frame_only);
+ eObjectPathCalcRange range);
/* constraints */
struct ListBase *get_active_constraints(struct Object *ob);
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
index 88cc8a85897..fec4beea809 100644
--- a/source/blender/editors/include/ED_paint.h
+++ b/source/blender/editors/include/ED_paint.h
@@ -40,13 +40,44 @@ void ED_imapaint_dirty_region(
struct Image *ima, struct ImBuf *ibuf, int x, int y, int w, int h, bool find_old);
void ED_imapaint_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
-/* paint_image_undo.c */
+/* image_undo.c */
void ED_image_undo_push_begin(const char *name, int paint_mode);
+void ED_image_undo_push_begin_with_image(const char *name,
+ struct Image *image,
+ struct ImBuf *ibuf);
+
void ED_image_undo_push_end(void);
void ED_image_undo_restore(struct UndoStep *us);
void ED_image_undosys_type(struct UndoType *ut);
+void *ED_image_paint_tile_find(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool validate);
+void *ED_image_paint_tile_push(struct ListBase *undo_tiles,
+ struct Image *ima,
+ struct ImBuf *ibuf,
+ struct ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ unsigned short **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev);
+void ED_image_paint_tile_lock_init(void);
+void ED_image_paint_tile_lock_end(void);
+
+struct ListBase *ED_image_paint_tile_list_get(void);
+
+#define ED_IMAGE_UNDO_TILE_BITS 6
+#define ED_IMAGE_UNDO_TILE_SIZE (1 << ED_IMAGE_UNDO_TILE_BITS)
+#define ED_IMAGE_UNDO_TILE_NUMBER(size) \
+ (((size) + ED_IMAGE_UNDO_TILE_SIZE - 1) >> ED_IMAGE_UNDO_TILE_BITS)
+
/* paint_curve_undo.c */
void ED_paintcurve_undo_push_begin(const char *name);
void ED_paintcurve_undo_push_end(void);
diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h
index 3ef3c0ba937..0c973f4ca88 100644
--- a/source/blender/editors/include/ED_particle.h
+++ b/source/blender/editors/include/ED_particle.h
@@ -40,12 +40,18 @@ int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
-struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
+struct PTCacheEdit *PE_get_current(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph,
struct Scene *scene,
struct Object *ob);
void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
-int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
+int PE_minmax(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ float min[3],
+ float max[3]);
struct ParticleEditSettings *PE_settings(struct Scene *scene);
/* update calls */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index d0fab134dcc..c3e61f5f2b2 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -66,6 +66,7 @@ void ED_region_do_listen(struct wmWindow *win,
void ED_region_do_layout(struct bContext *C, struct ARegion *ar);
void ED_region_do_draw(struct bContext *C, struct ARegion *ar);
void ED_region_exit(struct bContext *C, struct ARegion *ar);
+void ED_region_remove(struct bContext *C, struct ScrArea *sa, struct ARegion *ar);
void ED_region_pixelspace(struct ARegion *ar);
void ED_region_update_rect(struct ARegion *ar);
void ED_region_init(struct ARegion *ar);
@@ -238,6 +239,15 @@ struct ScrArea *ED_screen_state_toggle(struct bContext *C,
struct wmWindow *win,
struct ScrArea *sa,
const short state);
+ScrArea *ED_screen_temp_space_open(struct bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type,
+ bool dialog);
void ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
void ED_screens_navigation_bar_tools_menu_create(struct bContext *C,
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index dc7b25392e8..28280fae3a8 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -521,7 +521,9 @@ int view3d_opengl_select(struct ViewContext *vc,
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
-void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc);
+void ED_view3d_viewcontext_init(struct bContext *C,
+ struct ViewContext *vc,
+ struct Depsgraph *depsgraph);
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
void view3d_operator_needs_opengl(const struct bContext *C);
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index ffabace48c0..4e4db46adf6 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -858,9 +858,9 @@ DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
DEF_ICON_BLANK(858)
-DEF_ICON_BLANK(859)
-DEF_ICON_BLANK(860)
-DEF_ICON_BLANK(861)
+DEF_ICON(DESKTOP)
+DEF_ICON(EXTERNAL_DRIVE)
+DEF_ICON(NETWORK_DRIVE)
/* SEQUENCE / IMAGE EDITOR */
DEF_ICON(SEQ_SEQUENCER)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 702d319817f..f5721c008b2 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -524,6 +524,7 @@ bool UI_but_is_tool(const uiBut *but);
bool UI_but_is_utf8(const uiBut *but);
#define UI_but_is_decorator(but) ((but)->func == ui_but_anim_decorate_cb)
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title);
bool UI_block_is_empty(const uiBlock *block);
bool UI_block_can_add_separator(const uiBlock *block);
@@ -1810,6 +1811,7 @@ void uiLayoutSetActivateInit(uiLayout *layout, bool active);
void uiLayoutSetEnabled(uiLayout *layout, bool enabled);
void uiLayoutSetRedAlert(uiLayout *layout, bool redalert);
void uiLayoutSetAlignment(uiLayout *layout, char alignment);
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size);
void uiLayoutSetKeepAspect(uiLayout *layout, bool keepaspect);
void uiLayoutSetScaleX(uiLayout *layout, float scale);
void uiLayoutSetScaleY(uiLayout *layout, float scale);
@@ -1827,6 +1829,7 @@ bool uiLayoutGetActivateInit(uiLayout *layout);
bool uiLayoutGetEnabled(uiLayout *layout);
bool uiLayoutGetRedAlert(uiLayout *layout);
int uiLayoutGetAlignment(uiLayout *layout);
+bool uiLayoutGetFixedSize(uiLayout *layout);
bool uiLayoutGetKeepAspect(uiLayout *layout);
int uiLayoutGetWidth(uiLayout *layout);
float uiLayoutGetScaleX(uiLayout *layout);
@@ -2451,6 +2454,8 @@ void UI_widgetbase_draw_cache_end(void);
void UI_theme_init_default(void);
void UI_style_init_default(void);
+void UI_interface_tag_script_reload(void);
+
/* Special drawing for toolbar, mainly workarounds for inflexible icon sizing. */
#define USE_UI_TOOLBAR_HACK
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index efa35c84b9e..8e04db8127e 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -234,6 +234,8 @@ typedef enum ThemeColorID {
TH_DIS_MARKER,
TH_PATH_BEFORE,
TH_PATH_AFTER,
+ TH_PATH_KEYFRAME_BEFORE,
+ TH_PATH_KEYFRAME_AFTER,
TH_CAMERA_PATH,
TH_LOCK_MARKER,
@@ -281,6 +283,7 @@ typedef enum ThemeColorID {
TH_NLA_TWEAK, /* 'tweaking' track in NLA */
TH_NLA_TWEAK_DUPLI, /* error/warning flag for other strips referencing dupli strip */
+ TH_NLA_TRACK,
TH_NLA_TRANSITION,
TH_NLA_TRANSITION_SEL,
TH_NLA_META,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index bc8d25e8d9e..d33023c69a1 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -50,6 +50,7 @@ set(SRC
interface_eyedropper_datablock.c
interface_eyedropper_depth.c
interface_eyedropper_driver.c
+ interface_eyedropper_gpencil_color.c
interface_handlers.c
interface_icons.c
interface_icons_event.c
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 27a33a38b15..54fd91e5361 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -786,6 +786,8 @@ static bool ui_but_update_from_old_block(const bContext *C,
oldbut->flag = (oldbut->flag & ~flag_copy) | (but->flag & flag_copy);
oldbut->drawflag = (oldbut->drawflag & ~drawflag_copy) | (but->drawflag & drawflag_copy);
+ SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons);
+
/* 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)) {
@@ -3389,7 +3391,7 @@ static void ui_but_build_drawstr_float(uiBut *but, double value)
if (value == (double)FLT_MAX) {
STR_CONCAT(but->drawstr, slen, "inf");
}
- else if (value == (double)-FLT_MIN) {
+ else if (value == (double)-FLT_MAX) {
STR_CONCAT(but->drawstr, slen, "-inf");
}
else if (subtype == PROP_PERCENTAGE) {
@@ -6689,3 +6691,8 @@ void UI_exit(void)
ui_resources_free();
ui_but_clipboard_free();
}
+
+void UI_interface_tag_script_reload(void)
+{
+ ui_interface_tag_script_reload_queries();
+}
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index 168c6051327..c8baa1a7c7b 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -243,7 +243,7 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
}
/* create driver */
- fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
+ fcu = verify_driver_fcurve(id, path, but->rnaindex, DRIVER_FCURVE_KEYFRAMES);
if (fcu) {
ChannelDriver *driver = fcu->driver;
diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c
index 580ff527bf6..ae6a71f17e6 100644
--- a/source/blender/editors/interface/interface_context_menu.c
+++ b/source/blender/editors/interface/interface_context_menu.c
@@ -63,7 +63,14 @@
static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
{
/* Compute data path from context to property. */
+
+ /* If this returns null, we won't be able to bind shortcuts to these RNA properties.
+ * Support can be added at #wm_context_member_from_ptr. */
const char *member_id = WM_context_member_from_ptr(C, &but->rnapoin);
+ if (member_id == NULL) {
+ return NULL;
+ }
+
const char *data_path = RNA_path_from_ID_to_struct(&but->rnapoin);
const char *member_id_data_path = member_id;
@@ -90,27 +97,35 @@ static IDProperty *shortcut_property_from_rna(bContext *C, uiBut *but)
return prop;
}
-static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **prop)
+static const char *shortcut_get_operator_property(bContext *C, uiBut *but, IDProperty **r_prop)
{
if (but->optype) {
/* Operator */
- *prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL;
+ *r_prop = (but->opptr && but->opptr->data) ? IDP_CopyProperty(but->opptr->data) : NULL;
return but->optype->idname;
}
else if (but->rnaprop) {
- if (RNA_property_type(but->rnaprop) == PROP_BOOLEAN) {
+ const PropertyType rnaprop_type = RNA_property_type(but->rnaprop);
+
+ if (rnaprop_type == PROP_BOOLEAN) {
/* Boolean */
- *prop = shortcut_property_from_rna(C, but);
+ *r_prop = shortcut_property_from_rna(C, but);
+ if (*r_prop == NULL) {
+ return NULL;
+ }
return "WM_OT_context_toggle";
}
- else if (RNA_property_type(but->rnaprop) == PROP_ENUM) {
+ else if (rnaprop_type == PROP_ENUM) {
/* Enum */
- *prop = shortcut_property_from_rna(C, but);
+ *r_prop = shortcut_property_from_rna(C, but);
+ if (*r_prop == NULL) {
+ return NULL;
+ }
return "WM_OT_context_menu_enum";
}
}
- *prop = NULL;
+ *r_prop = NULL;
return NULL;
}
@@ -899,13 +914,13 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (is_array_component) {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy All to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
true);
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy Single to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -913,7 +928,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
}
else {
uiItemBooleanO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy To Selected"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy to Selected"),
ICON_NONE,
"UI_OT_copy_to_selected_button",
"all",
@@ -928,7 +943,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
if (ptr->owner_id && !is_whole_array &&
ELEM(type, PROP_BOOLEAN, PROP_INT, PROP_FLOAT, PROP_ENUM)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy As New Driver"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Copy as New Driver"),
ICON_NONE,
"UI_OT_copy_as_driver_button");
}
@@ -950,7 +965,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
but->search_func == ui_rna_collection_search_cb)) &&
ui_jump_to_target_button_poll(C)) {
uiItemO(layout,
- CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump To Target"),
+ CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"),
ICON_NONE,
"UI_OT_jump_to_target_button");
uiItemS(layout);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index 551e25a5986..72c31c7b39e 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -1849,9 +1849,17 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, const uiWidgetColors *wcol, cons
cumap = (CurveMapping *)but->poin;
}
+ float clip_size_x = BLI_rctf_size_x(&cumap->curr);
+ float clip_size_y = BLI_rctf_size_y(&cumap->curr);
+
+ /* zero-sized curve */
+ if (clip_size_x == 0.0f || clip_size_y == 0.0f) {
+ return;
+ }
+
/* calculate offset and zoom */
- float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / BLI_rctf_size_x(&cumap->curr);
- float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / BLI_rctf_size_y(&cumap->curr);
+ float zoomx = (BLI_rcti_size_x(rect) - 2.0f) / clip_size_x;
+ float zoomy = (BLI_rcti_size_y(rect) - 2.0f) / clip_size_y;
float offsx = cumap->curr.xmin - (1.0f / zoomx);
float offsy = cumap->curr.ymin - (1.0f / zoomy);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index 3c26c37b610..988dea270f5 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -69,6 +69,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_gpencil_color");
return keymap;
}
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
index 68c12fe7652..0cf357c508b 100644
--- a/source/blender/editors/interface/interface_eyedropper_color.c
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -290,7 +290,7 @@ 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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
/* add temp handler */
WM_event_add_modal_handler(C, op);
@@ -332,7 +332,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
+ ot->description = "Sample a color from the Blender window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index ffe93e48936..479cf9ccffe 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -304,7 +304,7 @@ 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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), 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 336fae45895..fd5a46e7716 100644
--- a/source/blender/editors/interface/interface_eyedropper_datablock.c
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -314,7 +314,7 @@ 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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), 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 2e51701e01d..8a48ca19db2 100644
--- a/source/blender/editors/interface/interface_eyedropper_depth.c
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -311,7 +311,7 @@ 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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), 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 e6fc52bc3bc..cc13367c190 100644
--- a/source/blender/editors/interface/interface_eyedropper_driver.c
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -180,7 +180,7 @@ 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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), 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
new file mode 100644
index 00000000000..02d4596e93c
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_gpencil_color.c
@@ -0,0 +1,324 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edinterface
+ *
+ * Eyedropper (RGB Color)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_gpencil_color
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_context.h"
+#include "BKE_gpencil.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_report.h"
+
+#include "UI_interface.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_gpencil.h"
+#include "ED_screen.h"
+#include "ED_undo.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+typedef struct EyedropperGPencil {
+ struct ColorManagedDisplay *display;
+ /** color under cursor RGB */
+ float color[3];
+} EyedropperGPencil;
+
+/* Helper: Draw status message while the user is running the operator */
+static void eyedropper_gpencil_status_indicators(bContext *C)
+{
+ char msg_str[UI_MAX_DRAW_STR];
+ BLI_strncpy(
+ msg_str, TIP_("LMB: Stroke - Shift: Fill - Shift+Ctrl: Stroke + Fill"), UI_MAX_DRAW_STR);
+
+ ED_workspace_status_text(C, msg_str);
+}
+
+/* Initialize. */
+static bool eyedropper_gpencil_init(bContext *C, wmOperator *op)
+{
+ EyedropperGPencil *eye = MEM_callocN(sizeof(EyedropperGPencil), __func__);
+
+ op->customdata = eye;
+ Scene *scene = CTX_data_scene(C);
+
+ const char *display_device;
+ display_device = scene->display_settings.display_device;
+ eye->display = IMB_colormanagement_display_get_named(display_device);
+
+ return true;
+}
+
+/* Exit and free memory. */
+static void eyedropper_gpencil_exit(bContext *C, wmOperator *op)
+{
+ /* Clear status message area. */
+ ED_workspace_status_text(C, NULL);
+
+ MEM_SAFE_FREE(op->customdata);
+}
+
+/* Set the material. */
+static void eyedropper_gpencil_color_set(bContext *C, const wmEvent *event, EyedropperGPencil *eye)
+{
+ Main *bmain = CTX_data_main(C);
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = NULL;
+
+ const bool only_stroke = ((!event->ctrl) && (!event->shift));
+ const bool only_fill = ((!event->ctrl) && (event->shift));
+ const bool both = ((event->ctrl) && (event->shift));
+
+ float col_conv[4];
+ bool found = false;
+
+ /* Convert from linear rgb space to display space because grease pencil colors are in display
+ * space, and this conversion is needed to undo the conversion to linear performed by
+ * eyedropper_color_sample_fl. */
+ if (eye->display) {
+ copy_v3_v3(col_conv, eye->color);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
+ }
+ else {
+ copy_v3_v3(col_conv, eye->color);
+ }
+
+ /* Look for a similar material in grease pencil slots. */
+ short *totcol = give_totcolp(ob);
+ for (short i = 0; i < *totcol; i++) {
+ ma = give_current_material(ob, i + 1);
+ if (ma == NULL) {
+ continue;
+ }
+
+ MaterialGPencilStyle *gp_style = ma->gp_style;
+ if (gp_style != NULL) {
+ /* Check stroke color. */
+ bool found_stroke = compare_v3v3(gp_style->stroke_rgba, col_conv, 0.01f) &&
+ (gp_style->flag & GP_STYLE_STROKE_SHOW);
+ /* Check fill color. */
+ bool found_fill = compare_v3v3(gp_style->fill_rgba, col_conv, 0.01f) &&
+ (gp_style->flag & GP_STYLE_FILL_SHOW);
+
+ if ((only_stroke) && (found_stroke) && ((gp_style->flag & GP_STYLE_FILL_SHOW) == 0)) {
+ found = true;
+ }
+ else if ((only_fill) && (found_fill) && ((gp_style->flag & GP_STYLE_STROKE_SHOW) == 0)) {
+ found = true;
+ }
+ else if ((both) && (found_stroke) && (found_fill)) {
+ found = true;
+ }
+
+ /* Found existing material. */
+ if (found) {
+ ob->actcol = i + 1;
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL);
+ return;
+ }
+ }
+ }
+
+ /* If material was not found add a new material with stroke and/or fill color
+ * depending of the secondary key (LMB: Stroke, Shift: Fill, Shift+Ctrl: Stroke/Fill)
+ */
+ int idx;
+ Material *ma_new = BKE_gpencil_object_material_new(bmain, ob, "Material", &idx);
+ WM_main_add_notifier(NC_OBJECT | ND_OB_SHADING, &ob->id);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, NULL);
+ DEG_relations_tag_update(bmain);
+
+ BLI_assert(ma_new != NULL);
+
+ MaterialGPencilStyle *gp_style_new = ma_new->gp_style;
+ BLI_assert(gp_style_new != NULL);
+
+ /* Only create Stroke (default option). */
+ if (only_stroke) {
+ /* Stroke color. */
+ gp_style_new->flag |= GP_STYLE_STROKE_SHOW;
+ gp_style_new->flag &= ~GP_STYLE_FILL_SHOW;
+ copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
+ zero_v4(gp_style_new->fill_rgba);
+ }
+ /* Fill Only. */
+ else if (only_fill) {
+ /* Fill color. */
+ gp_style_new->flag &= ~GP_STYLE_STROKE_SHOW;
+ gp_style_new->flag |= GP_STYLE_FILL_SHOW;
+ zero_v4(gp_style_new->stroke_rgba);
+ copy_v3_v3(gp_style_new->fill_rgba, col_conv);
+ }
+ /* Stroke and Fill. */
+ else if (both) {
+ gp_style_new->flag |= GP_STYLE_STROKE_SHOW | GP_STYLE_FILL_SHOW;
+ copy_v3_v3(gp_style_new->stroke_rgba, col_conv);
+ copy_v3_v3(gp_style_new->fill_rgba, col_conv);
+ }
+ /* Push undo for new created material. */
+ ED_undo_push(C, "Add Grease Pencil Material");
+}
+
+/* Sample the color below cursor. */
+static void eyedropper_gpencil_color_sample(bContext *C, EyedropperGPencil *eye, int mx, int my)
+{
+ eyedropper_color_sample_fl(C, mx, my, eye->color);
+}
+
+/* Cancel operator. */
+static void eyedropper_gpencil_cancel(bContext *C, wmOperator *op)
+{
+ eyedropper_gpencil_exit(C, op);
+}
+
+/* Main modal status check. */
+static int eyedropper_gpencil_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperGPencil *eye = (EyedropperGPencil *)op->customdata;
+ /* Handle modal keymap */
+ switch (event->type) {
+ case EVT_MODAL_MAP: {
+ switch (event->val) {
+ case EYE_MODAL_SAMPLE_BEGIN: {
+ return OPERATOR_RUNNING_MODAL;
+ }
+ case EYE_MODAL_CANCEL: {
+ eyedropper_gpencil_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ }
+ case EYE_MODAL_SAMPLE_CONFIRM: {
+ eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+
+ /* Create material. */
+ eyedropper_gpencil_color_set(C, event, eye);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ eyedropper_gpencil_exit(C, op);
+ return OPERATOR_FINISHED;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ break;
+ }
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE: {
+ eyedropper_gpencil_color_sample(C, eye, event->x, event->y);
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int eyedropper_gpencil_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* Init. */
+ if (eyedropper_gpencil_init(C, op)) {
+ /* Add modal temp handler. */
+ WM_event_add_modal_handler(C, op);
+ /* Status message. */
+ eyedropper_gpencil_status_indicators(C);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_gpencil_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_gpencil_init(C, op)) {
+
+ /* cleanup */
+ eyedropper_gpencil_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_PASS_THROUGH;
+ }
+}
+
+static bool eyedropper_gpencil_poll(bContext *C)
+{
+ /* Only valid if the current active object is grease pencil. */
+ Object *obact = CTX_data_active_object(C);
+ if ((obact == NULL) || (obact->type != OB_GPENCIL)) {
+ return false;
+ }
+
+ /* Test we have a window below. */
+ return (CTX_wm_window(C) != NULL);
+}
+
+void UI_OT_eyedropper_gpencil_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Eyedropper";
+ ot->idname = "UI_OT_eyedropper_gpencil_color";
+ ot->description = "Sample a color from the Blender Window and create Grease Pencil material";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_gpencil_invoke;
+ ot->modal = eyedropper_gpencil_modal;
+ ot->cancel = eyedropper_gpencil_cancel;
+ ot->exec = eyedropper_gpencil_exec;
+ ot->poll = eyedropper_gpencil_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index cc13c4004a4..83820c919c8 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -108,6 +108,7 @@ static int ui_do_but_EXIT(bContext *C,
const wmEvent *event);
static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
static void ui_textedit_string_set(uiBut *but, struct uiHandleButtonData *data, const char *str);
+static void button_tooltip_timer_reset(bContext *C, uiBut *but);
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -3258,7 +3259,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
ui_but_update(but);
- WM_cursor_modal_set(win, BC_TEXTEDITCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT);
#ifdef WITH_INPUT_IME
if (is_num_but == false && BLT_lang_is_ime_supported()) {
@@ -3967,8 +3968,11 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
uiButExtraOpIcon *op_icon = ui_but_extra_operator_icon_mouse_over_get(but, data, event);
if (op_icon) {
+ ED_region_tag_redraw(data->region);
+ button_tooltip_timer_reset(C, but);
+
ui_but_extra_operator_icon_apply(C, but, op_icon);
- button_activate_exit(C, but, data, false, false);
+ /* Note: 'but', 'data' may now be freed, don't access. */
return true;
}
@@ -4217,9 +4221,8 @@ static int ui_do_but_TEX(
}
else if (!ui_but_extra_operator_icon_mouse_over_get(but, data, event)) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
+ return WM_UI_HANDLER_BREAK;
}
-
- return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_TEXT_EDITING) {
@@ -4686,7 +4689,7 @@ static void ui_numedit_set_active(uiBut *but)
}
else {
if (data->changed_cursor == false) {
- WM_cursor_modal_set(data->window, CURSOR_X_MOVE);
+ WM_cursor_modal_set(data->window, WM_CURSOR_X_MOVE);
data->changed_cursor = true;
}
}
@@ -7494,6 +7497,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData");
data->wm = CTX_wm_manager(C);
data->window = CTX_wm_window(C);
+ BLI_assert(ar != NULL);
data->region = ar;
#ifdef USE_CONT_MOUSE_CORRECT
@@ -7565,7 +7569,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
if (but->type == UI_BTYPE_GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
- WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
+ WM_cursor_modal_set(data->window, horizontal ? WM_CURSOR_X_MOVE : WM_CURSOR_Y_MOVE);
}
else if (but->type == UI_BTYPE_NUM) {
ui_numedit_set_active(but);
@@ -8006,6 +8010,7 @@ void ui_but_execute_begin(struct bContext *UNUSED(C),
*active_back = but->active;
data = MEM_callocN(sizeof(uiHandleButtonData), "uiHandleButtonData_Fake");
but->active = data;
+ BLI_assert(ar != NULL);
data->region = ar;
}
@@ -9817,9 +9822,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
if (but && (U.pie_menu_confirm > 0) &&
(dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) {
- if (but) {
- return ui_but_pie_menu_apply(C, menu, but, true);
- }
+ return ui_but_pie_menu_apply(C, menu, but, true);
}
retval = ui_but_pie_menu_apply(C, menu, but, true);
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index b844e237366..1495fb7e716 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1583,7 +1583,6 @@ static struct {
IconTextureDrawCall normal;
IconTextureDrawCall border;
bool enabled;
- float mat[4][4];
} g_icon_draw_cache = {{{{{0}}}}};
void UI_icon_draw_cache_begin(void)
diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c
index e1ce77b8b61..b7fd953ed63 100644
--- a/source/blender/editors/interface/interface_icons_event.c
+++ b/source/blender/editors/interface/interface_icons_event.c
@@ -171,12 +171,13 @@ void icon_draw_rect_input(float x,
const bool simple_text = false;
- if ((event_type >= AKEY) || (ZKEY <= event_type)) {
+ if ((event_type >= AKEY) && (event_type <= ZKEY)) {
char str[2] = {'A' + (event_type - AKEY), '\0'};
icon_draw_rect_input_default_text(&rect, color, margin, str);
}
- if ((event_type >= F1KEY) || (F12KEY <= event_type)) {
- char str[3] = {'F', '1' + (event_type - F1KEY), '\0'};
+ else if ((event_type >= F1KEY) && (event_type <= F12KEY)) {
+ char str[4];
+ SNPRINTF(str, "F%d", 1 + (event_type - F1KEY));
icon_draw_rect_input_default_text(&rect, color, margin, str);
}
else if (event_type == LEFTSHIFTKEY) {
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 5c73b41b778..81979b1fc8f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -971,6 +971,9 @@ void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
/* interface_eyedropper_driver.c */
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
+/* interface_eyedropper_gpencil_color.c */
+void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot);
+
/* interface_util.c */
/**
@@ -993,4 +996,7 @@ void ui_rna_collection_search_cb(const struct bContext *C,
/* interface_ops.c */
bool ui_jump_to_target_button_poll(struct bContext *C);
+/* interface_queries.c */
+void ui_interface_tag_script_reload_queries(void);
+
#endif /* __INTERFACE_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 6a707b56f36..a6f8ba4560d 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -130,8 +130,8 @@ typedef struct uiItem {
} uiItem;
enum {
- UI_ITEM_FIXED = 1 << 0,
- UI_ITEM_MIN = 1 << 1,
+ UI_ITEM_AUTO_FIXED_SIZE = 1 << 0,
+ UI_ITEM_FIXED_SIZE = 1 << 1,
UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */
UI_ITEM_PROP_SEP = 1 << 3,
@@ -307,7 +307,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
return unit_x; /* No icon or name. */
}
if (layout->alignment != UI_LAYOUT_ALIGN_EXPAND) {
- layout->item.flag |= UI_ITEM_MIN;
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
}
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float margin = compact ? 1.25 : 1.50;
@@ -3269,7 +3269,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w += itemw;
litem->h = MAX2(itemh, litem->h);
@@ -3280,7 +3280,7 @@ static void ui_litem_estimate_row(uiLayout *litem)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -3326,7 +3326,7 @@ static void ui_litem_layout_row(uiLayout *litem)
extra_pixel = 0.0f;
for (item = litem->items.first; item; item = item->next) {
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
continue;
}
@@ -3342,18 +3342,19 @@ static void ui_litem_layout_row(uiLayout *litem)
x += neww;
- bool min_flag = item->flag & UI_ITEM_MIN;
+ bool min_flag = item->flag & UI_ITEM_FIXED_SIZE;
/* ignore min flag for rows with right or center alignment */
if (item->type != ITEM_BUTTON &&
ELEM(((uiLayout *)item)->alignment, UI_LAYOUT_ALIGN_RIGHT, UI_LAYOUT_ALIGN_CENTER) &&
- litem->alignment == UI_LAYOUT_ALIGN_EXPAND && ((uiItem *)litem)->flag & UI_ITEM_MIN) {
+ litem->alignment == UI_LAYOUT_ALIGN_EXPAND &&
+ ((uiItem *)litem)->flag & UI_ITEM_FIXED_SIZE) {
min_flag = false;
}
if ((neww < minw || min_flag) && w != 0) {
/* fixed size */
- item->flag |= UI_ITEM_FIXED;
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ item->flag |= UI_ITEM_AUTO_FIXED_SIZE;
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
fixedw += minw;
@@ -3362,7 +3363,7 @@ static void ui_litem_layout_row(uiLayout *litem)
}
else {
/* keep free size */
- item->flag &= ~UI_ITEM_FIXED;
+ item->flag &= ~UI_ITEM_AUTO_FIXED_SIZE;
freew += itemw;
}
}
@@ -3380,9 +3381,9 @@ static void ui_litem_layout_row(uiLayout *litem)
ui_item_size(item, &itemw, &itemh);
minw = ui_litem_min_width(itemw);
- if (item->flag & UI_ITEM_FIXED) {
+ if (item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
/* fixed minimum size items */
- if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) {
+ if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_FIXED_SIZE) {
minw = itemw;
}
itemw = ui_item_fit(
@@ -3423,7 +3424,7 @@ static void ui_litem_layout_row(uiLayout *litem)
uiItem *last_item = litem->items.last;
extra_pixel = litem->w - (x - litem->x);
if (extra_pixel > 0 && litem->alignment == UI_LAYOUT_ALIGN_EXPAND && last_free_item &&
- last_item && last_item->flag & UI_ITEM_FIXED) {
+ last_item && last_item->flag & UI_ITEM_AUTO_FIXED_SIZE) {
ui_item_move(last_free_item, 0, extra_pixel);
for (item = last_free_item->next; item; item = item->next) {
ui_item_move(item, extra_pixel, extra_pixel);
@@ -3449,7 +3450,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
for (item = litem->items.first; item; item = item->next) {
ui_item_size(item, &itemw, &itemh);
- min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN);
+ min_size_flag = min_size_flag && (item->flag & UI_ITEM_FIXED_SIZE);
litem->w = MAX2(litem->w, itemw);
litem->h += itemh;
@@ -3460,7 +3461,7 @@ static void ui_litem_estimate_column(uiLayout *litem, bool is_box)
}
if (min_size_flag) {
- litem->item.flag |= UI_ITEM_MIN;
+ litem->item.flag |= UI_ITEM_FIXED_SIZE;
}
}
@@ -4279,7 +4280,7 @@ static void ui_litem_layout_absolute(uiLayout *litem)
static void ui_litem_estimate_split(uiLayout *litem)
{
ui_litem_estimate_row(litem);
- litem->item.flag &= ~UI_ITEM_MIN;
+ litem->item.flag &= ~UI_ITEM_FIXED_SIZE;
}
static void ui_litem_layout_split(uiLayout *litem)
@@ -5099,7 +5100,7 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
/* XXX uiBut hasn't scaled yet
* we can flag the button as not expandable, depending on its size */
if (w <= 2 * UI_UNIT_X && (!but->str || but->str[0] == '\0')) {
- bitem->item.flag |= UI_ITEM_MIN;
+ bitem->item.flag |= UI_ITEM_FIXED_SIZE;
}
if (layout->child_items_layout) {
@@ -5119,6 +5120,21 @@ void ui_layout_add_but(uiLayout *layout, uiBut *but)
}
}
+void uiLayoutSetFixedSize(uiLayout *layout, bool fixed_size)
+{
+ if (fixed_size) {
+ layout->item.flag |= UI_ITEM_FIXED_SIZE;
+ }
+ else {
+ layout->item.flag &= ~UI_ITEM_FIXED_SIZE;
+ }
+}
+
+bool uiLayoutGetFixedSize(uiLayout *layout)
+{
+ return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0;
+}
+
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
{
layout->root->opcontext = opcontext;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index b3c46dda4c3..7ce4242c697 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -221,7 +221,7 @@ static int copy_as_driver_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_as_driver_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy As New Driver";
+ ot->name = "Copy as New Driver";
ot->idname = "UI_OT_copy_as_driver_button";
ot->description =
"Create a new driver with this property as input, and copy it to the "
@@ -453,7 +453,7 @@ static int unset_property_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_unset_property_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Unset property";
+ ot->name = "Unset Property";
ot->idname = "UI_OT_unset_property_button";
ot->description = "Clear the property and use default or generated value in operators";
@@ -944,7 +944,7 @@ static int copy_to_selected_button_exec(bContext *C, wmOperator *op)
static void UI_OT_copy_to_selected_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Copy To Selected";
+ ot->name = "Copy to Selected";
ot->idname = "UI_OT_copy_to_selected_button";
ot->description = "Copy property from this object to selected objects or bones";
@@ -1092,7 +1092,7 @@ static int jump_to_target_button_exec(bContext *C, wmOperator *UNUSED(op))
static void UI_OT_jump_to_target_button(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Jump To Target";
+ ot->name = "Jump to Target";
ot->idname = "UI_OT_jump_to_target_button";
ot->description = "Switch to the target object or bone";
@@ -1751,6 +1751,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_eyedropper_id);
WM_operatortype_append(UI_OT_eyedropper_depth);
WM_operatortype_append(UI_OT_eyedropper_driver);
+ WM_operatortype_append(UI_OT_eyedropper_gpencil_color);
}
/**
diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c
index 1c3d99d8bd2..34b1070f8b4 100644
--- a/source/blender/editors/interface/interface_query.c
+++ b/source/blender/editors/interface/interface_query.c
@@ -137,15 +137,15 @@ bool ui_but_has_array_value(const uiBut *but)
PROP_COORDS));
}
+static wmOperatorType *g_ot_tool_set_by_id = NULL;
bool UI_but_is_tool(const uiBut *but)
{
/* very evil! */
if (but->optype != NULL) {
- static wmOperatorType *ot = NULL;
- if (ot == NULL) {
- ot = WM_operatortype_find("WM_OT_tool_set_by_id", false);
+ if (g_ot_tool_set_by_id == NULL) {
+ g_ot_tool_set_by_id = WM_operatortype_find("WM_OT_tool_set_by_id", false);
}
- if (but->optype == ot) {
+ if (but->optype == g_ot_tool_set_by_id) {
return true;
}
}
@@ -463,14 +463,33 @@ bool ui_block_is_popup_any(const uiBlock *block)
return (ui_block_is_menu(block) || ui_block_is_popover(block) || ui_block_is_pie_menu(block));
}
-bool UI_block_is_empty(const uiBlock *block)
+static const uiBut *ui_but_next_non_separator(const uiBut *but)
{
- for (const uiBut *but = block->buttons.first; but; but = but->next) {
+ for (; but; but = but->next) {
if (!ELEM(but->type, UI_BTYPE_SEPR, UI_BTYPE_SEPR_LINE)) {
- return false;
+ return but;
}
}
- return true;
+ return NULL;
+}
+
+bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title)
+{
+ const uiBut *but = block->buttons.first;
+ if (skip_title) {
+ /* Skip the first label, since popups often have a title,
+ * we may want to consider the block empty in this case. */
+ but = ui_but_next_non_separator(but);
+ if (but && but->type == UI_BTYPE_LABEL) {
+ but = but->next;
+ }
+ }
+ return (ui_but_next_non_separator(but) == NULL);
+}
+
+bool UI_block_is_empty(const uiBlock *block)
+{
+ return UI_block_is_empty_ex(block, false);
}
bool UI_block_can_add_separator(const uiBlock *block)
@@ -596,3 +615,14 @@ ARegion *ui_screen_region_find_mouse_over(bScreen *screen, const wmEvent *event)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Manage Internal State
+ * \{ */
+
+void ui_interface_tag_script_reload_queries(void)
+{
+ g_ot_tool_set_by_id = NULL;
+}
+
+/** \} */
diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c
index ab3a86ec9e1..fed3c0b3d11 100644
--- a/source/blender/editors/interface/interface_region_menu_popup.c
+++ b/source/blender/editors/interface/interface_region_menu_popup.c
@@ -474,7 +474,7 @@ void UI_popup_menu_end(bContext *C, uiPopupMenu *pup)
bool UI_popup_menu_end_or_cancel(bContext *C, uiPopupMenu *pup)
{
- if (!UI_block_is_empty(pup->block)) {
+ if (!UI_block_is_empty_ex(pup->block, true)) {
UI_popup_menu_end(C, pup);
return true;
}
diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c
index 028d99ac052..cd0421dde09 100644
--- a/source/blender/editors/interface/interface_region_popover.c
+++ b/source/blender/editors/interface/interface_region_popover.c
@@ -334,7 +334,8 @@ int UI_popover_panel_invoke(bContext *C, const char *idname, bool keep_open, Rep
}
if (block) {
- UI_block_active_only_flagged_buttons(C, CTX_wm_region(C), block);
+ uiPopupBlockHandle *handle = block->handle;
+ UI_block_active_only_flagged_buttons(C, handle->region, block);
}
return OPERATOR_INTERFACE;
}
diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c
index 2073117d51c..63dee77e90e 100644
--- a/source/blender/editors/interface/interface_region_popup.c
+++ b/source/blender/editors/interface/interface_region_popup.c
@@ -765,7 +765,7 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C,
UI_but_tooltip_timer_remove(C, activebut);
}
/* standard cursor by default */
- WM_cursor_set(window, CURSOR_STD);
+ WM_cursor_set(window, WM_CURSOR_DEFAULT);
/* create handle */
handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index aac018db24e..fe484676ddd 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -3674,7 +3674,7 @@ void uiTemplateWaveform(uiLayout *layout, PointerRNA *ptr, const char *propname)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Vectorscope Template
+/** \name Vector-Scope Template
* \{ */
void uiTemplateVectorscope(uiLayout *layout, PointerRNA *ptr, const char *propname)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 0ee2ed0f338..b3e039292e1 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -4521,7 +4521,7 @@ static int widget_roundbox_set(uiBut *but, rcti *rect)
}
/* align with open menu */
- if (but->active && (but->type != UI_BTYPE_POPOVER)) {
+ if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
int direction = ui_but_menu_direction(but);
if (direction == UI_DIR_UP) {
@@ -4638,9 +4638,6 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
case UI_BTYPE_SEARCH_MENU:
wt = widget_type(UI_WTYPE_NAME);
- if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
- wt->wcol_theme = &btheme->tui.wcol_menu_back;
- }
break;
case UI_BTYPE_TAB:
@@ -4914,7 +4911,10 @@ static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
{
/* tsk, this isn't nice. */
const float unit_half = unit_size / 2;
- const float cent_x = mval_origin ? mval_origin[0] : BLI_rcti_cent_x(rect);
+ const float cent_x = mval_origin ? CLAMPIS(mval_origin[0],
+ rect->xmin + unit_size,
+ rect->xmax - unit_size) :
+ BLI_rcti_cent_x(rect);
rect->ymax -= unit_half;
rect->ymin += unit_half;
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index bea9af99c2e..c6125478571 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -371,7 +371,6 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_OBCENTER_DIA:
cp = &ts->obcenter_dia;
break;
- break;
case TH_EDGE:
cp = ts->edge;
break;
@@ -779,6 +778,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_PATH_AFTER:
cp = ts->path_after;
break;
+ case TH_PATH_KEYFRAME_BEFORE:
+ cp = ts->path_keyframe_before;
+ break;
+ case TH_PATH_KEYFRAME_AFTER:
+ cp = ts->path_keyframe_after;
+ break;
case TH_CAMERA_PATH:
cp = ts->camera_path;
break;
@@ -835,6 +840,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
cp = ts->nla_tweakdupli;
break;
+ case TH_NLA_TRACK:
+ cp = ts->nla_track;
+ break;
case TH_NLA_TRANSITION:
cp = ts->nla_transition;
break;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 4bfff5f02cf..b1a060089ee 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -1263,7 +1263,7 @@ void UI_view2d_view_restore(const bContext *C)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Gridline Drawing
+/** \name Grid-Line Drawing
* \{ */
/* Draw a constant grid in given 2d-region */
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 032fb7e4cc2..5cf7cb4e7c4 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -256,13 +256,13 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
RNA_int_set(op->ptr, "deltay", 0);
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
@@ -1113,13 +1113,13 @@ static int view_zoomdrag_invoke(bContext *C, wmOperator *op, const wmEvent *even
}
if (v2d->keepofs & V2D_LOCKOFS_X) {
- WM_cursor_modal_set(window, BC_NS_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NS_SCROLL);
}
else if (v2d->keepofs & V2D_LOCKOFS_Y) {
- WM_cursor_modal_set(window, BC_EW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_EW_SCROLL);
}
else {
- WM_cursor_modal_set(window, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(window, WM_CURSOR_NSEW_SCROLL);
}
/* add temp handler */
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index aac4da12658..573dfcde88a 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -604,6 +604,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemL(row, IFACE_("Options:"), ICON_NONE);
row = uiLayoutRow(box, false);
+ uiItemR(row, imfptr, "relative_path", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(box, false);
uiItemR(row, imfptr, "set_frame_range", 0, NULL, ICON_NONE);
row = uiLayoutRow(box, false);
@@ -691,7 +694,7 @@ void WM_OT_alembic_import(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_ALEMBIC,
FILE_BLENDER,
FILE_SAVE,
- WM_FILESEL_FILEPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c
index 7e89ed9511f..837c5b1c6bd 100644
--- a/source/blender/editors/lattice/editlattice_select.c
+++ b/source/blender/editors/lattice/editlattice_select.c
@@ -89,8 +89,9 @@ bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool ED_lattice_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -634,11 +635,12 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base)
bool ED_lattice_select_pick(
bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
BPoint *bp = NULL;
Base *basact = NULL;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
vc.mval[0] = mval[0];
vc.mval[1] = mval[1];
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index b4ef2620895..7afd72f33c9 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -148,9 +148,10 @@ static void edbm_bevel_update_header(bContext *C, wmOperator *op)
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%.1f%%", RNA_float_get(op->ptr, "offset_pct"));
}
else {
+ double offset_val = (double)RNA_float_get(op->ptr, "offset");
bUnit_AsString2(offset_str,
NUM_STR_REP_LEN,
- (double)RNA_float_get(op->ptr, "offset"),
+ offset_val * sce->unit.scale_length,
3,
B_UNIT_LENGTH,
&sce->unit,
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 283e147b77b..4a511bbb5a2 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -455,7 +455,7 @@ void MESH_OT_bisect(struct wmOperatorType *ot)
0.00001,
0.1);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
#ifdef USE_GIZMO
WM_gizmogrouptype_append(MESH_GGT_bisect);
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
index 7155348fed5..993898bddd5 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin_gizmo.c
@@ -522,7 +522,6 @@ typedef struct GizmoGroupData_SpinRedo {
PropertyRNA *prop_axis_no;
PropertyRNA *prop_angle;
- float rotate_axis[3];
#ifdef USE_ANGLE_Z_ORIENT
/* Apply 'orient_mat' for the final value. */
float orient_axis_relative[3];
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 370cc6a2a6d..ec740447f93 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -101,17 +101,19 @@ static int bm_face_isect_pair_swap(BMFace *f, void *UNUSED(user_data))
/**
* Use for intersect and boolean.
*/
-static void edbm_intersect_select(BMEditMesh *em)
+static void edbm_intersect_select(BMEditMesh *em, bool do_select)
{
- BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+ if (do_select) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
- BMIter iter;
- BMEdge *e;
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BM_edge_select_set(em->bm, e, true);
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(em->bm, e, true);
+ }
}
}
}
@@ -210,10 +212,9 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
em->bm, BM_elem_cb_check_hflag_enabled_simple(const BMFace *, BM_ELEM_SELECT));
}
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
@@ -317,10 +318,9 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
boolean_operation,
eps);
- if (has_isect) {
- edbm_intersect_select(em);
- }
- else {
+ edbm_intersect_select(em, has_isect);
+
+ if (!has_isect) {
isect_len++;
}
}
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 61f9dc43c0f..395c614f328 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -2777,7 +2777,7 @@ static int knifetool_invoke(bContext *C, wmOperator *op, const wmEvent *event)
op->flag |= OP_IS_MODAL_CURSOR_REGION;
/* add a modal handler for this operator - handles loop selection */
- WM_cursor_modal_set(CTX_wm_window(C), BC_KNIFECURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_KNIFE);
WM_event_add_modal_handler(C, op);
knifetool_update_mval_i(kcd, event->mval);
@@ -2804,8 +2804,8 @@ wmKeyMap *knifetool_modal_keymap(wmKeyConfig *keyconf)
static const EnumPropertyItem modal_items[] = {
{KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
{KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
- {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
- {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
+ {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap to Midpoints On", ""},
+ {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap to Midpoints Off", ""},
{KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
{KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
{KNF_MODAL_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""},
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index 3d34a4ad3b5..a709bd010aa 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -22,6 +22,7 @@
*/
#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
@@ -142,10 +143,21 @@ static int knifeproject_exec(bContext *C, wmOperator *op)
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- /* not essential, but switch out of vertex mode since the
- * selected regions wont be nicely isolated after flushing.
- * note: call after de-select to avoid selection flushing */
- EDBM_selectmode_disable(scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (ob->type == OB_MESH) {
+ Mesh *me = (Mesh *)ob->data;
+ BMEditMesh *embm = me->edit_mesh;
+ if (embm) {
+ /* not essential, but switch out of vertex mode since the
+ * selected regions wont be nicely isolated after flushing.
+ * note: call after de-select to avoid selection flushing.
+ * note: do this on all participating meshes so this is in sync
+ * e.g. for later selection picking, see T68852.*/
+ EDBM_selectmode_disable(scene, embm, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+ }
+ }
+ }
+ CTX_DATA_END;
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG);
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 3be94cf99c1..3c3e91e8afe 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -386,7 +386,6 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event)
bool ok = true;
if (is_interactive == false) {
if (exec_data.base_index >= bases_len) {
- return OPERATOR_CANCELLED;
ok = false;
}
else {
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 6d51e1d3393..8d98a3bf231 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -101,16 +101,21 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BMIter face_iter;
/* Delete all unmasked faces */
+ const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
+ BLI_assert(cd_vert_mask_offset != -1);
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
float mask_threshold = RNA_float_get(op->ptr, "mask_threshold");
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- bool delete_face = false;
+ bool keep_face = true;
BM_ITER_ELEM (v, &face_iter, f, BM_VERTS_OF_FACE) {
- float mask = BM_elem_float_data_get(&bm->vdata, v, CD_PAINT_MASK);
- delete_face = mask < mask_threshold;
+ const float mask = BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
+ if (mask < mask_threshold) {
+ keep_face = false;
+ break;
+ }
}
- BM_elem_flag_set(f, BM_ELEM_TAG, delete_face);
+ BM_elem_flag_set(f, BM_ELEM_TAG, !keep_face);
}
BM_mesh_delete_hflag_context(bm, BM_ELEM_TAG, DEL_FACES);
@@ -173,15 +178,16 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
}
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BKE_editmesh_free_derivedmesh(em);
BKE_mesh_free(new_mesh);
new_mesh = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
- }));
+ }),
+ mesh);
- BM_mesh_free(bm);
+ BKE_editmesh_free(em);
+ MEM_freeN(em);
if (new_mesh->totvert == 0) {
BKE_mesh_free(new_mesh);
@@ -195,8 +201,6 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
Object *new_ob = ED_object_add_type(C, OB_MESH, NULL, ob->loc, ob->rot, false, local_view_bits);
BKE_mesh_nomain_to_mesh(new_mesh, new_ob->data, new_ob, &CD_MASK_EVERYTHING, true);
- BKE_mesh_free(new_mesh);
-
if (RNA_boolean_get(op->ptr, "apply_shrinkwrap")) {
BKE_shrinkwrap_mesh_nearest_surface_deform(C, new_ob, ob);
}
@@ -211,6 +215,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
}
}
+ BKE_mesh_calc_normals(new_ob->data);
+
WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, new_ob);
BKE_mesh_batch_cache_dirty_tag(new_ob->data, BKE_MESH_BATCH_DIRTY_ALL);
DEG_relations_tag_update(bmain);
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index cad9e9a3d06..3e59a884696 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -2642,8 +2642,9 @@ bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
bool EDBM_mesh_deselect_all_multi(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
@@ -4219,7 +4220,8 @@ void MESH_OT_select_nth(wmOperatorType *ot)
void em_setup_viewcontext(bContext *C, ViewContext *vc)
{
- ED_view3d_viewcontext_init(C, vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, vc, depsgraph);
if (vc->obedit) {
vc->em = BKE_editmesh_from_object(vc->obedit);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 0c4db012786..a20ae5fc1ac 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3161,7 +3161,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
}
MEM_freeN(objects);
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vertices", count_multi);
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi);
return OPERATOR_FINISHED;
}
@@ -3872,7 +3872,7 @@ void MESH_OT_knife_cut(wmOperatorType *ot)
/* internal */
RNA_def_int(
- ot->srna, "cursor", BC_KNIFECURSOR, 0, BC_NUMCURSORS, "Cursor", "", 0, BC_NUMCURSORS);
+ ot->srna, "cursor", WM_CURSOR_KNIFE, 0, WM_CURSOR_NUM, "Cursor", "", 0, WM_CURSOR_NUM);
}
/** \} */
@@ -3946,6 +3946,61 @@ static Base *mesh_separate_tagged(
return base_new;
}
+static Base *mesh_separate_arrays(Main *bmain,
+ Scene *scene,
+ ViewLayer *view_layer,
+ Base *base_old,
+ BMesh *bm_old,
+ BMVert **verts,
+ uint verts_len,
+ BMEdge **edges,
+ uint edges_len,
+ BMFace **faces,
+ uint faces_len)
+{
+ Base *base_new;
+ Object *obedit = base_old->object;
+ BMesh *bm_new;
+
+ bm_new = BM_mesh_create(&bm_mesh_allocsize_default,
+ &((struct BMeshCreateParams){
+ .use_toolflags = true,
+ }));
+
+ CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH.vmask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->edata, &bm_new->edata, CD_MASK_BMESH.emask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->ldata, &bm_new->ldata, CD_MASK_BMESH.lmask, CD_CALLOC, 0);
+ CustomData_copy(&bm_old->pdata, &bm_new->pdata, CD_MASK_BMESH.pmask, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bm_new->vdata, verts_len, BM_VERT);
+ CustomData_bmesh_init_pool(&bm_new->edata, edges_len, BM_EDGE);
+ CustomData_bmesh_init_pool(&bm_new->ldata, faces_len * 3, BM_LOOP);
+ CustomData_bmesh_init_pool(&bm_new->pdata, faces_len, BM_FACE);
+
+ base_new = ED_object_add_duplicate(bmain, scene, view_layer, base_old, USER_DUP_MESH);
+
+ /* normally would call directly after but in this case delay recalc */
+ /* DAG_relations_tag_update(bmain); */
+
+ /* new in 2.5 */
+ assign_matarar(bmain, base_new->object, give_matarar(obedit), *give_totcolp(obedit));
+
+ ED_object_base_select(base_new, BA_SELECT);
+
+ BM_mesh_copy_arrays(bm_old, bm_new, verts, verts_len, edges, edges_len, faces, faces_len);
+
+ for (uint i = 0; i < verts_len; i++) {
+ BM_vert_kill(bm_old, verts[i]);
+ }
+
+ BM_mesh_bm_to_me(bmain, bm_new, base_new->object->data, (&(struct BMeshToMeshParams){0}));
+
+ BM_mesh_free(bm_new);
+ ((Mesh *)base_new->object->data)->edit_mesh = NULL;
+
+ return base_new;
+}
+
static bool mesh_separate_selected(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
@@ -3959,41 +4014,6 @@ static bool mesh_separate_selected(
return (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
}
-/* flush a hflag to from verts to edges/faces */
-static void bm_mesh_hflag_flush_vert(BMesh *bm, const char hflag)
-{
- BMEdge *e;
- BMLoop *l_iter;
- BMLoop *l_first;
- BMFace *f;
-
- BMIter eiter;
- BMIter fiter;
-
- bool ok;
-
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e->v1, hflag) && BM_elem_flag_test(e->v2, hflag)) {
- BM_elem_flag_enable(e, hflag);
- }
- else {
- BM_elem_flag_disable(e, hflag);
- }
- }
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- ok = true;
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (!BM_elem_flag_test(l_iter->v, hflag)) {
- ok = false;
- break;
- }
- } while ((l_iter = l_iter->next) != l_first);
-
- BM_elem_flag_set(f, hflag, ok);
- }
-}
-
/**
* Sets an object to a single material. from one of its slots.
*
@@ -4109,72 +4129,64 @@ static bool mesh_separate_material(
static bool mesh_separate_loose(
Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base_old, BMesh *bm_old)
{
- int i;
- BMEdge *e;
- BMVert *v_seed;
- BMWalker walker;
- bool result = false;
- int max_iter = bm_old->totvert;
+ /* Without this, we duplicate the object mode mesh for each loose part.
+ * This can get very slow especially for large meshes with many parts
+ * which would duplicate the mesh on entering edit-mode. */
+ const bool clear_object_data = true;
- /* Clear all selected vertices */
- BM_mesh_elem_hflag_disable_all(bm_old, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ bool result = false;
- /* A "while (true)" loop should work here as each iteration should
- * select and remove at least one vertex and when all vertices
- * are selected the loop will break out. But guard against bad
- * behavior by limiting iterations to the number of vertices in the
- * original mesh.*/
- for (i = 0; i < max_iter; i++) {
- int tot = 0;
- /* Get a seed vertex to start the walk */
- v_seed = BM_iter_at_index(bm_old, BM_VERTS_OF_MESH, NULL, 0);
+ BMVert **vert_groups = MEM_mallocN(sizeof(*vert_groups) * bm_old->totvert, __func__);
+ BMEdge **edge_groups = MEM_mallocN(sizeof(*edge_groups) * bm_old->totedge, __func__);
+ BMFace **face_groups = MEM_mallocN(sizeof(*face_groups) * bm_old->totface, __func__);
+
+ int(*groups)[3] = NULL;
+ int groups_len = BM_mesh_calc_edge_groups_as_arrays(
+ bm_old, vert_groups, edge_groups, face_groups, &groups);
+ if (groups_len <= 1) {
+ goto finally;
+ }
+
+ if (clear_object_data) {
+ ED_mesh_geometry_clear(base_old->object->data);
+ }
+
+ /* Separate out all groups except the first. */
+ uint group_ofs[3] = {UNPACK3(groups[0])};
+ for (int i = 1; i < groups_len; i++) {
+ Base *base_new = mesh_separate_arrays(bmain,
+ scene,
+ view_layer,
+ base_old,
+ bm_old,
+ vert_groups + group_ofs[0],
+ groups[i][0],
+ edge_groups + group_ofs[1],
+ groups[i][1],
+ face_groups + group_ofs[2],
+ groups[i][2]);
+ result |= (base_new != NULL);
- /* No vertices available, can't do anything */
- if (v_seed == NULL) {
- break;
- }
+ group_ofs[0] += groups[i][0];
+ group_ofs[1] += groups[i][1];
+ group_ofs[2] += groups[i][2];
+ }
- /* Select the seed explicitly, in case it has no edges */
- if (!BM_elem_flag_test(v_seed, BM_ELEM_TAG)) {
- BM_elem_flag_enable(v_seed, BM_ELEM_TAG);
- tot++;
- }
+ Mesh *me_old = base_old->object->data;
+ BMEditMesh *em_old = me_old->edit_mesh;
- /* Walk from the single vertex, selecting everything connected
- * to it */
- BMW_init(&walker,
- bm_old,
- BMW_VERT_SHELL,
- BMW_MASK_NOP,
- BMW_MASK_NOP,
- BMW_MASK_NOP,
- BMW_FLAG_NOP,
- BMW_NIL_LAY);
+ BM_mesh_elem_hflag_disable_all(em_old->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- for (e = BMW_begin(&walker, v_seed); e; e = BMW_step(&walker)) {
- if (!BM_elem_flag_test(e->v1, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
- tot++;
- }
- if (!BM_elem_flag_test(e->v2, BM_ELEM_TAG)) {
- BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
- tot++;
- }
- }
- BMW_end(&walker);
-
- if (bm_old->totvert == tot) {
- /* Every vertex selected, nothing to separate, work is done */
- break;
- }
+ if (clear_object_data) {
+ BM_mesh_bm_to_me(NULL, em_old->bm, me_old, (&(struct BMeshToMeshParams){0}));
+ }
- /* Flush the selection to get edge/face selections matching
- * the vertex selection */
- bm_mesh_hflag_flush_vert(bm_old, BM_ELEM_TAG);
+finally:
+ MEM_freeN(vert_groups);
+ MEM_freeN(edge_groups);
+ MEM_freeN(face_groups);
- /* Move selection into a separate object */
- result |= (mesh_separate_tagged(bmain, scene, view_layer, base_old, bm_old) != NULL);
- }
+ MEM_freeN(groups);
return result;
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 569994bead1..7007ff29401 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -880,14 +880,14 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_loose)
{
- if (calc_edges_loose && mesh->totedge) {
- BKE_mesh_calc_edges_loose(mesh);
- }
-
if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0)) {
BKE_mesh_calc_edges(mesh, calc_edges, true);
}
+ if (calc_edges_loose && mesh->totedge) {
+ BKE_mesh_calc_edges_loose(mesh);
+ }
+
/* Default state is not to have tessface's so make sure this is the case. */
BKE_mesh_tessface_clear(mesh);
@@ -1023,73 +1023,104 @@ static void mesh_add_polys(Mesh *mesh, int len)
mesh->totpoly = totpoly;
}
-static void mesh_remove_verts(Mesh *mesh, int len)
+/* -------------------------------------------------------------------- */
+/** \name Add Geometry
+ * \{ */
+
+void ED_mesh_verts_add(Mesh *mesh, ReportList *reports, int count)
{
- int totvert;
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode");
+ return;
+ }
+ mesh_add_verts(mesh, count);
+}
- if (len == 0) {
+void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode");
+ return;
+ }
+ mesh_add_edges(mesh, count);
+}
+
+void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode");
return;
}
+ mesh_add_loops(mesh, count);
+}
- totvert = mesh->totvert - len;
- CustomData_free_elem(&mesh->vdata, totvert, len);
+void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
+{
+ if (mesh->edit_mesh) {
+ BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode");
+ return;
+ }
+ mesh_add_polys(mesh, count);
+}
- /* set final vertex list size */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Geometry
+ * \{ */
+
+static void mesh_remove_verts(Mesh *mesh, int len)
+{
+ if (len == 0) {
+ return;
+ }
+ const int totvert = mesh->totvert - len;
+ CustomData_free_elem(&mesh->vdata, totvert, len);
mesh->totvert = totvert;
}
static void mesh_remove_edges(Mesh *mesh, int len)
{
- int totedge;
-
if (len == 0) {
return;
}
-
- totedge = mesh->totedge - len;
+ const int totedge = mesh->totedge - len;
CustomData_free_elem(&mesh->edata, totedge, len);
-
mesh->totedge = totedge;
}
-#if 0
-void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
+static void mesh_remove_loops(Mesh *mesh, int len)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add geometry in edit mode");
+ if (len == 0) {
return;
}
-
- if (verts) {
- mesh_add_verts(mesh, verts);
- }
- if (edges) {
- mesh_add_edges(mesh, edges);
- }
- if (faces) {
- mesh_add_faces(mesh, faces);
- }
+ const int totloop = mesh->totloop - len;
+ CustomData_free_elem(&mesh->ldata, totloop, len);
+ mesh->totloop = totloop;
}
-#endif
-void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
+static void mesh_remove_polys(Mesh *mesh, int len)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add edges in edit mode");
+ if (len == 0) {
return;
}
-
- mesh_add_edges(mesh, count);
+ const int totpoly = mesh->totpoly - len;
+ CustomData_free_elem(&mesh->pdata, totpoly, len);
+ mesh->totpoly = totpoly;
}
-void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_verts_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add vertices in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode");
+ return;
+ }
+ else if (count > mesh->totvert) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains");
return;
}
- mesh_add_verts(mesh, count);
+ mesh_remove_verts(mesh, count);
}
void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
@@ -1106,40 +1137,44 @@ void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count)
mesh_remove_edges(mesh, count);
}
-void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_loops_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot remove vertices in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove loops in edit mode");
return;
}
- else if (count > mesh->totvert) {
- BKE_report(reports, RPT_ERROR, "Cannot remove more vertices than the mesh contains");
+ else if (count > mesh->totloop) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more loops than the mesh contains");
return;
}
- mesh_remove_verts(mesh, count);
+ mesh_remove_loops(mesh, count);
}
-void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_polys_remove(Mesh *mesh, ReportList *reports, int count)
{
if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add loops in edit mode");
+ BKE_report(reports, RPT_ERROR, "Cannot remove polys in edit mode");
+ return;
+ }
+ else if (count > mesh->totpoly) {
+ BKE_report(reports, RPT_ERROR, "Cannot remove more polys than the mesh contains");
return;
}
- mesh_add_loops(mesh, count);
+ mesh_remove_polys(mesh, count);
}
-void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count)
+void ED_mesh_geometry_clear(Mesh *mesh)
{
- if (mesh->edit_mesh) {
- BKE_report(reports, RPT_ERROR, "Cannot add polygons in edit mode");
- return;
- }
-
- mesh_add_polys(mesh, count);
+ mesh_remove_verts(mesh, mesh->totvert);
+ mesh_remove_edges(mesh, mesh->totedge);
+ mesh_remove_loops(mesh, mesh->totloop);
+ mesh_remove_polys(mesh, mesh->totpoly);
}
+/** \} */
+
void ED_mesh_report_mirror_ex(wmOperator *op, int totmirr, int totfail, char selectmode)
{
const char *elem_type;
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index c68f5963cbd..a918996563f 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -54,6 +54,7 @@
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_object_deform.h"
+#include "BKE_object_facemap.h"
#include "BKE_report.h"
#include "DEG_depsgraph.h"
@@ -267,6 +268,22 @@ static void join_mesh_single(Depsgraph *depsgraph,
mpoly->loopstart += *loopofs;
mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
}
+
+ /* Face maps. */
+ int *fmap = CustomData_get(pdata, *polyofs, CD_FACEMAP);
+ int *fmap_src = CustomData_get(&me->pdata, 0, CD_FACEMAP);
+
+ /* Remap to correct new face-map indices, if needed. */
+ if (fmap_src) {
+ BLI_assert(fmap != NULL);
+ int *fmap_index_map;
+ int fmap_index_map_len;
+ fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
+ BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
+ if (fmap_index_map != NULL) {
+ MEM_freeN(fmap_index_map);
+ }
+ }
}
/* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
@@ -403,7 +420,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
key->type = KEY_RELATIVE;
}
- /* first pass over objects - copying materials and vertexgroups across */
+ /* First pass over objects: Copying materials, vertex-groups & face-maps across. */
CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
/* only act if a mesh, and not the one we're joining to */
if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
@@ -422,6 +439,19 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ob->actdef = 1;
}
+ /* Join this object's face maps to the base one's. */
+ for (bFaceMap *fmap = ob_iter->fmaps.first; fmap; fmap = fmap->next) {
+ /* 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_callocN(sizeof(bFaceMap), "join faceMap");
+ memcpy(fmap_new, fmap, sizeof(bFaceMap));
+ BLI_addtail(&ob->fmaps, fmap_new);
+ }
+ }
+ if (ob->fmaps.first && ob->actfmap == 0) {
+ ob->actfmap = 1;
+ }
+
if (me->totvert) {
/* Add this object's materials to the base one's if they don't exist already
* (but only if limits not exceeded yet) */
@@ -1110,7 +1140,8 @@ bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px,
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (dist_px) {
@@ -1291,7 +1322,8 @@ bool ED_mesh_pick_vert(
return false;
}
- ED_view3d_viewcontext_init(C, &vc);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_select_id_validate(&vc);
if (use_zbuf) {
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 18ff7ae1a5e..64ae75a0ee8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -693,13 +693,14 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot)
* stiffness circle) */
bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
static MetaElem *startelem = NULL;
ViewContext vc;
int a, hits;
unsigned int buffer[MAXPICKBUF];
rcti rect;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_rcti_init_pt_radius(&rect, mval, 12);
@@ -835,8 +836,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese
bool ED_mball_deselect_all_multi(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
uint bases_len = 0;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.view_layer, vc.v3d, &bases_len);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 3d5ec3d4ed5..716ff94bbae 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -1030,7 +1030,7 @@ static int empty_drop_named_image_invoke(bContext *C, wmOperator *op, const wmEv
return OPERATOR_CANCELLED;
}
/* handled below */
- id_us_min((ID *)ima);
+ id_us_min(&ima->id);
Object *ob = NULL;
Object *ob_cursor = ED_view3d_give_object_under_cursor(C, event->mval);
@@ -1071,7 +1071,7 @@ void OBJECT_OT_drop_named_image(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Empty Image/Drop Image To Empty";
+ ot->name = "Add Empty Image/Drop Image to Empty";
ot->description = "Add an empty image type to scene with data";
ot->idname = "OBJECT_OT_drop_named_image";
@@ -2147,6 +2147,7 @@ static int convert_exec(bContext *C, wmOperator *op)
const bool gpencil_lines = RNA_boolean_get(op->ptr, "gpencil_lines");
const bool use_collections = RNA_boolean_get(op->ptr, "use_collections");
int a, mballConverted = 0;
+ bool gpencilConverted = false;
/* don't forget multiple users! */
@@ -2387,20 +2388,20 @@ static int convert_exec(bContext *C, wmOperator *op)
}
else if (target == OB_GPENCIL) {
if (ob->type != OB_CURVE) {
+ ob->flag &= ~OB_DONE;
BKE_report(
op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported.");
}
else {
- /* Create a new grease pencil object only if it was not created before.
- * All curves selected are converted as strokes of the same grease pencil object.
+ /* Create a new grease pencil object and copy transformations.
* Nurbs Surface are not supported.
*/
- if (gpencil_ob == NULL) {
- const float *cur = scene->cursor.location;
- ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
- gpencil_ob = ED_gpencil_add_object(C, scene, cur, local_view_bits);
- }
+ ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0;
+ gpencil_ob = ED_gpencil_add_object(C, scene, ob->loc, local_view_bits);
+ copy_v3_v3(gpencil_ob->rot, ob->rot);
+ copy_v3_v3(gpencil_ob->scale, ob->scale);
BKE_gpencil_convert_curve(bmain, scene, gpencil_ob, ob, false, false, true);
+ gpencilConverted = true;
}
}
}
@@ -2500,6 +2501,17 @@ static int convert_exec(bContext *C, wmOperator *op)
}
FOREACH_SCENE_OBJECT_END;
}
+ /* Remove curves converted to Grease Pencil object. */
+ if (gpencilConverted) {
+ FOREACH_SCENE_OBJECT_BEGIN (scene, ob_curve) {
+ if (ob_curve->type == OB_CURVE) {
+ if (ob_curve->flag & OB_DONE) {
+ ED_object_base_free_and_unlink(bmain, scene, ob_curve);
+ }
+ }
+ }
+ FOREACH_SCENE_OBJECT_END;
+ }
}
// XXX ED_object_editmode_enter(C, 0);
@@ -2585,7 +2597,7 @@ static Base *object_add_duplicate_internal(
DEG_id_tag_update(&obn->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
BKE_collection_object_add_from(bmain, scene, ob, obn);
}
else {
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 70a9870e6ae..bc79521ee9b 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -371,7 +371,7 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
/* copy data stored in job descriptor */
bkr.scene = scene;
@@ -435,7 +435,7 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
ob = base->object;
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
data = MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index d9baec7c3ca..9e9cfe1beed 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -879,7 +879,7 @@ static int bake(Render *re,
else {
ob_cage_eval = DEG_get_evaluated_object(depsgraph, ob_cage);
ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
}
}
}
@@ -976,7 +976,7 @@ static int bake(Render *re,
highpoly[i].ob = ob_iter;
highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER;
- highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER);
+ highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false);
/* lowpoly to highpoly transformation matrix */
@@ -992,10 +992,10 @@ static int bake(Render *re,
if (ob_cage != NULL) {
ob_cage_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_cage_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_cage_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
}
ob_low_eval->restrictflag |= OB_RESTRICT_RENDER;
- ob_low_eval->base_flag &= ~(BASE_VISIBLE | BASE_ENABLED_RENDER);
+ ob_low_eval->base_flag &= ~(BASE_VISIBLE_DEPSGRAPH | BASE_ENABLED_RENDER);
/* populate the pixel arrays with the corresponding face data for each high poly object */
if (!RE_bake_pixels_populate_from_objects(me_low,
diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c
index fcaefaf220d..a00e5e7b198 100644
--- a/source/blender/editors/object/object_collection.c
+++ b/source/blender/editors/object/object_collection.c
@@ -186,7 +186,7 @@ void COLLECTION_OT_objects_add_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Add Selected To Active Collection";
+ ot->name = "Add Selected to Active Collection";
ot->description = "Add the object to an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_add_active";
@@ -259,7 +259,7 @@ void COLLECTION_OT_objects_remove_active(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove Selected From Active Collection";
+ ot->name = "Remove Selected from Active Collection";
ot->description = "Remove the object from an object collection that contains the active object";
ot->idname = "COLLECTION_OT_objects_remove_active";
@@ -302,7 +302,7 @@ 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->name = "Remove from All Unlinked Collections";
ot->description = "Remove selected objects from all collections not used in a scene";
ot->idname = "COLLECTION_OT_objects_remove_all";
@@ -361,7 +361,7 @@ void COLLECTION_OT_objects_remove(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Remove From Collection";
+ ot->name = "Remove from Collection";
ot->description = "Remove selected objects from a collection";
ot->idname = "COLLECTION_OT_objects_remove";
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 74abe104134..70d024c7902 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -218,7 +218,7 @@ static int object_hide_view_set_exec(bContext *C, wmOperator *op)
/* Hide selected or unselected objects. */
for (Base *base = view_layer->object_bases.first; base; base = base->next) {
- if (!(base->flag & BASE_VISIBLE)) {
+ if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
continue;
}
@@ -292,7 +292,7 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS);
if (v3d->flag & V3D_LOCAL_COLLECTIONS) {
- if ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ if (lc->runtime_flag & LAYER_COLLECTION_RESTRICT_VIEWPORT) {
return OPERATOR_CANCELLED;
}
if (toggle) {
@@ -300,11 +300,11 @@ static int object_hide_collection_exec(bContext *C, wmOperator *op)
BKE_layer_collection_local_sync(view_layer, v3d);
}
else {
- BKE_layer_collection_local_isolate(view_layer, v3d, lc, extend);
+ BKE_layer_collection_isolate_local(view_layer, v3d, lc, extend);
}
}
else {
- BKE_layer_collection_isolate(scene, view_layer, lc, extend);
+ BKE_layer_collection_isolate_global(scene, view_layer, lc, extend);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -910,12 +910,25 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot)
/* ********************************************** */
/* Motion Paths */
+static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range)
+{
+ switch (range) {
+ case OBJECT_PATH_CALC_RANGE_CURRENT_FRAME:
+ return ANIMVIZ_CALC_RANGE_CURRENT_FRAME;
+ case OBJECT_PATH_CALC_RANGE_CHANGED:
+ return ANIMVIZ_CALC_RANGE_CHANGED;
+ case OBJECT_PATH_CALC_RANGE_FULL:
+ return ANIMVIZ_CALC_RANGE_FULL;
+ }
+ return ANIMVIZ_CALC_RANGE_FULL;
+}
+
/* For the objects with animation: update paths for those that have got them
* This should selectively update paths that exist...
*
* To be called from various tools that do incremental updates
*/
-void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_only)
+void ED_objects_recalculate_paths(bContext *C, Scene *scene, eObjectPathCalcRange range)
{
/* Transform doesn't always have context available to do update. */
if (C == NULL) {
@@ -923,11 +936,9 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
Main *bmain = CTX_data_main(C);
- /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
- * nested pointers, like animation data. */
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- ListBase targets = {NULL, NULL};
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ListBase targets = {NULL, NULL};
/* loop over objects in scene */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
/* set flag to force recalc, then grab path(s) from object */
@@ -936,11 +947,27 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
+ Depsgraph *depsgraph;
+ bool free_depsgraph = false;
+ /* For a single frame update it's faster to re-use existing dependency graph and avoid overhead
+ * of building all the relations and so on for a temporary one. */
+ if (range == OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
+ /* NOTE: Dependency graph will be evaluated at all the frames, but we first need to access some
+ * nested pointers, like animation data. */
+ depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ free_depsgraph = false;
+ }
+ else {
+ depsgraph = animviz_depsgraph_build(bmain, scene, view_layer, &targets);
+ free_depsgraph = true;
+ }
+
/* recalculate paths, then free */
- animviz_calc_motionpaths(depsgraph, bmain, scene, &targets, true, current_frame_only);
+ animviz_calc_motionpaths(
+ depsgraph, bmain, scene, &targets, object_path_convert_range(range), true);
BLI_freelistN(&targets);
- if (!current_frame_only) {
+ if (range != OBJECT_PATH_CALC_RANGE_CURRENT_FRAME) {
/* Tag objects for copy on write - so paths will draw/redraw
* For currently frame only we update evaluated object directly. */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) {
@@ -950,6 +977,11 @@ void ED_objects_recalculate_paths(bContext *C, Scene *scene, bool current_frame_
}
CTX_DATA_END;
}
+
+ /* Free temporary depsgraph. */
+ if (free_depsgraph) {
+ DEG_graph_free(depsgraph);
+ }
}
/* show popup to determine settings */
@@ -995,7 +1027,7 @@ static int object_calculate_paths_exec(bContext *C, wmOperator *op)
CTX_DATA_END;
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1060,7 +1092,7 @@ static int object_update_paths_exec(bContext *C, wmOperator *UNUSED(op))
}
/* calculate the paths for objects that have them (and are tagged to get refreshed) */
- ED_objects_recalculate_paths(C, scene, false);
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_FULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
@@ -1515,7 +1547,7 @@ static int move_to_collection_exec(bContext *C, wmOperator *op)
}
int collection_index = RNA_property_int_get(op->ptr, prop);
- collection = BKE_collection_from_index(CTX_data_scene(C), collection_index);
+ collection = BKE_collection_from_index(scene, collection_index);
if (collection == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unexpected error, collection not found");
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 88d01936882..abcb4afa37d 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -677,7 +677,7 @@ static int modifier_apply_obdata(
/* Multires: ensure that recent sculpting is applied */
if (md_eval->type == eModifierType_Multires) {
- multires_force_update(ob);
+ multires_force_sculpt_rebuild(ob);
}
if (mmd && mmd->totlvl && mti->type == eModifierTypeType_OnlyDeform) {
@@ -2022,7 +2022,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op)
is_bind = (csmd->bind_coords != NULL);
MEM_SAFE_FREE(csmd->bind_coords);
- MEM_SAFE_FREE(csmd->delta_cache);
+ MEM_SAFE_FREE(csmd->delta_cache.deltas);
if (is_bind) {
/* toggle off */
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 0d20a07dcee..c030c551374 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1817,6 +1817,10 @@ static void single_object_users(
if (v3d) {
ID_NEW_REMAP(v3d->camera);
}
+ /* Camera pointers of markers. */
+ for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) {
+ ID_NEW_REMAP(marker->camera);
+ }
/* Making single user may affect other scenes if they share
* with current one some collections in their ViewLayer. */
@@ -2046,6 +2050,13 @@ void ED_object_single_users(Main *bmain,
single_obdata_users(bmain, scene, NULL, NULL, 0);
single_object_action_users(bmain, scene, NULL, NULL, 0);
single_mat_users_expand(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
+ * 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. */
+ libblock_relink_collection(scene->master_collection);
}
/* Relink nodetrees' pointers that have been duplicated. */
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 815cc618d4b..35762c5861e 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -40,12 +40,17 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_shrinkwrap.h"
#include "BKE_customdata.h"
#include "BKE_mesh_remesh_voxel.h"
@@ -73,13 +78,24 @@ static bool object_remesh_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
+ if (ob == NULL) {
+ return false;
+ }
+
if (BKE_object_is_in_editmode(ob)) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run from edit mode.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run from edit mode.");
return false;
}
if (ob->mode == OB_MODE_SCULPT && ob->sculpt->bm) {
- CTX_wm_operator_poll_msg_set(C, "The voxel remesher cannot run with dyntopo activated.");
+ CTX_wm_operator_poll_msg_set(C, "The remesher cannot run with dyntopo activated.");
+ return false;
+ }
+
+ if (modifiers_usesMultires(ob)) {
+ CTX_wm_operator_poll_msg_set(
+ C, "The remesher cannot run with a Multires modifier in the modifier stack.");
+ return false;
}
return ED_operator_object_active_editable_mesh(C);
@@ -101,29 +117,35 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
ED_sculpt_undo_geometry_begin(ob);
}
- new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(mesh, mesh->remesh_voxel_size);
+ float isovalue = 0.0f;
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ isovalue = mesh->remesh_voxel_size * 0.3f;
+ }
+
+ new_mesh = BKE_mesh_remesh_voxel_to_mesh_nomain(
+ mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue);
if (!new_mesh) {
return OPERATOR_CANCELLED;
}
- Mesh *obj_mesh_copy = NULL;
- if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ if (mesh->flag & ME_REMESH_FIX_POLES && mesh->remesh_voxel_adaptivity <= 0.0f) {
+ new_mesh = BKE_mesh_remesh_voxel_fix_poles(new_mesh);
+ BKE_mesh_calc_normals(new_mesh);
}
- BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+ if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) {
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_shrinkwrap_remesh_target_project(new_mesh, mesh, ob);
+ }
if (mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
+ BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
+
if (mesh->flag & ME_REMESH_SMOOTH_NORMALS) {
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -163,14 +185,26 @@ enum {
/****************** quadriflow remesh operator *********************/
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
+typedef enum eSymmetryAxes {
+ SYMMETRY_AXES_X = (1 << 0),
+ SYMMETRY_AXES_Y = (1 << 1),
+ SYMMETRY_AXES_Z = (1 << 2),
+} eSymmetryAxes;
+
typedef struct QuadriFlowJob {
/* from wmJob */
struct Object *owner;
+ struct Main *bmain;
short *stop, *do_update;
float *progress;
int target_faces;
int seed;
+ bool use_paint_symmetry;
+ eSymmetryAxes symmetry_axes;
+
bool use_preserve_sharp;
bool use_preserve_boundary;
bool use_mesh_curvature;
@@ -181,6 +215,57 @@ typedef struct QuadriFlowJob {
int success;
} QuadriFlowJob;
+static bool mesh_is_manifold_consistent(Mesh *mesh)
+{
+ /* In this check we count boundary edges as manifold. Additionally, we also
+ * check that the direction of the faces are consistent and doesn't suddenly
+ * flip
+ */
+
+ bool is_manifold_consistent = true;
+ const MLoop *mloop = mesh->mloop;
+ char *edge_faces = (char *)MEM_callocN(mesh->totedge * sizeof(char), "remesh_manifold_check");
+ int *edge_vert = (int *)MEM_malloc_arrayN(
+ mesh->totedge, sizeof(unsigned int), "remesh_consistent_check");
+
+ for (unsigned int i = 0; i < mesh->totedge; i++) {
+ edge_vert[i] = -1;
+ }
+
+ for (unsigned int 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) {
+ is_manifold_consistent = false;
+ break;
+ }
+
+ if (edge_vert[loop->e] == -1) {
+ edge_vert[loop->e] = loop->v;
+ }
+ else if (edge_vert[loop->e] == loop->v) {
+ /* Mesh has flips in the surface so it is non consistent */
+ is_manifold_consistent = false;
+ break;
+ }
+ }
+
+ if (is_manifold_consistent) {
+ /* check for wire edges */
+ for (unsigned int i = 0; i < mesh->totedge; i++) {
+ if (edge_faces[i] == 0) {
+ is_manifold_consistent = false;
+ break;
+ }
+ }
+ }
+
+ MEM_freeN(edge_faces);
+ MEM_freeN(edge_vert);
+
+ return is_manifold_consistent;
+}
+
static void quadriflow_free_job(void *customdata)
{
QuadriFlowJob *qj = customdata;
@@ -221,6 +306,66 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel)
*(qj->progress) = progress;
}
+static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+
+ Mesh *mesh_bisect, *mesh_bisect_temp;
+ mesh_bisect = BKE_mesh_copy(bmain, mesh);
+
+ int axis;
+ float plane_co[3], plane_no[3];
+ zero_v3(plane_co);
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
+ zero_v3(plane_no);
+ plane_no[axis] = -1.0f;
+ mesh_bisect_temp = mesh_bisect;
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no);
+ if (mesh_bisect_temp != mesh_bisect) {
+ BKE_id_free(bmain, mesh_bisect_temp);
+ }
+ }
+ }
+
+ BKE_id_free(bmain, mesh);
+
+ return mesh_bisect;
+}
+
+static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+ Mesh *mesh_mirror, *mesh_mirror_temp;
+
+ mesh_mirror = mesh;
+
+ int axis;
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_AXIS_X << i;
+ mesh_mirror_temp = mesh_mirror;
+ mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
+ if (mesh_mirror_temp != mesh_mirror) {
+ BKE_id_free(NULL, mesh_mirror_temp);
+ }
+ }
+ }
+
+ return mesh_mirror;
+}
+
static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
{
QuadriFlowJob *qj = customdata;
@@ -235,16 +380,33 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
Object *ob = qj->owner;
Mesh *mesh = ob->data;
Mesh *new_mesh;
+ Mesh *bisect_mesh;
+
+ /* Check if the mesh is manifold. Quadriflow requires manifold meshes */
+ if (!mesh_is_manifold_consistent(mesh)) {
+ qj->success = -2;
+ return;
+ }
+
+ /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
+ * freeing the original ID */
+ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh);
- new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh,
+ /* Bisect the input mesh using the paint symmetry settings */
+ bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes);
+
+ new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh,
qj->target_faces,
qj->seed,
qj->use_preserve_sharp,
- qj->use_preserve_boundary,
+ qj->use_preserve_boundary ||
+ qj->use_paint_symmetry,
qj->use_mesh_curvature,
quadriflow_update_job,
(void *)qj);
+ BKE_id_free(qj->bmain, bisect_mesh);
+
if (!new_mesh) {
*do_update = true;
*stop = 0;
@@ -255,28 +417,26 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
return;
}
+ /* Mirror the Quadriflow result to build the final mesh */
+ if (new_mesh) {
+ new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
+ }
+
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_begin(ob);
}
- Mesh *obj_mesh_copy = NULL;
if (qj->preserve_paint_mask) {
- obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
- CustomData_copy(
- &mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
- for (int i = 0; i < mesh->totvert; i++) {
- copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
- }
+ BKE_mesh_runtime_clear_geometry(mesh);
+ BKE_remesh_reproject_paint_mask(new_mesh, mesh);
}
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
- if (qj->preserve_paint_mask) {
- BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
- BKE_mesh_free(obj_mesh_copy);
- }
-
if (qj->smooth_normals) {
+ if (qj->use_paint_symmetry) {
+ BKE_mesh_calc_normals(ob->data);
+ }
BKE_mesh_smooth_flag_set(ob->data, true);
}
@@ -298,17 +458,22 @@ static void quadriflow_end_job(void *customdata)
WM_set_locked_interface(G_MAIN->wm.first, false);
- if (qj->success > 0) {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
- }
- else {
- if (qj->success == 0) {
+ switch (qj->success) {
+ case 1:
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
+ break;
+ case 0:
WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!");
- }
- else {
+ break;
+ case -1:
WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!");
- }
+ break;
+ case -2:
+ WM_report(RPT_WARNING,
+ "QuadriFlow: The mesh needs to be manifold and have face normals that point in a "
+ "consistent direction.");
+ break;
}
}
@@ -317,10 +482,13 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
job->owner = CTX_data_active_object(C);
+ job->bmain = CTX_data_main(C);
job->target_faces = RNA_int_get(op->ptr, "target_faces");
job->seed = RNA_int_get(op->ptr, "seed");
+ job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
+
job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
@@ -329,6 +497,22 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
+ /* Update the target face count if symmetry is enabled */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ if (sd && job->use_paint_symmetry) {
+ job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL);
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (job->symmetry_axes & symm_it) {
+ job->target_faces = job->target_faces / 2;
+ }
+ }
+ }
+ else {
+ job->use_paint_symmetry = false;
+ job->symmetry_axes = 0;
+ }
+
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
CTX_data_scene(C),
@@ -453,6 +637,12 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna,
+ "use_paint_symmetry",
+ true,
+ "Use Paint Symmetry",
+ "Generates a symmetrycal mesh using the paint symmetry configuration");
+
+ RNA_def_boolean(ot->srna,
"use_preserve_sharp",
false,
"Preserve Sharp",
@@ -485,7 +675,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
RNA_def_enum(ot->srna,
"mode",
mode_type_items,
- 0,
+ QUADRIFLOW_REMESH_FACES,
"Mode",
"How to specify the amount of detail for the new mesh");
@@ -511,7 +701,7 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
prop = RNA_def_int(ot->srna,
"target_faces",
- 1,
+ 4000,
1,
INT_MAX,
"Number of Faces",
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index 28242b986f1..40fa11994f4 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -214,7 +214,7 @@ bool ED_object_base_deselect_all(ViewLayer *view_layer, View3D *v3d, int action)
static int get_base_select_priority(Base *base)
{
- if (base->flag & BASE_VISIBLE) {
+ if (base->flag & BASE_VISIBLE_DEPSGRAPH) {
if (base->flag & BASE_SELECTABLE) {
return 3;
}
@@ -288,7 +288,7 @@ bool ED_object_jump_to_object(bContext *C, Object *ob, const bool UNUSED(reveal_
if (!(base->flag & BASE_SELECTED)) {
ED_object_base_deselect_all(view_layer, v3d, SEL_DESELECT);
- if (base->flag & BASE_VISIBLE) {
+ if (BASE_VISIBLE(v3d, base)) {
ED_object_base_select(base, BA_SELECT);
}
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 1cd16b1b0bf..b534e1b9683 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -1715,8 +1715,9 @@ static void object_transform_axis_target_cancel(bContext *C, wmOperator *op)
static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.obact == NULL || !object_is_target_compat(vc.obact)) {
/* Falls back to texture space transform. */
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 2047ecb9e0a..f16a372cb3c 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -93,6 +93,7 @@
bool PE_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -100,7 +101,7 @@ bool PE_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL) {
return false;
}
@@ -113,6 +114,7 @@ bool PE_poll(bContext *C)
bool PE_hair_poll(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -120,7 +122,7 @@ bool PE_hair_poll(bContext *C)
return false;
}
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit == NULL || edit->psys == NULL) {
return false;
}
@@ -149,8 +151,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
}
if (edit->points) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->keys) {
MEM_freeN(point->keys);
}
@@ -356,9 +357,9 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o
return edit;
}
-PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
+PTCacheEdit *PE_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, ob, 0);
+ return pe_get_current(depsgraph, scene, ob, 0);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
@@ -380,10 +381,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
KEY_K;
if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if (fabsf(cfra - *key->time) < pset->fade_frames) {
key->flag &= ~PEK_HIDE;
}
@@ -395,10 +394,8 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
}
}
else {
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
key->flag &= ~PEK_HIDE;
}
}
@@ -466,14 +463,14 @@ static void PE_set_data(bContext *C, PEData *data)
data->view_layer = CTX_data_view_layer(C);
data->ob = CTX_data_active_object(C);
data->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- data->edit = PE_get_current(data->scene, data->ob);
+ data->edit = PE_get_current(data->depsgraph, data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
{
PE_set_data(C, data);
- ED_view3d_viewcontext_init(C, &data->vc);
+ ED_view3d_viewcontext_init(C, &data->vc, data->depsgraph);
if (!XRAY_ENABLED(data->vc.v3d)) {
if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
@@ -633,8 +630,7 @@ static bool point_is_selected(PTCacheEditPoint *point)
return 0;
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
return 1;
}
@@ -684,8 +680,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
nearest_point = -1;
nearest_key = -1;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -707,8 +702,7 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum ePartic
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p;
@@ -745,8 +739,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
selected = 0;
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) {
/* only do end keys */
@@ -762,8 +755,7 @@ static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int sele
}
else {
/* do all keys */
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -823,8 +815,7 @@ static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
/* do all keys */
PTCacheEditKey *key;
int k;
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_KEYS {
if (selected == 0 || key->flag & PEK_SELECT) {
float mouse_distance;
if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
@@ -866,8 +857,7 @@ static void foreach_selected_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
func(data, p);
}
}
@@ -878,10 +868,8 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
func(data, p, k, true);
}
}
@@ -892,8 +880,7 @@ static void foreach_point(PEData *data, ForPointFunc func)
PTCacheEdit *edit = data->edit;
POINT_P;
- LOOP_POINTS
- {
+ LOOP_POINTS {
func(data, p);
}
}
@@ -905,11 +892,9 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
KEY_K;
int sel = 0;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
sel++;
}
}
@@ -1117,8 +1102,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
/* we delay settings the PARS_EDIT_RECALC for mirrored particles
* to avoid doing mirror twice */
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
@@ -1128,8 +1112,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_EDIT_RECALC) {
if (edit->mirror_cache[p] != -1) {
edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
@@ -1173,13 +1156,11 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
psys_mat_hair_to_object(
object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairmat, key->co);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
dist_1st = len_v3v3((key + 1)->co, key->co);
dist_1st *= dist * emitterdist;
@@ -1215,8 +1196,7 @@ static void deflect_emitter_iter(void *__restrict iter_data_v,
invert_m4_m4(hairimat, hairmat);
- LOOP_KEYS
- {
+ LOOP_KEYS {
mul_m4_v3(hairimat, key->co);
}
}
@@ -1268,8 +1248,7 @@ static void apply_lengths_iter(void *__restrict iter_data_v,
}
PTCacheEditKey *key;
int k;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k) {
float dv1[3];
sub_v3_v3v3(dv1, key->co, (key - 1)->co);
@@ -1387,8 +1366,7 @@ void recalc_lengths(PTCacheEdit *edit)
return;
}
- LOOP_EDITED_POINTS
- {
+ LOOP_EDITED_POINTS {
key = point->keys;
for (k = 0; k < point->totkey - 1; k++, key++) {
key->length = len_v3v3(key->co, (key + 1)->co);
@@ -1461,15 +1439,14 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
HairKey *hkey;
POINT_P;
KEY_K;
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1477,11 +1454,9 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
/* flush edit key flag to hair key flag to preserve selection
* on save */
if (edit->psys) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
hkey = edit->psys->particles[p].hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
hkey->editflag = key->flag;
hkey++;
}
@@ -1491,8 +1466,7 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1511,15 +1485,13 @@ void update_world_cos(Object *ob, PTCacheEdit *edit)
return;
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
mul_m4_v3(hairmat, key->world_co);
@@ -1541,10 +1513,8 @@ static void update_velocities(PTCacheEdit *edit)
frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
- LOOP_EDITED_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_EDITED_POINTS {
+ LOOP_KEYS {
if (k == 0) {
dfra = *(key + 1)->time - *key->time;
@@ -1596,7 +1566,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* use this to do partial particle updates, not usable when adding or
* removing, then a full redo is necessary and calling this may crash */
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
if (!edit) {
@@ -1605,8 +1575,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
/* flag all particles to be updated if not using flag */
if (!useflag) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag |= PEP_EDIT_RECALC;
}
}
@@ -1624,14 +1593,19 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
if (pset->flag & PE_AUTO_VELOCITY) {
update_velocities(edit);
}
- PE_hide_keys_time(scene, edit, CFRA);
+
+ /* Only do this for emitter particles because drawing PE_FADE_TIME is not respected in 2.8 yet
+ * and flagging with PEK_HIDE will prevent selection. This might get restored once this is
+ * supported in drawing (but doesn't make much sense for hair anyways). */
+ if (edit->psys->part->type == PART_EMITTER) {
+ PE_hide_keys_time(scene, edit, CFRA);
+ }
/* regenerate path caches */
psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
/* disable update flag */
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_EDIT_RECALC;
}
@@ -1686,8 +1660,7 @@ static void select_keys(PEData *data,
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (data->select) {
key->flag |= PEK_SELECT;
}
@@ -1780,17 +1753,15 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
int action = RNA_enum_get(op->ptr, "action");
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
action = SEL_DESELECT;
break;
}
@@ -1802,10 +1773,8 @@ static int pe_select_all_exec(bContext *C, wmOperator *op)
}
bool changed = false;
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
changed |= select_action_apply(point, key, action);
}
}
@@ -1841,26 +1810,26 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele
PEData data;
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
POINT_P;
KEY_K;
+ PE_set_view3d_data(C, &data);
+
+ PTCacheEdit *edit = PE_get_current(data.depsgraph, scene, ob);
+
if (!PE_start_edit(edit)) {
return false;
}
if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
}
}
}
- PE_set_view3d_data(C, &data);
data.mval = mval;
data.rad = ED_view3d_select_dist_px();
@@ -2048,26 +2017,22 @@ static int select_random_exec(bContext *C, wmOperator *op)
PE_set_data(C, &data);
data.select_action = SEL_SELECT;
- edit = PE_get_current(data.scene, data.ob);
+ edit = PE_get_current(data.depsgraph, data.scene, data.ob);
rng = BLI_rng_new_srandom(seed);
switch (type) {
case RAN_HAIR:
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- LOOP_KEYS
- {
+ LOOP_KEYS {
data.is_changed |= select_action_apply(point, key, flag);
}
}
break;
case RAN_POINTS:
- LOOP_VISIBLE_POINTS
- {
- LOOP_VISIBLE_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
data.is_changed |= select_action_apply(point, key, flag);
}
@@ -2166,10 +2131,8 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_VISIBLE_POINTS
- {
- LOOP_SELECTED_KEYS
- {
+ LOOP_VISIBLE_POINTS {
+ LOOP_SELECTED_KEYS {
if ((key->flag & PEK_SELECT) != 0) {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
@@ -2182,9 +2145,10 @@ bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
bool PE_deselect_all_visible(bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (!PE_start_edit(edit)) {
return false;
}
@@ -2193,9 +2157,10 @@ bool PE_deselect_all_visible(bContext *C)
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2229,9 +2194,10 @@ bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
{
BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PEData data;
if (!PE_start_edit(edit)) {
@@ -2260,11 +2226,12 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ARegion *ar = CTX_wm_region(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
POINT_P;
@@ -2287,16 +2254,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const
data.is_changed |= PE_deselect_all_visible_ex(edit);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_KEYS
- {
+ LOOP_VISIBLE_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
const bool is_select = key->flag & PEK_SELECT;
@@ -2350,30 +2315,26 @@ static int hide_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
POINT_P;
KEY_K;
if (RNA_boolean_get(op->ptr, "unselected")) {
- LOOP_UNSELECTED_POINTS
- {
+ LOOP_UNSELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
}
else {
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
point->flag |= PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->flag &= ~PEK_SELECT;
}
}
@@ -2410,19 +2371,17 @@ static int reveal_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
const bool select = RNA_boolean_get(op->ptr, "select");
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (point->flag & PEP_HIDE) {
point->flag &= ~PEP_HIDE;
point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS
- {
+ LOOP_KEYS {
SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
}
}
@@ -2460,8 +2419,7 @@ static void select_less_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
if (k == 0) {
if (((key + 1)->flag & PEK_SELECT) == 0) {
key->flag |= PEK_TAG;
@@ -2479,8 +2437,7 @@ static void select_less_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
key->flag &= ~(PEK_TAG | PEK_SELECT);
point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
@@ -2525,8 +2482,7 @@ static void select_more_keys(PEData *data, int point_index)
PTCacheEditPoint *point = edit->points + point_index;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (key->flag & PEK_SELECT) {
continue;
}
@@ -2548,8 +2504,7 @@ static void select_more_keys(PEData *data, int point_index)
}
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
key->flag &= ~PEK_TAG;
key->flag |= PEK_SELECT;
@@ -2694,7 +2649,8 @@ void PARTICLE_OT_rekey(wmOperatorType *ot)
static void rekey_particle_to_time(
const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSimulationData sim = {0};
ParticleData *pa;
@@ -2709,7 +2665,7 @@ static void rekey_particle_to_time(
psys = edit->psys;
- sim.depsgraph = CTX_data_depsgraph_pointer(C);
+ sim.depsgraph = depsgraph;
sim.scene = scene;
sim.ob = ob;
sim.psys = psys;
@@ -2758,14 +2714,12 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
/* mirror tags */
psmd_eval = edit->psmd_eval;
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
}
}
- LOOP_TAGGED_POINTS
- {
+ LOOP_TAGGED_POINTS {
new_totpart--;
removed++;
}
@@ -2850,21 +2804,17 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated(
depsgraph, ob, &psmd->modifier);
- LOOP_POINTS
- {
- LOOP_TAGGED_KEYS
- {
+ LOOP_POINTS {
+ LOOP_TAGGED_KEYS {
PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
break;
}
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
new_totkey = point->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
/* we can't have elements with less than two keys*/
@@ -2874,13 +2824,11 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
}
remove_tagged_particles(ob, psys, pe_x_mirror(ob));
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
new_totkey = pa->totkey;
- LOOP_TAGGED_KEYS
- {
+ LOOP_TAGGED_KEYS {
new_totkey--;
}
@@ -2889,8 +2837,7 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem
nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
key++;
hkey++;
@@ -3062,9 +3009,10 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot)
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd_eval;
KDTree_3d *tree;
@@ -3087,8 +3035,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
tree = BLI_kdtree_3d_new(psys->totpart);
/* insert particles into kd tree */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3099,8 +3046,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
BLI_kdtree_3d_balance(tree);
/* tag particles to be removed */
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
psys_mat_hair_to_object(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
copy_v3_v3(co, point->keys->co);
@@ -3130,7 +3076,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d double particle(s)", totremoved);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
@@ -3166,10 +3112,11 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
static int weight_set_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ParticleEditSettings *pset = PE_settings(scene);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
POINT_P;
KEY_K;
@@ -3181,12 +3128,10 @@ static int weight_set_exec(bContext *C, wmOperator *op)
weight = brush->strength;
edit = psys->edit;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
ParticleData *pa = psys->particles + p;
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
hkey = pa->hair + k;
hkey->weight = interpf(weight, hkey->weight, factor);
}
@@ -3315,6 +3260,7 @@ static int delete_exec(bContext *C, wmOperator *op)
}
DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
+ BKE_particle_batch_cache_dirty_tag(data.edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
return OPERATOR_FINISHED;
@@ -3346,11 +3292,11 @@ void PARTICLE_OT_delete(wmOperatorType *ot)
/*************************** mirror operator **************************/
-static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+static void PE_mirror_x(Depsgraph *depsgraph, Scene *scene, Object *ob, int tagged)
{
Mesh *me = (Mesh *)(ob->data);
ParticleSystemModifierData *psmd_eval;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
ParticleData *pa, *newpa, *new_pars;
PTCacheEditPoint *newpoint, *new_points;
@@ -3386,8 +3332,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
totpart = psys->totpart;
newtotpart = psys->totpart;
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
pa = psys->particles + p;
if (!tagged) {
@@ -3503,8 +3448,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
}
}
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->flag &= ~PEP_TAG;
}
@@ -3513,14 +3457,18 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(depsgraph, scene, ob, 0);
update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
return OPERATOR_FINISHED;
@@ -3681,8 +3629,7 @@ static void brush_length(PEData *data, int point_index, float UNUSED(mouse_dista
KEY_K;
float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(pvec, key->co);
}
@@ -3731,8 +3678,7 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance)
unit_m4(imat);
}
- LOOP_KEYS
- {
+ LOOP_KEYS {
float kco[3];
if (k == 0) {
@@ -4504,10 +4450,11 @@ typedef struct BrushEdit {
static int brush_edit_init(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ARegion *ar = CTX_wm_region(C);
BrushEdit *bedit;
float min[3], max[3];
@@ -4518,7 +4465,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
/* set the 'distance factor' for grabbing (used in comb etc) */
INIT_MINMAX(min, max);
- PE_minmax(scene, view_layer, min, max);
+ PE_minmax(depsgraph, scene, view_layer, min, max);
mid_v3_v3v3(min, min, max);
bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
@@ -4744,7 +4691,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob)) {
- PE_mirror_x(scene, ob, 1);
+ PE_mirror_x(depsgraph, scene, ob, 1);
}
update_world_cos(ob, edit);
@@ -4993,10 +4940,11 @@ static void shape_cut(PEData *data, int pa_index)
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
Object *shapeob = pset->shape_object;
int selected = count_selected_keys(scene, edit);
int lock_root = pset->flag & PE_LOCK_FIRST;
@@ -5074,10 +5022,11 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot)
/************************ utilities ******************************/
-int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
+int PE_minmax(
+ Depsgraph *depsgraph, Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
ParticleSystem *psys;
ParticleSystemModifierData *psmd_eval = NULL;
POINT_P;
@@ -5096,15 +5045,13 @@ int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
unit_m4(mat);
}
- LOOP_VISIBLE_POINTS
- {
+ LOOP_VISIBLE_POINTS {
if (psys) {
psys_mat_hair_to_global(
ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
}
- LOOP_SELECTED_KEYS
- {
+ LOOP_SELECTED_KEYS {
copy_v3_v3(co, key->co);
mul_m4_v3(mat, co);
DO_MINMAX(co, min, max);
@@ -5181,15 +5128,13 @@ void PE_create_particle_edit(
BLI_listbase_clear(&edit->pathcachebufs);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->totkey = pa->totkey;
point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
point->flag |= PEP_EDIT_RECALC;
hkey = pa->hair;
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
@@ -5217,8 +5162,7 @@ void PE_create_particle_edit(
}
for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (BKE_ptcache_mem_pointers_seek(p, pm) == 0) {
continue;
}
@@ -5421,8 +5365,7 @@ static float calculate_point_length(PTCacheEditPoint *point)
{
float length = 0.0f;
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k > 0) {
length += len_v3v3((key - 1)->co, key->co);
}
@@ -5435,8 +5378,7 @@ static float calculate_average_length(PTCacheEdit *edit)
int num_selected = 0;
float total_length = 0;
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
total_length += calculate_point_length(point);
num_selected++;
}
@@ -5450,8 +5392,7 @@ static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
float orig_prev_co[3], prev_co[3];
KEY_K;
- LOOP_KEYS
- {
+ LOOP_KEYS {
if (k == 0) {
copy_v3_v3(orig_prev_co, key->co);
copy_v3_v3(prev_co, key->co);
@@ -5484,8 +5425,7 @@ static void scale_point_to_length(PTCacheEditPoint *point, float length)
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
POINT_P;
- LOOP_SELECTED_POINTS
- {
+ LOOP_SELECTED_POINTS {
scale_point_to_length(point, length);
}
recalc_lengths(edit);
@@ -5497,7 +5437,7 @@ static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
float average_length = calculate_average_length(edit);
if (average_length == 0.0f) {
diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c
index 40d90676487..aee79523c87 100644
--- a/source/blender/editors/physics/particle_edit_undo.c
+++ b/source/blender/editors/physics/particle_edit_undo.c
@@ -109,8 +109,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
POINT_P;
KEY_K;
- LOOP_POINTS
- {
+ LOOP_POINTS {
if (psys && psys->particles[p].hair) {
MEM_freeN(psys->particles[p].hair);
}
@@ -133,8 +132,7 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
edit->points = MEM_dupallocN(undo->points);
edit->totpoint = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
point->keys = MEM_dupallocN(point->keys);
}
@@ -143,13 +141,11 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
psys->totpart = undo->totpoint;
- LOOP_POINTS
- {
+ LOOP_POINTS {
pa = psys->particles + p;
hkey = pa->hair = MEM_dupallocN(pa->hair);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
hkey++;
@@ -174,10 +170,8 @@ static void undoptcache_to_editcache(PTCacheUndo *undo, PTCacheEdit *edit)
}
BKE_ptcache_mem_pointers_init(pm);
- LOOP_POINTS
- {
- LOOP_KEYS
- {
+ LOOP_POINTS {
+ LOOP_KEYS {
if ((int)key->ftime == (int)pm->frame) {
key->co = pm->cur[BPHYS_DATA_LOCATION];
key->vel = pm->cur[BPHYS_DATA_VELOCITY];
@@ -228,10 +222,11 @@ typedef struct ParticleUndoStep {
static bool particle_undosys_poll(struct bContext *C)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
return (edit != NULL);
}
@@ -240,11 +235,12 @@ static bool particle_undosys_step_encode(struct bContext *C,
struct Main *UNUSED(bmain),
UndoStep *us_p)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
ViewLayer *view_layer = CTX_data_view_layer(C);
us->scene_ref.ptr = CTX_data_scene(C);
us->object_ref.ptr = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+ PTCacheEdit *edit = PE_get_current(depsgraph, us->scene_ref.ptr, us->object_ref.ptr);
undoptcache_from_editcache(&us->data, edit);
return true;
}
@@ -255,6 +251,7 @@ static void particle_undosys_step_decode(struct bContext *C,
int UNUSED(dir),
bool UNUSED(is_final))
{
+ 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);
BLI_assert(particle_undosys_poll(C));
@@ -262,7 +259,7 @@ static void particle_undosys_step_decode(struct bContext *C,
ParticleUndoStep *us = (ParticleUndoStep *)us_p;
Scene *scene = us->scene_ref.ptr;
Object *ob = us->object_ref.ptr;
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
if (edit) {
undoptcache_to_editcache(&us->data, edit);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 5a2009845f8..cfb3a400f47 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -1017,13 +1017,11 @@ static void copy_particle_edit(Depsgraph *depsgraph,
edit->points = MEM_dupallocN(edit_from->points);
pa = psys->particles;
- LOOP_POINTS
- {
+ LOOP_POINTS {
HairKey *hkey = pa->hair;
point->keys = MEM_dupallocN(point->keys);
- LOOP_KEYS
- {
+ LOOP_KEYS {
key->co = hkey->co;
key->time = &hkey->time;
key->flag = hkey->editflag;
diff --git a/source/blender/editors/physics/rigidbody_constraint.c b/source/blender/editors/physics/rigidbody_constraint.c
index 4b1d51ee6c2..303a0714388 100644
--- a/source/blender/editors/physics/rigidbody_constraint.c
+++ b/source/blender/editors/physics/rigidbody_constraint.c
@@ -115,13 +115,7 @@ bool ED_rigidbody_constraint_add(
void ED_rigidbody_constraint_remove(Main *bmain, Scene *scene, Object *ob)
{
- RigidBodyWorld *rbw = BKE_rigidbody_get_world(scene);
-
- BKE_rigidbody_remove_constraint(scene, ob);
- if (rbw) {
- BKE_collection_object_remove(bmain, rbw->constraints, ob, false);
- DEG_id_tag_update(&rbw->constraints->id, ID_RECALC_COPY_ON_WRITE);
- }
+ BKE_rigidbody_remove_constraint(bmain, scene, ob, false);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index bc8a1799fa0..43ca421b9d0 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -105,7 +105,7 @@ bool ED_rigidbody_object_add(Main *bmain, Scene *scene, Object *ob, int type, Re
void ED_rigidbody_object_remove(Main *bmain, Scene *scene, Object *ob)
{
- BKE_rigidbody_remove_object(bmain, scene, ob);
+ BKE_rigidbody_remove_object(bmain, scene, ob, false);
DEG_relations_tag_update(bmain);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 053ca3d8f9f..7106af25a82 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -859,7 +859,7 @@ static void screen_render_cancel(bContext *C, wmOperator *op)
static void clean_viewport_memory_base(Base *base)
{
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return;
}
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 3e001ef25b5..6dc3a1ec1ac 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -115,7 +115,7 @@ ImBuf *get_brush_icon(Brush *brush)
// first use the path directly to try and load the file
BLI_strncpy(path, brush->icon_filepath, sizeof(brush->icon_filepath));
- BLI_path_abs(path, BKE_main_blendfile_path_from_global());
+ BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id));
/* use default colorspaces for brushes */
brush->icon_imbuf = IMB_loadiffname(path, flags, NULL);
@@ -474,7 +474,7 @@ static Scene *preview_prepare_scene(
}
}
else if (base->object->type == OB_LAMP) {
- base->flag |= BASE_VISIBLE;
+ base->flag |= BASE_VISIBLE_DEPSGRAPH;
}
}
}
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 9f13431f25a..7970d491877 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -103,15 +103,17 @@ static Object **object_array_for_shading(bContext *C, uint *r_objects_len)
ScrArea *sa = CTX_wm_area(C);
SpaceProperties *sbuts = NULL;
View3D *v3d = NULL;
- if (sa->spacetype == SPACE_PROPERTIES) {
- sbuts = sa->spacedata.first;
- }
- else if (sa->spacetype == SPACE_VIEW3D) {
- v3d = sa->spacedata.first;
+ if (sa != NULL) {
+ if (sa->spacetype == SPACE_PROPERTIES) {
+ sbuts = sa->spacedata.first;
+ }
+ else if (sa->spacetype == SPACE_VIEW3D) {
+ v3d = sa->spacedata.first;
+ }
}
Object **objects;
- if (sbuts && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) {
+ if (sbuts != NULL && sbuts->pinid && GS(sbuts->pinid->name) == ID_OB) {
objects = MEM_mallocN(sizeof(*objects), __func__);
objects[0] = (Object *)sbuts->pinid;
*r_objects_len = 1;
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 3154d5d0985..a54701f8725 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -36,6 +36,8 @@
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BLT_translation.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -137,11 +139,11 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
SpaceImage *sima;
bool area_was_image = false;
- if (scene->r.displaymode == R_OUTPUT_NONE) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
return NULL;
}
- if (scene->r.displaymode == R_OUTPUT_WINDOW) {
+ if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
@@ -154,14 +156,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
/* changes context! */
- if (WM_window_open_temp(C, mx, my, sizex, sizey, WM_WINDOW_RENDER) == NULL) {
+ if (WM_window_open_temp(
+ C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE, false) == NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
sa = CTX_wm_area(C);
}
- else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
+ else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
sa = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c
index 84d6610242a..7705278443f 100644
--- a/source/blender/editors/scene/scene_edit.c
+++ b/source/blender/editors/scene/scene_edit.c
@@ -29,21 +29,16 @@
#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_library.h"
-#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_scene.h"
-#include "BKE_workspace.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "BLT_translation.h"
-#include "DNA_object_types.h"
-#include "DNA_workspace_types.h"
-
#include "ED_object.h"
#include "ED_render.h"
#include "ED_scene.h"
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index cb87b076d79..9957fe0515c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -30,6 +30,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_rand.h"
#include "BLI_utildefines.h"
#include "BLI_linklist_stack.h"
@@ -60,7 +61,6 @@
#include "BLF_api.h"
-#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_metadata.h"
@@ -543,20 +543,20 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
region_draw_azones(sa, ar);
/* for debugging unneeded area redraws and partial redraw */
-#if 0
- GPU_blend(true);
- GPUVertFormat *format = immVertexFormat();
- uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4f(drand48(), drand48(), drand48(), 0.1f);
- immRectf(pos,
- ar->drawrct.xmin - ar->winrct.xmin,
- ar->drawrct.ymin - ar->winrct.ymin,
- ar->drawrct.xmax - ar->winrct.xmin,
- ar->drawrct.ymax - ar->winrct.ymin);
- immUnbindProgram();
- GPU_blend(false);
-#endif
+ if (G.debug_value == 888) {
+ GPU_blend(true);
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(BLI_thread_frand(0), BLI_thread_frand(0), BLI_thread_frand(0), 0.1f);
+ immRectf(pos,
+ ar->drawrct.xmin - ar->winrct.xmin,
+ ar->drawrct.ymin - ar->winrct.ymin,
+ ar->drawrct.xmax - ar->winrct.xmin,
+ ar->drawrct.ymax - ar->winrct.ymin);
+ immUnbindProgram();
+ GPU_blend(false);
+ }
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
@@ -1827,7 +1827,7 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
if (WM_cursor_set_from_tool(win, sa, ar)) {
return;
}
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -2869,7 +2869,7 @@ void ED_region_info_draw(ARegion *ar,
float fill_color[4],
const bool full_redraw)
{
- ED_region_info_draw_multiline(ar, (const char * [2]){text, NULL}, fill_color, full_redraw);
+ ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw);
}
#define MAX_METADATA_STR 1024
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index 420d70e63fb..46559efc614 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -28,8 +28,6 @@
#include "RNA_types.h"
-#include "WM_api.h"
-
#include "ED_screen.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/area_utils.c b/source/blender/editors/screen/area_utils.c
index 1a99210b73d..61fb9d5a3a8 100644
--- a/source/blender/editors/screen/area_utils.c
+++ b/source/blender/editors/screen/area_utils.c
@@ -28,7 +28,6 @@
#include "RNA_access.h"
#include "RNA_types.h"
-#include "WM_api.h"
#include "WM_message.h"
#include "ED_screen.h"
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index d8926bfc460..dc435efd86b 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -24,8 +24,6 @@
#include <stdio.h>
#include <string.h>
-#include "MEM_guardedalloc.h"
-
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index 6f8b25f782b..f7742c5e50a 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -29,36 +29,28 @@
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
-#include "DNA_brush_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_sequence_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_object.h"
#include "BKE_action.h"
#include "BKE_armature.h"
-#include "BKE_paint.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_sequencer.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
#include "RNA_access.h"
#include "ED_armature.h"
#include "ED_gpencil.h"
#include "ED_anim_api.h"
-#include "ED_uvedit.h"
#include "WM_api.h"
#include "UI_interface.h"
diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c
index db744df02e7..a6b8bba73e3 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -21,7 +21,7 @@
#include "ED_screen.h"
#include "GPU_batch_presets.h"
-#include "GPU_extensions.h"
+#include "GPU_platform.h"
#include "GPU_framebuffer.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@@ -32,9 +32,7 @@
#include "BLI_rect.h"
#include "WM_api.h"
-#include "WM_types.h"
-#include "UI_interface.h"
#include "UI_resources.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index b37aa47aba6..bbdddfadc30 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -41,20 +41,18 @@
#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
+#include "BKE_sound.h"
#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_object.h"
#include "ED_screen.h"
#include "ED_screen_types.h"
#include "ED_clip.h"
#include "ED_node.h"
-#include "ED_render.h"
#include "UI_interface.h"
@@ -518,6 +516,17 @@ 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 *ar)
+{
+ ED_region_exit(C, ar);
+ BKE_area_region_free(sa->type, ar);
+ BLI_freelinkN(&sa->regionbase, ar);
+}
+
/* *********** exit calls are for closing running stuff ******** */
void ED_region_exit(bContext *C, ARegion *ar)
@@ -583,6 +592,11 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
if (screen->animtimer) {
WM_event_remove_timer(wm, window, screen->animtimer);
+
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
+ Scene *scene = WM_window_get_active_scene(prevwin);
+ Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
+ BKE_sound_stop_scene(scene_eval);
}
screen->animtimer = NULL;
screen->scrubbing = false;
@@ -630,14 +644,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (sa) {
if (az->type == AZONE_AREA) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else if (az->type == AZONE_REGION) {
if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
}
}
@@ -646,14 +660,14 @@ static void screen_cursor_set(wmWindow *win, const int xy[2])
if (actedge) {
if (screen_geom_edge_is_horizontal(actedge)) {
- WM_cursor_set(win, CURSOR_Y_MOVE);
+ WM_cursor_set(win, WM_CURSOR_Y_MOVE);
}
else {
- WM_cursor_set(win, CURSOR_X_MOVE);
+ WM_cursor_set(win, WM_CURSOR_X_MOVE);
}
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
}
@@ -1346,6 +1360,54 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
return sc->areabase.first;
}
+/**
+ * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
+ * by \a display_type.
+ *
+ * \param title: Title to set for the window, if a window is spawned.
+ * \param x, y: Position of the window, if a window is spawned.
+ * \param sizex, sizey: Dimensions of the window, if a window is spawned.
+ */
+ScrArea *ED_screen_temp_space_open(bContext *C,
+ const char *title,
+ int x,
+ int y,
+ int sizex,
+ int sizey,
+ eSpace_Type space_type,
+ int display_type,
+ bool dialog)
+{
+ ScrArea *sa = 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);
+ }
+ break;
+ case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
+ ScrArea *ctx_sa = CTX_wm_area(C);
+
+ if (ctx_sa->full) {
+ sa = ctx_sa;
+ ED_area_newspace(C, ctx_sa, space_type, true);
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ }
+ else if (ctx_sa->spacetype == space_type) {
+ sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
+ }
+ else {
+ sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
+ }
+ break;
+ }
+ }
+
+ return sa;
+}
+
/* update frame rate info for viewport drawing */
void ED_refresh_viewport_fps(bContext *C)
{
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f29535a7f0b..cc1f53eabde 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -38,7 +38,6 @@
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
#include "DNA_curve_types.h"
-#include "DNA_gpencil_types.h"
#include "DNA_scene_types.h"
#include "DNA_meta_types.h"
#include "DNA_mesh_types.h"
@@ -48,7 +47,6 @@
#include "DNA_userdef_types.h"
#include "BKE_context.h"
-#include "BKE_customdata.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -1043,28 +1041,28 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(
- win, (ELEM(sad->gesture_dir, 'n', 's')) ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ win, (ELEM(sad->gesture_dir, 'n', 's')) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
else {
/* Different area, so possible join. */
if (sad->gesture_dir == 'n') {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (sad->gesture_dir == 's') {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (sad->gesture_dir == 'e') {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
is_gesture = (delta_max > join_threshold);
}
}
else {
- WM_cursor_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1229,7 +1227,7 @@ static int area_swap_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* add modal handler */
- WM_cursor_modal_set(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_SWAP_AREA);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
@@ -2121,7 +2119,7 @@ static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
{
wmWindow *win = CTX_wm_window(C);
int dir = RNA_enum_get(op->ptr, "direction");
- WM_cursor_set(win, (dir == 'n' || dir == 's') ? BC_V_SPLITCURSOR : BC_H_SPLITCURSOR);
+ WM_cursor_set(win, (dir == 'n' || dir == 's') ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT);
}
/* UI callback, adds new handler */
@@ -3420,19 +3418,19 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (dir == 1) {
- WM_cursor_set(win, BC_N_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_N_ARROW);
}
else if (dir == 3) {
- WM_cursor_set(win, BC_S_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_S_ARROW);
}
else if (dir == 2) {
- WM_cursor_set(win, BC_E_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_E_ARROW);
}
else if (dir == 0) {
- WM_cursor_set(win, BC_W_ARROWCURSOR);
+ WM_cursor_set(win, WM_CURSOR_W_ARROW);
}
else {
- WM_cursor_set(win, BC_STOPCURSOR);
+ WM_cursor_set(win, WM_CURSOR_STOP);
}
break;
@@ -3848,10 +3846,7 @@ static int region_quadview_exec(bContext *C, wmOperator *op)
for (ar = sa->regionbase.first; ar; ar = arn) {
arn = ar->next;
if (ar->alignment == RGN_ALIGN_QSPLIT) {
- ED_region_exit(C, ar);
- BKE_area_region_free(sa->type, ar);
- BLI_remlink(&sa->regionbase, ar);
- MEM_freeN(ar);
+ ED_region_remove(C, sa, ar);
}
}
ED_area_tag_redraw(sa);
@@ -3951,7 +3946,7 @@ static int region_toggle_exec(bContext *C, wmOperator *op)
region = CTX_wm_region(C);
}
- if (region) {
+ if (region && (region->alignment != RGN_ALIGN_NONE)) {
ED_region_toggle_hidden(C, region);
}
ED_region_tag_redraw(region);
@@ -4833,7 +4828,14 @@ static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int sizey = 520 * UI_DPI_FAC;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Preferences"),
+ event->x,
+ event->y,
+ sizex,
+ sizey,
+ SPACE_USERPREF,
+ false) != NULL) {
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
@@ -4882,7 +4884,16 @@ static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent
but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Drivers Editor"),
+ event->x,
+ event->y,
+ sizex,
+ sizey,
+ SPACE_GRAPH,
+ false) != NULL) {
+ ED_drivers_editor_init(C, CTX_wm_area(C));
+
/* activate driver F-Curve for the property under the cursor */
if (but) {
FCurve *fcu;
@@ -4938,7 +4949,14 @@ static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *even
int shift_y = 480;
/* changes context! */
- if (WM_window_open_temp(C, event->x, event->y + shift_y, sizex, sizey, WM_WINDOW_INFO) != NULL) {
+ if (WM_window_open_temp(C,
+ IFACE_("Blender Info Log"),
+ event->x,
+ event->y + shift_y,
+ sizex,
+ sizey,
+ SPACE_INFO,
+ false) != NULL) {
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
index 26849edeb44..661c17f55d2 100644
--- a/source/blender/editors/screen/screen_user_menu.c
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -52,27 +52,43 @@
#include "RNA_access.h"
/* -------------------------------------------------------------------- */
+/** \name Internal Utilities
+ * \{ */
+
+static const char *screen_menu_context_string(const bContext *C, const SpaceLink *sl)
+{
+ if (sl->spacetype == SPACE_NODE) {
+ const SpaceNode *snode = (const SpaceNode *)sl;
+ return snode->tree_idname;
+ }
+ return CTX_data_mode_string(C);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Menu Type
* \{ */
bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
if (sl == NULL) {
*r_len = 0;
return NULL;
}
+ const char *context_mode = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
uint array_len = 3;
bUserMenu **um_array = MEM_calloc_arrayN(array_len, sizeof(*um_array), __func__);
um_array[0] = BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
um_array[1] = (sl->spacetype != SPACE_TOPBAR) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context_mode) :
NULL;
um_array[2] = (sl->spacetype == SPACE_VIEW3D) ?
- BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context) :
+ BKE_blender_user_menu_find(&U.user_menus, SPACE_PROPERTIES, context_mode) :
NULL;
*r_len = array_len;
@@ -82,7 +98,7 @@ bUserMenu **ED_screen_user_menus_find(const bContext *C, uint *r_len)
bUserMenu *ED_screen_user_menu_ensure(bContext *C)
{
SpaceLink *sl = CTX_wm_space_data(C);
- const char *context = CTX_data_mode_string(C);
+ const char *context = screen_menu_context_string(C, sl);
return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
}
diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c
index 61b737589c8..bbb959c27ff 100644
--- a/source/blender/editors/screen/workspace_edit.c
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -29,18 +29,13 @@
#include "BKE_appdir.h"
#include "BKE_blendfile.h"
#include "BKE_context.h"
-#include "BKE_idcode.h"
-#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_main.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_workspace.h"
#include "BLO_readfile.h"
-#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
@@ -49,13 +44,9 @@
#include "ED_object.h"
#include "ED_screen.h"
-#include "MEM_guardedalloc.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
-#include "DEG_depsgraph.h"
-
#include "UI_interface.h"
#include "UI_resources.h"
@@ -63,7 +54,6 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "screen_intern.h"
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 752a5c36010..a5cc262ddcd 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/atomic
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -47,7 +48,6 @@ set(SRC
paint_image.c
paint_image_2d.c
paint_image_proj.c
- paint_image_undo.c
paint_mask.c
paint_ops.c
paint_stroke.c
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 5c83bdf0012..c59ab6279cd 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -91,6 +91,7 @@ typedef struct CursorSnapshot {
GLuint overlay_texture;
int size;
int zoom;
+ int curve_preset;
} CursorSnapshot;
static TexSnapshot primary_snap = {0};
@@ -409,7 +410,7 @@ static void load_tex_cursor_task_cb(void *__restrict userdata,
if (len <= 1.0f) {
float avg = BKE_brush_curve_strength_clamped(br, len, 1.0f); /* Falloff curve */
- buffer[index] = 255 - (GLubyte)(255 * avg);
+ buffer[index] = (GLubyte)(255 * avg);
}
else {
buffer[index] = 0;
@@ -426,7 +427,8 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
int size;
const bool refresh = !cursor_snap.overlay_texture ||
- (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom;
+ (overlay_flags & PAINT_OVERLAY_INVALID_CURVE) || cursor_snap.zoom != zoom ||
+ cursor_snap.curve_preset != br->curve_preset;
init = (cursor_snap.overlay_texture != 0);
@@ -506,6 +508,7 @@ static int load_tex_cursor(Brush *br, ViewContext *vc, float zoom)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ cursor_snap.curve_preset = br->curve_preset;
BKE_paint_reset_overlay_invalid(PAINT_OVERLAY_INVALID_CURVE);
return 1;
@@ -1093,17 +1096,15 @@ static bool ommit_cursor_drawing(Paint *paint, ePaintMode mode, Brush *brush)
return true;
}
-static void cursor_draw_point_screen_space(const uint gpuattr,
- const ARegion *ar,
- const float true_location[3],
- const float obmat[4][4])
+static void cursor_draw_point_screen_space(
+ const uint gpuattr, const ARegion *ar, float true_location[3], float obmat[4][4], int size)
{
float translation_vertex_cursor[3], location[3];
copy_v3_v3(location, true_location);
mul_m4_v3(obmat, location);
ED_view3d_project(ar, location, translation_vertex_cursor);
imm_draw_circle_fill_3d(
- gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], 3, 10);
+ gpuattr, translation_vertex_cursor[0], translation_vertex_cursor[1], size, 10);
}
static void cursor_draw_tiling_preview(const uint gpuattr,
@@ -1145,7 +1146,7 @@ static void cursor_draw_tiling_preview(const uint gpuattr,
for (dim = 0; dim < 3; dim++) {
location[dim] = cur[dim] * step[dim] + orgLoc[dim];
}
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@@ -1166,7 +1167,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
/* Axis Symmetry */
flip_v3_v3(location, true_location, (char)i);
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
/* Tiling */
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
@@ -1181,7 +1182,7 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
mul_m4_v3(symm_rot_mat, location);
cursor_draw_tiling_preview(gpuattr, ar, location, sd, ob, radius);
- cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat);
+ cursor_draw_point_screen_space(gpuattr, ar, location, ob->obmat, 3);
}
}
}
@@ -1191,7 +1192,13 @@ static void cursor_draw_point_with_symmetry(const uint gpuattr,
static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession *ss)
{
immUniformColor4f(1.0f, 1.0f, 1.0f, 0.6f);
- GPU_depth_test(true);
+
+ /* Cursor normally draws on top, but for this part we need depth tests. */
+ const bool depth_test = GPU_depth_test_enabled();
+ if (!depth_test) {
+ GPU_depth_test(true);
+ }
+
GPU_line_width(1.0f);
if (ss->preview_vert_index_count > 0) {
immBegin(GPU_PRIM_LINES, ss->preview_vert_index_count);
@@ -1200,10 +1207,24 @@ static void sculpt_geometry_preview_lines_draw(const uint gpuattr, SculptSession
}
immEnd();
}
+
+ /* Restore depth test value. */
+ if (!depth_test) {
+ GPU_depth_test(false);
+ }
+}
+
+static bool paint_use_2d_cursor(ePaintMode mode)
+{
+ if (mode >= PAINT_MODE_TEXTURE_3D) {
+ return true;
+ }
+ return false;
}
static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
ARegion *ar = CTX_wm_region(C);
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -1211,6 +1232,9 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
Brush *brush = BKE_paint_brush(paint);
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ /* 2d or 3d painting? */
+ const bool use_2d_cursor = paint_use_2d_cursor(mode);
+
/* check that brush drawing is enabled */
if (ommit_cursor_drawing(paint, mode, brush)) {
return;
@@ -1219,7 +1243,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* can't use stroke vc here because this will be called during
* mouse over too, not just during a stroke */
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
if (vc.rv3d && (vc.rv3d->rflag & RV3D_NAVIGATING)) {
return;
@@ -1237,7 +1261,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* set various defaults */
const float *outline_col = brush->add_col;
- const float outline_alpha = 0.5f;
+ const float outline_alpha = 0.7f;
float translation[2] = {x, y};
float final_radius = (BKE_brush_size_get(scene, brush) * zoomx);
@@ -1251,33 +1275,6 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* draw overlay */
bool alpha_overlay_active = paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
- /* TODO: as sculpt and other paint modes are unified, this
- * special mode of drawing will go away */
- if ((mode == PAINT_MODE_SCULPT) && vc.obact->sculpt) {
- float location[3];
- int pixel_radius;
-
- /* test if brush is over the mesh */
- bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
-
- if (BKE_brush_use_locked_size(scene, brush)) {
- BKE_brush_size_set(scene, brush, pixel_radius);
- }
-
- /* check if brush is subtracting, use different color then */
- /* TODO: no way currently to know state of pen flip or
- * invert key modifier without starting a stroke */
- if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
- BKE_brush_sculpt_has_secondary_color(brush)) {
- outline_col = brush->sub_col;
- }
-
- /* only do if brush is over the mesh */
- if (hit) {
- paint_cursor_on_hit(ups, brush, &vc, location);
- }
- }
-
if (ups->draw_anchored) {
final_radius = ups->anchored_size;
copy_v2_fl2(translation,
@@ -1290,148 +1287,239 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
GPU_blend(true); /* TODO: also set blend mode? */
GPU_line_smooth(true);
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ if (use_2d_cursor) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- /* set brush color */
- immUniformColor3fvAlpha(outline_col, outline_alpha);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
- /* draw brush outline */
- if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
- /* inner at full alpha */
- imm_draw_circle_wire_2d(
- pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
- /* outer at half alpha */
- immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ /* draw brush outline */
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_2d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ }
+
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_2d(pos, translation[0], translation[1], final_radius, 40);
}
+ else { /* 3d painting */
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ /* TODO: as sculpt and other paint modes are unified, this
+ * special mode of drawing will go away */
+ Object *obact = vc.obact;
+ SculptSession *ss = obact ? obact->sculpt : NULL;
+ if ((mode == PAINT_MODE_SCULPT) && ss) {
+ float location[3];
+ int pixel_radius;
+
+ /* test if brush is over the mesh */
+ bool hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location, ups);
+
+ if (BKE_brush_use_locked_size(scene, brush)) {
+ BKE_brush_size_set(scene, brush, pixel_radius);
+ }
- /* Only sculpt mode cursor for now */
+ /* check if brush is subtracting, use different color then */
+ /* TODO: no way currently to know state of pen flip or
+ * invert key modifier without starting a stroke */
+ if (((ups->draw_inverted == 0) ^ ((brush->flag & BRUSH_DIR_IN) == 0)) &&
+ BKE_brush_sculpt_has_secondary_color(brush)) {
+ outline_col = brush->sub_col;
+ }
- /* Disable for PBVH_GRIDS */
- SculptSession *ss = vc.obact->sculpt;
- bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
+ /* only do if brush is over the mesh */
+ if (hit) {
+ paint_cursor_on_hit(ups, brush, &vc, location);
+ }
+ }
- if ((mode == PAINT_MODE_SCULPT) && ss && !is_multires &&
- !(brush->falloff_shape & BRUSH_AIRBRUSH)) {
- Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- wmWindow *win = CTX_wm_window(C);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
- /* Update WM mouse cursor, disable when the 3D brush cursor is enabled */
- if (sd->paint.brush->overlay_flags & BRUSH_OVERLAY_CURSOR) {
- WM_cursor_set(win, CURSOR_STD);
+ if (ups->stroke_active && BKE_brush_use_size_pressure(scene, brush)) {
+ imm_draw_circle_wire_3d(
+ pos, translation[0], translation[1], final_radius * ups->size_pressure_value, 40);
+ /* outer at half alpha */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
}
- else {
- WM_cursor_set(win, CURSOR_EDIT);
+
+ /* Only sculpt mode cursor for now */
+ /* Disable for PBVH_GRIDS */
+ bool is_multires = ss && ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
+
+ SculptCursorGeometryInfo gi;
+ float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
+ int prev_active_vertex_index = -1;
+ bool is_cursor_over_mesh = false;
+
+ /* Update the active vertex */
+ if ((mode == PAINT_MODE_SCULPT) && ss && !ups->stroke_active) {
+ prev_active_vertex_index = ss->active_vertex_index;
+ is_cursor_over_mesh = sculpt_cursor_geometry_info_update(
+ C, &gi, mouse, (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE));
}
+ /* Use special paint crosshair cursor in all paint modes*/
+ wmWindow *win = CTX_wm_window(C);
+ WM_cursor_set(win, WM_CURSOR_PAINT);
- if (!ups->stroke_active) {
- SculptCursorGeometryInfo gi;
- float mouse[2] = {x - ar->winrct.xmin, y - ar->winrct.ymin};
- if (sculpt_cursor_geometry_info_update(C, &gi, mouse, true) && !alpha_overlay_active) {
+ if ((mode == PAINT_MODE_SCULPT) && ss &&
+ (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) {
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
- float rds;
- if (!BKE_brush_use_locked_size(scene, brush)) {
- rds = paint_calc_object_space_radius(&vc, gi.location, BKE_brush_size_get(scene, brush));
- }
- else {
- rds = BKE_brush_unprojected_radius_get(scene, brush);
- }
+ if (!ups->stroke_active) {
+ bool update_previews = false;
+ if (is_cursor_over_mesh && !alpha_overlay_active) {
- wmViewport(&ar->winrct);
+ if (prev_active_vertex_index != ss->active_vertex_index) {
+ update_previews = true;
+ }
- /* Draw 3D active vertex preview with symmetry*/
- if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
- cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
- }
+ float rds;
+ if (!BKE_brush_use_locked_size(scene, brush)) {
+ rds = paint_calc_object_space_radius(
+ &vc, gi.location, BKE_brush_size_get(scene, brush));
+ }
+ else {
+ rds = BKE_brush_unprojected_radius_get(scene, brush);
+ }
- /* Draw 3D brush cursor */
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- ar,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
-
- float cursor_trans[4][4], cursor_rot[4][4];
- float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
- float quat[4];
-
- copy_m4_m4(cursor_trans, vc.obact->obmat);
- translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
- rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
- quat_to_mat4(cursor_rot, quat);
-
- GPU_matrix_push();
- GPU_matrix_mul(cursor_trans);
- GPU_matrix_mul(cursor_rot);
- imm_draw_circle_wire_3d(pos, 0, 0, rds, 40);
- GPU_matrix_pop();
-
- /* Update and draw dynamic mesh preview lines */
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
- sculpt_geometry_preview_lines_update(C, ss, rds);
- sculpt_geometry_preview_lines_draw(pos, ss);
+ wmViewport(&ar->winrct);
+
+ /* Draw 3D active vertex preview with symmetry*/
+ if (len_v3v3(gi.active_vertex_co, gi.location) < rds) {
+ cursor_draw_point_with_symmetry(pos, ar, gi.active_vertex_co, sd, vc.obact, rds);
+ }
+
+ /* Draw pose brush origin */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ if (update_previews) {
+ BKE_sculpt_update_object_for_edit(depsgraph, vc.obact, true, false);
+ sculpt_pose_calc_pose_data(
+ sd, vc.obact, ss, gi.location, rds, brush->pose_offset, ss->pose_origin, NULL);
+ }
+ cursor_draw_point_screen_space(pos, ar, ss->pose_origin, vc.obact->obmat, 5);
+ }
+
+ /* Draw 3D brush cursor */
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+
+ float cursor_trans[4][4], cursor_rot[4][4];
+ float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f};
+ float quat[4];
+
+ copy_m4_m4(cursor_trans, vc.obact->obmat);
+ translate_m4(cursor_trans, gi.location[0], gi.location[1], gi.location[2]);
+ rotation_between_vecs_to_quat(quat, z_axis, gi.normal);
+ quat_to_mat4(cursor_rot, quat);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(cursor_trans);
+ GPU_matrix_mul(cursor_rot);
+ immUniformColor3fvAlpha(outline_col, outline_alpha);
+ GPU_line_width(2.0f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds, 80);
+ GPU_line_width(1.0f);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.5f);
+ imm_draw_circle_wire_3d(pos, 0, 0, rds * clamp_f(brush->alpha, 0.0f, 1.0f), 80);
+ GPU_matrix_pop();
+
+ /* Update and draw dynamic mesh preview lines */
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
+ sculpt_geometry_preview_lines_update(C, ss, rds);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ }
+ }
+
+ /* Draw pose brush line preview */
+ if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
+ GPU_line_width(2.0f);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(pos, ss->pose_origin);
+ immVertex3fv(pos, gi.location);
+ immEnd();
}
- }
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
+ GPU_matrix_pop();
- wmWindowViewport(win);
+ GPU_matrix_pop_projection();
+
+ wmWindowViewport(win);
+ }
+ else {
+ /* Draw default cursor when the mouse is not over the mesh or there are no supported
+ * overlays active */
+ GPU_line_width(1.0f);
+ /* Reduce alpha to increase the contrast when the cursor is over the mesh */
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.8);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 80);
+ immUniformColor3fvAlpha(outline_col, outline_alpha * 0.35f);
+ imm_draw_circle_wire_3d(pos,
+ translation[0],
+ translation[1],
+ final_radius * clamp_f(brush->alpha, 0.0f, 1.0f),
+ 80);
+ }
}
else {
- /* Draw default cursor when the mouse is not over the mesh or there are no supported
- * overlays active */
- GPU_line_width(1.0f);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
- }
- }
- else {
- if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
- /* Draw cursor location preview when the stroke is active using the data from StrokeCache
- */
- float cursor_location[3];
- wmViewport(&ar->winrct);
- copy_v3_v3(cursor_location, ss->cache->true_location);
- if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
- add_v3_v3(cursor_location, ss->cache->grab_delta);
- }
- cursor_draw_point_with_symmetry(pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
-
- /* Draw cached dynamic mesh preview lines */
- if (brush->sculpt_tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->modifiers_active) {
- GPU_matrix_push_projection();
- ED_view3d_draw_setup_view(CTX_wm_window(C),
- CTX_data_depsgraph_pointer(C),
- CTX_data_scene(C),
- ar,
- CTX_wm_view3d(C),
- NULL,
- NULL,
- NULL);
- GPU_matrix_push();
- GPU_matrix_mul(vc.obact->obmat);
- sculpt_geometry_preview_lines_draw(pos, ss);
- GPU_matrix_pop();
- GPU_matrix_pop_projection();
+ if (vc.obact->sculpt->cache && !vc.obact->sculpt->cache->first_time) {
+ /* Draw cursor location preview when the stroke is active using the data from StrokeCache
+ */
+ float cursor_location[3];
+ wmViewport(&ar->winrct);
+ copy_v3_v3(cursor_location, ss->cache->true_location);
+ if (ss->cache->brush->sculpt_tool == SCULPT_TOOL_GRAB) {
+ add_v3_v3(cursor_location, ss->cache->grab_delta);
+ }
+ cursor_draw_point_with_symmetry(
+ pos, ar, cursor_location, sd, vc.obact, ss->cache->radius);
+
+ /* Draw cached dynamic mesh preview lines */
+ if (brush->sculpt_tool == SCULPT_TOOL_GRAB && (brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) &&
+ !is_multires) {
+ if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && ss->deform_modifiers_active) {
+ GPU_matrix_push_projection();
+ ED_view3d_draw_setup_view(CTX_wm_window(C),
+ CTX_data_depsgraph_pointer(C),
+ CTX_data_scene(C),
+ ar,
+ CTX_wm_view3d(C),
+ NULL,
+ NULL,
+ NULL);
+ GPU_matrix_push();
+ GPU_matrix_mul(vc.obact->obmat);
+ sculpt_geometry_preview_lines_draw(pos, ss);
+ GPU_matrix_pop();
+ GPU_matrix_pop_projection();
+ }
}
- }
- wmWindowViewport(win);
+ wmWindowViewport(win);
+ }
}
}
- }
- else {
- /* Draw default cursor in unsupported modes */
- GPU_line_width(1.0f);
- imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ else {
+ /* Draw default cursor in unsupported modes */
+ GPU_line_width(1.0f);
+ imm_draw_circle_wire_3d(pos, translation[0], translation[1], final_radius, 40);
+ }
}
immUnbindProgram();
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index d9fd194e96f..62c31c91f8d 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -35,8 +35,6 @@
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "DEG_depsgraph.h"
-
#include "ED_view3d.h"
#include "ED_paint.h"
diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c
index bd62a59e73f..c14ccd27804 100644
--- a/source/blender/editors/sculpt_paint/paint_curve_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c
@@ -35,7 +35,6 @@
#include "ED_undo.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "paint_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 5852012891d..026dc39c668 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -37,7 +37,6 @@
#include "BKE_ccg.h"
#include "BKE_context.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
@@ -135,7 +134,6 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
float planes[4][4])
{
CCGElem **grids;
- CCGKey key;
BLI_bitmap **grid_hidden;
int *grid_indices, totgrid, i;
bool any_changed = false, any_visible = false;
@@ -143,7 +141,7 @@ static void partialvis_update_grids(Depsgraph *depsgraph,
/* get PBVH data */
BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, &grids);
grid_hidden = BKE_pbvh_grid_hidden(pbvh);
- BKE_pbvh_get_grid_key(pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(pbvh);
sculpt_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN);
@@ -299,15 +297,17 @@ static void rect_from_props(rcti *rect, PointerRNA *ptr)
rect->ymax = RNA_int_get(ptr, "ymax");
}
-static void clip_planes_from_rect(bContext *C, float clip_planes[4][4], const rcti *rect)
+static void clip_planes_from_rect(bContext *C,
+ Depsgraph *depsgraph,
+ float clip_planes[4][4],
+ const rcti *rect)
{
ViewContext vc;
BoundBox bb;
view3d_operator_needs_opengl(C);
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, rect);
- negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
@@ -322,17 +322,18 @@ static void get_pbvh_nodes(
/* select search callback */
switch (mode) {
case PARTIALVIS_INSIDE:
- cb = BKE_pbvh_node_planes_contain_AABB;
+ cb = BKE_pbvh_node_frustum_contain_AABB;
break;
case PARTIALVIS_OUTSIDE:
- cb = BKE_pbvh_node_planes_exclude_AABB;
+ cb = BKE_pbvh_node_frustum_exclude_AABB;
break;
case PARTIALVIS_ALL:
case PARTIALVIS_MASKED:
break;
}
- BKE_pbvh_search_gather(pbvh, cb, clip_planes, nodes, totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, cb, &frustum, nodes, totnode);
}
static int hide_show_exec(bContext *C, wmOperator *op)
@@ -355,7 +356,7 @@ static int hide_show_exec(bContext *C, wmOperator *op)
area = RNA_enum_get(op->ptr, "area");
rect_from_props(&rect, op->ptr);
- clip_planes_from_rect(C, clip_planes, &rect);
+ clip_planes_from_rect(C, depsgraph, clip_planes, &rect);
pbvh = BKE_sculpt_object_pbvh_ensure(depsgraph, ob);
BLI_assert(ob->sculpt->pbvh == pbvh);
@@ -363,6 +364,8 @@ static int hide_show_exec(bContext *C, wmOperator *op)
get_pbvh_nodes(pbvh, &nodes, &totnode, clip_planes, area);
pbvh_type = BKE_pbvh_type(pbvh);
+ negate_m4(clip_planes);
+
/* start undo */
switch (action) {
case PARTIALVIS_HIDE:
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index f3a6cfa0d5c..b4388f6c324 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -113,10 +113,10 @@ void imapaint_region_tiles(
IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
- *tw = ((x + w - 1) >> IMAPAINT_TILE_BITS);
- *th = ((y + h - 1) >> IMAPAINT_TILE_BITS);
- *tx = (x >> IMAPAINT_TILE_BITS);
- *ty = (y >> IMAPAINT_TILE_BITS);
+ *tw = ((x + w - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *th = ((y + h - 1) >> ED_IMAGE_UNDO_TILE_BITS);
+ *tx = (x >> ED_IMAGE_UNDO_TILE_BITS);
+ *ty = (y >> ED_IMAGE_UNDO_TILE_BITS);
}
void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h, bool find_old)
@@ -147,11 +147,12 @@ void ED_imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int
imapaint_region_tiles(ibuf, x, y, w, h, &tilex, &tiley, &tilew, &tileh);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
- image_undo_push_tile(undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
+ ED_image_paint_tile_push(
+ undo_tiles, ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false, find_old);
}
}
@@ -467,12 +468,13 @@ static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customda
static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
- ED_view3d_viewcontext_init(C, &pop->vc);
+ ED_view3d_viewcontext_init(C, &pop->vc, depsgraph);
copy_v2_v2(pop->prevmouse, mouse);
copy_v2_v2(pop->startmouse, mouse);
@@ -538,7 +540,7 @@ static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, Po
RNA_float_get_array(itemptr, "mouse", mouse);
pressure = RNA_float_get(itemptr, "pressure");
eraser = RNA_boolean_get(itemptr, "pen_flip");
- size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+ size = RNA_float_get(itemptr, "size");
/* stroking with fill tool only acts on stroke end */
if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
@@ -699,7 +701,7 @@ static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -1022,7 +1024,7 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
!RNA_boolean_get(op->ptr, "merged");
paint_sample_color(C, ar, event->mval[0], event->mval[1], use_sample_texture, false);
- WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 8f1156295a3..9c95a3cee4d 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -374,25 +374,65 @@ 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)
+ float radius,
+ const float pos[2])
{
Brush *brush = painter->brush;
- int xoff = -radius;
- int yoff = -radius;
+ int offset = (int)floorf(diameter / 2.0f);
unsigned short *mask, *m;
- int x, y;
mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
m = mask;
- for (y = 0; y < diameter; y++) {
- for (x = 0; x < diameter; x++, m++) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
+ int aa_samples = 1.0f / (radius * 0.20f);
+ aa_samples = clamp_i(aa_samples, 3, 16);
- *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamped(brush, len, radius));
+ /* Temporal until we have the brush properties */
+ const float hardness = 1.0f;
+ const float rotation = 0.0f;
+
+ float aa_offset = 1.0f / (2.0f * (float)aa_samples);
+ float aa_step = 1.0f / (float)aa_samples;
+
+ float bpos[2];
+ bpos[0] = pos[0] - floorf(pos[0]) + offset + aa_offset;
+ bpos[1] = pos[1] - floorf(pos[1]) + offset + aa_offset;
+
+ const float co = cosf(DEG2RADF(rotation));
+ const float si = sinf(DEG2RADF(rotation));
+
+ float norm_factor = 65535.0f / (float)(aa_samples * aa_samples);
+
+ for (int y = 0; y < diameter; y++) {
+ for (int x = 0; x < diameter; x++, m++) {
+ float total_samples = 0;
+ for (int i = 0; i < aa_samples; i++) {
+ for (int j = 0; j < aa_samples; j++) {
+ float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)};
+ float xy_rot[2];
+ sub_v2_v2(pixel_xy, bpos);
+
+ xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1];
+ xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1];
+
+ float len = len_v2(xy_rot);
+ float p = len / radius;
+ if (hardness < 1.0f) {
+ p = (p - hardness) / (1 - hardness);
+ p = 1.0f - p;
+ CLAMP(p, 0, 1);
+ }
+ else {
+ p = 1.0;
+ }
+ float hardness_factor = 3.0f * p * p - 2.0f * p * p * p;
+ float curve = BKE_brush_curve_strength_clamped(brush, len, radius);
+ total_samples += curve * hardness_factor;
+ }
+ }
+ *m = (unsigned short)(total_samples * norm_factor);
}
}
@@ -721,7 +761,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * size;
+ /* Adding 4 pixels of padding for brush antialiasing */
+ const int diameter = MAX2(1, size * 2) + 4;
bool do_random = false;
bool do_partial_update = false;
@@ -802,15 +843,13 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s,
}
/* curve mask can only change if the size changes */
- if (diameter != cache->lastdiameter) {
- if (cache->curve_mask) {
- MEM_freeN(cache->curve_mask);
- cache->curve_mask = NULL;
- }
-
- cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
}
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos);
+
/* detect if we need to recreate image brush buffer */
if ((diameter != cache->lastdiameter) || (tex_rotation != cache->last_tex_rotation) ||
do_random || update_color) {
@@ -1197,23 +1236,24 @@ static void paint_2d_do_making_brush(ImagePaintState *s,
int tileh)
{
ImBuf tmpbuf;
- IMB_initImBuf(&tmpbuf, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+ IMB_initImBuf(&tmpbuf, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, 0);
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
for (int ty = tiley; ty <= tileh; ty++) {
for (int tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
unsigned short *mask;
- int origx = region->destx - tx * IMAPAINT_TILE_SIZE;
- int origy = region->desty - ty * IMAPAINT_TILE_SIZE;
+ int origx = region->destx - tx * ED_IMAGE_UNDO_TILE_SIZE;
+ int origy = region->desty - ty * ED_IMAGE_UNDO_TILE_SIZE;
if (s->canvas->rect_float) {
- tmpbuf.rect_float = image_undo_find_tile(
+ tmpbuf.rect_float = ED_image_paint_tile_find(
undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
else {
- tmpbuf.rect = image_undo_find_tile(undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
+ tmpbuf.rect = ED_image_paint_tile_find(
+ undo_tiles, s->image, s->canvas, tx, ty, &mask, false);
}
IMB_rectblend(s->canvas,
@@ -1454,8 +1494,6 @@ static void paint_2d_canvas_free(ImagePaintState *s)
paint_delete_blur_kernel(s->blurkernel);
MEM_freeN(s->blurkernel);
}
-
- image_undo_remove_masks();
}
void paint_2d_stroke(void *ps,
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 04a54ad5137..4c7e5e18257 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -77,15 +77,11 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "UI_interface.h"
-
#include "ED_object.h"
-#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_paint.h"
#include "ED_screen.h"
@@ -93,6 +89,7 @@
#include "ED_view3d.h"
#include "GPU_extensions.h"
+#include "GPU_init_exit.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -105,7 +102,6 @@
#include "IMB_colormanagement.h"
-#include "bmesh.h"
//#include "bmesh_tools.h"
#include "paint_intern.h"
@@ -1812,31 +1808,31 @@ static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
}
if (generate_tile) {
- ListBase *undo_tiles = ED_image_undo_get_tiles();
+ ListBase *undo_tiles = ED_image_paint_tile_list_get();
volatile void *undorect;
if (tinf->masked) {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- &pjIma->maskRect[tile_index],
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ &pjIma->maskRect[tile_index],
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
else {
- undorect = image_undo_push_tile(undo_tiles,
- pjIma->ima,
- pjIma->ibuf,
- tinf->tmpibuf,
- tx,
- ty,
- NULL,
- &pjIma->valid[tile_index],
- true,
- false);
+ undorect = ED_image_paint_tile_push(undo_tiles,
+ pjIma->ima,
+ pjIma->ibuf,
+ tinf->tmpibuf,
+ tx,
+ ty,
+ NULL,
+ &pjIma->valid[tile_index],
+ true,
+ false);
}
BKE_image_mark_dirty(pjIma->ima, pjIma->ibuf);
@@ -1885,14 +1881,14 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* calculate the undo tile offset of the pixel, used to store the original
* pixel color and accumulated mask if any */
- x_tile = x_px >> IMAPAINT_TILE_BITS;
- y_tile = y_px >> IMAPAINT_TILE_BITS;
+ x_tile = x_px >> ED_IMAGE_UNDO_TILE_BITS;
+ y_tile = y_px >> ED_IMAGE_UNDO_TILE_BITS;
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
+ x_round = x_tile * ED_IMAGE_UNDO_TILE_SIZE;
+ y_round = y_tile * ED_IMAGE_UNDO_TILE_SIZE;
// memset(projPixel, 0, size);
- tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_offset = (x_px - x_round) + (y_px - y_round) * ED_IMAGE_UNDO_TILE_SIZE;
tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
/* other thread may be initializing the tile so wait here */
@@ -1900,8 +1896,9 @@ static ProjPixel *project_paint_uvpixel_init(const ProjPaintState *ps,
/* pass */
}
- BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
- BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+ BLI_assert(tile_index <
+ (ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x) * ED_IMAGE_UNDO_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (ED_IMAGE_UNDO_TILE_SIZE * ED_IMAGE_UNDO_TILE_SIZE));
projPixel->valid = projima->valid[tile_index];
@@ -2979,7 +2976,7 @@ static void project_paint_face_init(const ProjPaintState *ps,
TileInfo tinf = {
ps->tile_lock,
ps->do_masking,
- IMAPAINT_TILE_NUMBER(ibuf->x),
+ ED_IMAGE_UNDO_TILE_NUMBER(ibuf->x),
tmpibuf,
ps->projImages + image_index,
};
@@ -3931,7 +3928,7 @@ static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_th
BLI_spin_init(ps->tile_lock);
}
- image_undo_init_locks();
+ ED_image_paint_tile_lock_init();
}
for (a = 0; a < ps->thread_tot; a++) {
@@ -4249,8 +4246,8 @@ static void project_paint_build_proj_ima(ProjPaintState *ps,
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) *
- IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ size = sizeof(void **) * ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->x) *
+ ED_IMAGE_UNDO_TILE_NUMBER(projIma->ibuf->y);
projIma->partRedrawRect = BLI_memarena_alloc(
arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
partial_redraw_array_init(projIma->partRedrawRect);
@@ -4540,8 +4537,6 @@ static void project_paint_end(ProjPaintState *ps)
{
int a;
- image_undo_remove_masks();
-
/* dereference used image buffers */
if (ps->is_shared_user == false) {
ProjPaintImage *projIma;
@@ -4583,7 +4578,7 @@ static void project_paint_end(ProjPaintState *ps)
MEM_freeN((void *)ps->tile_lock);
}
- image_undo_end_locks();
+ ED_image_paint_tile_lock_end();
#ifndef PROJ_DEBUG_NOSEAMBLEED
if (ps->seam_bleed_px > 0.0f) {
@@ -6143,6 +6138,9 @@ static bool texture_paint_image_from_view_poll(bContext *C)
CTX_wm_operator_poll_msg_set(C, "No 3D viewport found to create image from");
return false;
}
+ if (!GPU_is_initialized()) {
+ return false;
+ }
return true;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c
deleted file mode 100644
index 93dcd3ad0f6..00000000000
--- a/source/blender/editors/sculpt_paint/paint_image_undo.c
+++ /dev/null
@@ -1,625 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * 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 edsculpt
- */
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_utildefines.h"
-#include "BLI_threads.h"
-
-#include "DNA_image_types.h"
-#include "DNA_windowmanager_types.h"
-#include "DNA_object_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
-
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-
-#include "BKE_context.h"
-#include "BKE_image.h"
-#include "BKE_paint.h"
-#include "BKE_undo_system.h"
-
-#include "DEG_depsgraph.h"
-
-#include "ED_paint.h"
-#include "ED_undo.h"
-#include "ED_util.h"
-#include "ED_object.h"
-
-#include "GPU_draw.h"
-
-#include "WM_api.h"
-
-#include "paint_intern.h"
-
-/* -------------------------------------------------------------------- */
-/** \name Undo Conversion
- * \{ */
-
-typedef struct UndoImageTile {
- struct UndoImageTile *next, *prev;
-
- char ibufname[IMB_FILENAME_SIZE];
-
- union {
- float *fp;
- unsigned int *uint;
- void *pt;
- } rect;
-
- unsigned short *mask;
-
- int x, y;
-
- /* TODO(campbell): avoid storing the ID per tile,
- * adds unnecessary overhead restoring undo steps when most tiles share the same image. */
- UndoRefID_Image image_ref;
-
- short source;
- bool use_float;
- char gen_type;
- bool valid;
-
- size_t undo_size;
-} UndoImageTile;
-
-/* this is a static resource for non-globality,
- * Maybe it should be exposed as part of the
- * paint operation, but for now just give a public interface */
-static SpinLock undolock;
-
-void image_undo_init_locks(void)
-{
- BLI_spin_init(&undolock);
-}
-
-void image_undo_end_locks(void)
-{
- BLI_spin_end(&undolock);
-}
-
-/* UNDO */
-typedef enum {
- COPY = 0,
- RESTORE = 1,
- RESTORE_COPY = 2,
-} CopyMode;
-
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
-{
- if (mode == COPY) {
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- else {
- if (mode == RESTORE_COPY) {
- IMB_rectcpy(tmpibuf,
- ibuf,
- 0,
- 0,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
- }
- /* swap to the tmpbuf for easy copying */
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- IMB_rectcpy(ibuf,
- tmpibuf,
- tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE,
- 0,
- 0,
- IMAPAINT_TILE_SIZE,
- IMAPAINT_TILE_SIZE);
-
- if (mode == RESTORE) {
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
- }
- else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
- }
- }
-}
-
-void *image_undo_find_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate)
-{
- UndoImageTile *tile;
- const bool use_float = (ibuf->rect_float != NULL);
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type &&
- ima->source == tile->source) {
- if (tile->use_float == use_float) {
- if (STREQ(tile->ibufname, ibuf->name)) {
- if (mask) {
- /* allocate mask if requested */
- if (!tile->mask) {
- tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE *
- IMAPAINT_TILE_SIZE,
- "UndoImageTile.mask");
- }
-
- *mask = tile->mask;
- }
- if (validate) {
- tile->valid = true;
- }
- return tile->rect.pt;
- }
- }
- }
- }
-
- return NULL;
-}
-
-void *image_undo_push_tile(ListBase *undo_tiles,
- Image *ima,
- ImBuf *ibuf,
- ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool **valid,
- bool proj,
- bool find_prev)
-{
- UndoImageTile *tile;
- int allocsize;
- const bool use_float = (ibuf->rect_float != NULL);
- void *data;
-
- /* check if tile is already pushed */
-
- /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
- if (find_prev) {
- data = image_undo_find_tile(undo_tiles, ima, ibuf, x_tile, y_tile, mask, true);
- if (data) {
- return data;
- }
- }
-
- if (*tmpibuf == NULL) {
- *tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
- }
-
- tile = MEM_callocN(sizeof(UndoImageTile), "UndoImageTile");
- tile->x = x_tile;
- tile->y = y_tile;
-
- /* add mask explicitly here */
- if (mask) {
- *mask = tile->mask = MEM_callocN(
- sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE, "UndoImageTile.mask");
- }
- allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
- allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
- tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
-
- BLI_strncpy(tile->ibufname, ibuf->name, sizeof(tile->ibufname));
-
- tile->gen_type = ima->gen_type;
- tile->source = ima->source;
- tile->use_float = use_float;
- tile->valid = true;
- tile->image_ref.ptr = ima;
-
- if (valid) {
- *valid = &tile->valid;
- }
- undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
-
- if (proj) {
- BLI_spin_lock(&undolock);
- }
- BLI_addtail(undo_tiles, tile);
-
- if (proj) {
- BLI_spin_unlock(&undolock);
- }
- return tile->rect.pt;
-}
-
-void image_undo_remove_masks(void)
-{
- ListBase *undo_tiles = ED_image_undo_get_tiles();
- UndoImageTile *tile;
-
- for (tile = undo_tiles->first; tile; tile = tile->next) {
- if (tile->mask) {
- MEM_freeN(tile->mask);
- tile->mask = NULL;
- }
- }
-}
-
-static void image_undo_restore_runtime(ListBase *lb)
-{
- ImBuf *ibuf, *tmpibuf;
- UndoImageTile *tile;
-
- tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (tile = lb->first; tile; tile = tile->next) {
- Image *ima = tile->image_ref.ptr;
- ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
-
- GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_restore_list(ListBase *lb)
-{
- ImBuf *tmpibuf = IMB_allocImBuf(
- IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
-
- for (UndoImageTile *tile = lb->first; tile; tile = tile->next) {
-
- Image *ima = tile->image_ref.ptr;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
-
- if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
- /* current ImBuf filename was changed, probably current frame
- * was changed when painting on image sequence, rather than storing
- * full image user (which isn't so obvious, btw) try to find ImBuf with
- * matched file name in list of already loaded images */
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
-
- ibuf = BKE_image_get_ibuf_with_name(ima, tile->ibufname);
- }
-
- if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float)) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- if (ima->gen_type != tile->gen_type || ima->source != tile->source) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- const bool use_float = (ibuf->rect_float != NULL);
-
- if (use_float != tile->use_float) {
- BKE_image_release_ibuf(ima, ibuf, NULL);
- continue;
- }
-
- undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
-
- BKE_image_mark_dirty(ima, ibuf);
- GPU_free_image(ima); /* force OpenGL reload */
-
- if (ibuf->rect_float) {
- ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
- }
- if (ibuf->mipmap[0]) {
- ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
- }
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
- DEG_id_tag_update(&ima->id, 0);
-
- BKE_image_release_ibuf(ima, ibuf, NULL);
- }
-
- IMB_freeImBuf(tmpibuf);
-}
-
-static void image_undo_free_list(ListBase *lb)
-{
- for (UndoImageTile *tile = lb->first, *tile_next; tile; tile = tile_next) {
- tile_next = tile->next;
- MEM_freeN(tile->rect.pt);
- MEM_freeN(tile);
- }
-}
-
-static void image_undo_invalidate(void)
-{
- UndoImageTile *tile;
- ListBase *lb = ED_image_undo_get_tiles();
-
- for (tile = lb->first; tile; tile = tile->next) {
- tile->valid = false;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Implements ED Undo System
- * \{ */
-
-typedef struct ImageUndoStep {
- UndoStep step;
- ListBase tiles;
- bool is_encode_init;
- ePaintMode paint_mode;
-} ImageUndoStep;
-
-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;
- if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
- return true;
- }
- }
- else {
- if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
- return true;
- }
- }
- return false;
-}
-
-static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* dummy, memory is cleared anyway. */
- us->is_encode_init = true;
- BLI_listbase_clear(&us->tiles);
-}
-
-static bool image_undosys_step_encode(struct bContext *C,
- struct Main *UNUSED(bmain),
- UndoStep *us_p)
-{
- /* dummy, encoding is done along the way by adding tiles
- * to the current 'ImageUndoStep' added by encode_init. */
- ImageUndoStep *us = (ImageUndoStep *)us_p;
-
- BLI_assert(us->step.data_size == 0);
-
- int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
-
- if (us->is_encode_init) {
- /* first dispose of invalid tiles (may happen due to drag dot for instance) */
- for (UndoImageTile *tile = us->tiles.first; tile;) {
- if (!tile->valid) {
- UndoImageTile *tmp_tile = tile->next;
- MEM_freeN(tile->rect.pt);
- BLI_freelinkN(&us->tiles, tile);
- tile = tmp_tile;
- }
- else {
- us->step.data_size += allocsize * (tile->use_float ? sizeof(float) : sizeof(char));
- tile = tile->next;
- }
- }
- }
- else {
- /* Happens when switching modes. */
- ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
- }
-
- us_p->is_applied = true;
-
- return true;
-}
-
-static void image_undosys_step_decode_undo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == true);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = false;
-}
-
-static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
-{
- BLI_assert(us->step.is_applied == false);
- image_undo_restore_list(&us->tiles);
- us->step.is_applied = true;
-}
-
-static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
- if (us_iter->step.next->is_applied == false) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
- while (us_iter != us || (!is_final && us_iter == us)) {
- image_undosys_step_decode_undo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
-}
-
-static void image_undosys_step_decode_redo(ImageUndoStep *us)
-{
- ImageUndoStep *us_iter = us;
- while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
- if (us_iter->step.prev->is_applied == true) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.prev;
- }
- while (us_iter && (us_iter->step.is_applied == false)) {
- image_undosys_step_decode_redo_impl(us_iter);
- if (us_iter == us) {
- break;
- }
- us_iter = (ImageUndoStep *)us_iter->step.next;
- }
-}
-
-static void image_undosys_step_decode(
- struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- if (dir < 0) {
- image_undosys_step_decode_undo(us, is_final);
- }
- else {
- image_undosys_step_decode_redo(us);
- }
-
- if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
- ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
- }
-
- /* Refresh texture slots. */
- ED_editors_init_for_undo(bmain);
-}
-
-static void image_undosys_step_free(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- image_undo_free_list(&us->tiles);
-}
-
-static void image_undosys_foreach_ID_ref(UndoStep *us_p,
- UndoTypeForEachIDRefFn foreach_ID_ref_fn,
- void *user_data)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- for (UndoImageTile *tile = us->tiles.first; tile; tile = tile->next) {
- foreach_ID_ref_fn(user_data, ((UndoRefID *)&tile->image_ref));
- }
-}
-
-/* Export for ED_undo_sys. */
-void ED_image_undosys_type(UndoType *ut)
-{
- ut->name = "Image";
- ut->poll = image_undosys_poll;
- ut->step_encode_init = image_undosys_step_encode_init;
- ut->step_encode = image_undosys_step_encode;
- ut->step_decode = image_undosys_step_decode;
- ut->step_free = image_undosys_step_free;
-
- ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
-
- ut->use_context = true;
-
- ut->step_size = sizeof(ImageUndoStep);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Utilities
- * \{ */
-
-ListBase *ED_image_undosys_step_get_tiles(UndoStep *us_p)
-{
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- return &us->tiles;
-}
-
-ListBase *ED_image_undo_get_tiles(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- UndoStep *us_prev = ustack->step_init;
- UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- /* We should always have an undo push started when accessing tiles,
- * not doing this means we won't have paint_mode correctly set. */
- BLI_assert(us_p == us_prev);
- if (us_p != us_prev) {
- /* Fallback value until we can be sure this never happens. */
- us->paint_mode = PAINT_MODE_TEXTURE_2D;
- }
- return ED_image_undosys_step_get_tiles(us_p);
-}
-
-/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
-void ED_image_undo_restore(UndoStep *us)
-{
- ListBase *lb = ED_image_undosys_step_get_tiles(us);
- image_undo_restore_runtime(lb);
- image_undo_invalidate();
-}
-
-void ED_image_undo_push_begin(const char *name, int paint_mode)
-{
- UndoStack *ustack = ED_undo_stack_get();
- bContext *C = NULL; /* special case, we never read from this. */
- UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
- ImageUndoStep *us = (ImageUndoStep *)us_p;
- BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
- us->paint_mode = paint_mode;
-}
-
-void ED_image_undo_push_end(void)
-{
- UndoStack *ustack = ED_undo_stack_get();
- BKE_undosys_step_push(ustack, NULL, NULL);
- WM_file_tag_modified();
-}
-
-/** \} */
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index 5efedf69fe4..19380fb9022 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -29,7 +29,6 @@ struct Brush;
struct ColorManagedDisplay;
struct ColorSpace;
struct ImagePool;
-struct ListBase;
struct MTex;
struct Object;
struct Paint;
@@ -37,7 +36,6 @@ struct PaintStroke;
struct PointerRNA;
struct RegionView3D;
struct Scene;
-struct UndoStep;
struct VPaint;
struct ViewContext;
struct bContext;
@@ -70,7 +68,7 @@ struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeRedraw redraw,
StrokeDone done,
int event_type);
-void paint_stroke_data_free(struct wmOperator *op);
+void paint_stroke_free(struct bContext *C, struct wmOperator *op);
bool paint_space_stroke_enabled(struct Brush *br, enum ePaintMode mode);
bool paint_supports_dynamic_size(struct Brush *br, enum ePaintMode mode);
@@ -184,10 +182,6 @@ typedef struct ImagePaintPartialRedraw {
int enabled;
} ImagePaintPartialRedraw;
-#define IMAPAINT_TILE_BITS 6
-#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
-#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
-
bool image_texture_paint_poll(struct bContext *C);
void imapaint_image_update(struct SpaceImage *sima,
struct Image *image,
@@ -252,31 +246,6 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot);
-/* paint_image_undo.c */
-void *image_undo_find_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- int x_tile,
- int y_tile,
- unsigned short **mask,
- bool validate);
-void *image_undo_push_tile(ListBase *undo_tiles,
- struct Image *ima,
- struct ImBuf *ibuf,
- struct ImBuf **tmpibuf,
- int x_tile,
- int y_tile,
- unsigned short **,
- bool **valid,
- bool proj,
- bool find_prev);
-void image_undo_remove_masks(void);
-void image_undo_init_locks(void);
-void image_undo_end_locks(void);
-
-struct ListBase *ED_image_undosys_step_get_tiles(struct UndoStep *us_p);
-struct ListBase *ED_image_undo_get_tiles(void);
-
/* sculpt_uv.c */
void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot);
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 0e8d4d75360..d160fba4013 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -109,6 +109,7 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
const PaintMaskFloodMode mode = data->mode;
const float value = data->value;
+ bool redraw = false;
PBVHVertexIter vi;
@@ -116,13 +117,19 @@ static void mask_flood_fill_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
+ float prevmask = *vi.mask;
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- if (data->multires) {
- BKE_pbvh_node_mark_normals_update(node);
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ if (data->multires) {
+ BKE_pbvh_node_mark_normals_update(node);
+ }
}
}
@@ -159,17 +166,16 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
.value = value,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
-
- 0, totnode, &data, mask_flood_fill_task_cb, &settings);
+ PBVHParallelSettings 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);
if (multires) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
if (nodes) {
@@ -255,24 +261,32 @@ static void mask_box_select_task_cb(void *__restrict userdata,
PBVHVertexIter vi;
bool any_masked = false;
+ bool redraw = false;
BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE)
{
if (is_effected(clip_planes_final, vi.co)) {
+ float prevmask = *vi.mask;
if (!any_masked) {
any_masked = true;
sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_MASK);
- BKE_pbvh_node_mark_redraw(node);
if (data->multires) {
BKE_pbvh_node_mark_normals_update(node);
}
}
mask_flood_fill_set_elem(vi.mask, mode, value);
+ if (prevmask != *vi.mask) {
+ redraw = true;
+ }
}
}
BKE_pbvh_vertex_iter_end;
+
+ if (redraw) {
+ BKE_pbvh_node_mark_update_mask(node);
+ }
}
bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select)
@@ -297,7 +311,6 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
/* transform the clip planes in object space */
ED_view3d_clipping_calc(&bb, clip_planes, vc->ar, vc->obact, rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -315,8 +328,10 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
flip_plane(clip_planes_final[j], clip_planes[j], symmpass);
}
- BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
+ BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
MaskTaskData data = {
.ob = ob,
@@ -328,11 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
.clip_planes_final = clip_planes_final,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings);
+ PBVHParallelSettings 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);
if (nodes) {
MEM_freeN(nodes);
@@ -344,6 +357,8 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(ar);
@@ -462,7 +477,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
* of lasso */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* lasso data calculations */
data.vc = &vc;
@@ -483,7 +498,6 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
&data);
ED_view3d_clipping_calc(&bb, clip_planes, vc.ar, vc.obact, &data.rect);
- negate_m4(clip_planes);
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
pbvh = ob->sculpt->pbvh;
@@ -505,8 +519,11 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle
* (should greatly help with bigger meshes) */
+ PBVHFrustumPlanes frustum = {.planes = clip_planes_final, .num_planes = 4};
BKE_pbvh_search_gather(
- pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
+ pbvh, BKE_pbvh_node_frustum_contain_AABB, &frustum, &nodes, &totnode);
+
+ negate_m4(clip_planes_final);
data.task_data.ob = ob;
data.task_data.pbvh = pbvh;
@@ -515,11 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
data.task_data.mode = mode;
data.task_data.value = value;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- (totnode > SCULPT_THREADED_LIMIT));
- BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings);
+ PBVHParallelSettings 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);
if (nodes) {
MEM_freeN(nodes);
@@ -531,6 +546,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
}
+ BKE_pbvh_update_vertex_data(pbvh, PBVH_UpdateMask);
+
sculpt_undo_push_end();
ED_region_tag_redraw(vc.ar);
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index f58afcdadc1..97455d479dc 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -29,32 +29,22 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
-#include "DNA_gpencil_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_gpencil.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
-
-#include "DEG_depsgraph.h"
#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_select_utils.h"
#include "ED_image.h"
-#include "ED_gpencil.h"
-#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
-#include "WM_toolsystem.h"
#include "RNA_access.h"
#include "RNA_define.h"
-#include "RNA_enum_types.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index c764933fcf0..36418045551 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -43,7 +43,6 @@
#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
-#include "BKE_mesh.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -257,6 +256,7 @@ static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode m
SCULPT_TOOL_GRAB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_SNAKE_HOOK,
SCULPT_TOOL_ELASTIC_DEFORM,
SCULPT_TOOL_POSE)) {
return false;
@@ -669,7 +669,7 @@ static float paint_space_stroke_spacing(bContext *C,
return max_ff(0.001f, size_clamp * spacing / 50.f);
}
else {
- return max_ff(1.0, size_clamp * spacing / 50.0f);
+ return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f);
}
}
@@ -808,7 +808,7 @@ static int paint_space_stroke(bContext *C,
while (length > 0.0f) {
float spacing = paint_space_stroke_spacing_variable(
C, scene, stroke, pressure, dpressure, length);
- float mouse[2];
+ float mouse[3];
if (length >= spacing) {
if (use_scene_spacing) {
@@ -857,14 +857,16 @@ PaintStroke *paint_stroke_new(bContext *C,
StrokeDone done,
int event_type)
{
+ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Paint *p = BKE_paint_get_active_from_context(C);
Brush *br = stroke->brush = BKE_paint_brush(p);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
float zoomx, zoomy;
- ED_view3d_viewcontext_init(C, &stroke->vc);
+ ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
stroke->get_location = get_location;
stroke->test_start = test_start;
@@ -887,6 +889,10 @@ PaintStroke *paint_stroke_new(bContext *C,
ups->overlap_factor = 1.0;
ups->stroke_active = true;
+ if (rv3d) {
+ rv3d->rflag |= RV3D_PAINTING;
+ }
+
zero_v3(ups->average_stroke_accum);
ups->average_stroke_counter = 0;
@@ -901,20 +907,46 @@ PaintStroke *paint_stroke_new(bContext *C,
return stroke;
}
-void paint_stroke_data_free(struct wmOperator *op)
+void paint_stroke_free(bContext *C, wmOperator *op)
{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
BKE_paint_set_overlay_override(0);
+
+ PaintStroke *stroke = op->customdata;
+ if (stroke == NULL) {
+ return;
+ }
+
+ UnifiedPaintSettings *ups = stroke->ups;
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
+
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
+
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
+
+ if (stroke->stroke_cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ }
+
+ BLI_freelistN(&stroke->line);
+
MEM_SAFE_FREE(op->customdata);
}
-static void stroke_done(struct bContext *C, struct wmOperator *op)
+static void stroke_done(bContext *C, wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
-
/* reset rotation here to avoid doing so in cursor display */
if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
ups->brush_rotation = 0.0f;
@@ -934,21 +966,7 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
}
}
- if (stroke->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
- }
-
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
-
- if (stroke->stroke_cursor) {
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- }
-
- BLI_freelistN(&stroke->line);
-
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
@@ -962,6 +980,7 @@ static bool sculpt_is_grab_tool(Brush *br)
return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_ELASTIC_DEFORM,
+ SCULPT_TOOL_POSE,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK);
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 6459325e6ee..a014fe7fdff 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -46,7 +46,6 @@
#include "BKE_image.h"
#include "BKE_material.h"
#include "BKE_mesh_runtime.h"
-#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -145,7 +144,6 @@ void paint_calc_redraw_planes(float planes[4][4],
rect.ymax += 2;
ED_view3d_clipping_calc(&bb, planes, ar, ob, &rect);
- negate_m4(planes);
}
float paint_calc_object_space_radius(ViewContext *vc, const float center[3], float pixel_radius)
@@ -506,7 +504,7 @@ void paint_sample_color(
unsigned int totpoly = me->totpoly;
if (CustomData_has_layer(&me_eval->ldata, CD_MLOOPUV)) {
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
view3d_operator_needs_opengl(C);
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 12da8790b91..77c95c6acb3 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -34,7 +34,6 @@
#include "BLI_array_utils.h"
#include "BLI_task.h"
-#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
#include "DNA_particle_types.h"
#include "DNA_scene_types.h"
@@ -42,7 +41,6 @@
#include "DNA_object_types.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "BKE_brush.h"
#include "BKE_context.h"
@@ -195,17 +193,12 @@ static bool vertex_paint_use_fast_update_check(Object *ob)
return false;
}
-static void paint_last_stroke_update(Scene *scene, ARegion *ar, const float mval[2])
+static void paint_last_stroke_update(Scene *scene, const float location[3])
{
- const int mval_i[2] = {mval[0], mval[1]};
- float world[3];
-
- if (ED_view3d_autodist_simple(ar, mval_i, world, 0, NULL)) {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->average_stroke_counter++;
- add_v3_v3(ups->average_stroke_accum, world);
- ups->last_stroke_valid = true;
- }
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ ups->average_stroke_counter++;
+ add_v3_v3(ups->average_stroke_accum, location);
+ ups->last_stroke_valid = true;
}
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -260,7 +253,7 @@ static bool weight_paint_poll_ex(bContext *C, bool check_tool)
(BKE_paint_brush(&CTX_data_tool_settings(C)->wpaint->paint) != NULL) &&
(sa = CTX_wm_area(C)) && (sa->spacetype == SPACE_VIEW3D)) {
ARegion *ar = CTX_wm_region(C);
- if (ar->regiontype == RGN_TYPE_WINDOW) {
+ if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_HUD)) {
if (!check_tool || WM_toolsystem_active_tool_is_brush(C)) {
return 1;
}
@@ -1610,7 +1603,7 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo
/* make mode data storage */
wpd = MEM_callocN(sizeof(struct WPaintData), "WPaintData");
paint_stroke_set_mode_data(stroke, wpd);
- ED_view3d_viewcontext_init(C, &wpd->vc);
+ ED_view3d_viewcontext_init(C, &wpd->vc, depsgraph);
view_angle_limits_init(&wpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -2079,11 +2072,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data,
struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((data->sd->flags & SCULPT_USE_OPENMP) &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings);
+ PBVHParallelSettings 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);
uint accum_len = 0;
double accum_weight = 0.0;
@@ -2128,24 +2119,23 @@ static void wpaint_paint_leaves(bContext *C,
/* Use this so average can modify its weight without touching the brush. */
data.strength = BKE_brush_weight_get(scene, brush);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
/* NOTE: current mirroring code cannot be run in parallel */
- settings.use_threading = !(me->editflag & ME_EDIT_MIRROR_X);
+ PBVHParallelSettings 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);
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
case WPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings);
break;
case WPAINT_TOOL_BLUR:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings);
break;
case WPAINT_TOOL_DRAW:
- BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -2351,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -2446,7 +2436,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -2597,11 +2587,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
* - revise whether op->customdata should be added in object, in set_vpaint
*/
-typedef struct PolyFaceMap {
- struct PolyFaceMap *next, *prev;
- int facenr;
-} PolyFaceMap;
-
struct VPaintData {
ViewContext vc;
struct NormalAnglePrecalc normal_angle_precalc;
@@ -2655,7 +2640,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
/* make mode data storage */
vpd = MEM_callocN(sizeof(*vpd), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
- ED_view3d_viewcontext_init(C, &vpd->vc);
+ ED_view3d_viewcontext_init(C, &vpd->vc, depsgraph);
view_angle_limits_init(&vpd->normal_angle_precalc,
vp->paint.brush->falloff_angle,
(vp->paint.brush->flag & BRUSH_FRONTFACE_FALLOFF) != 0);
@@ -3141,9 +3126,9 @@ static void calculate_average_color(SculptThreadedTaskData *data,
struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__);
data->custom_data = accum;
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings);
+ PBVHParallelSettings 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);
uint accum_len = 0;
uint accum_value[3] = {0};
@@ -3187,21 +3172,21 @@ static void vpaint_paint_leaves(bContext *C,
.lcol = (uint *)me->mloopcol,
.me = me,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, true, totnode);
switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) {
case VPAINT_TOOL_AVERAGE:
calculate_average_color(&data, nodes, totnode);
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
case VPAINT_TOOL_BLUR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings);
break;
case VPAINT_TOOL_SMEAR:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings);
break;
case VPAINT_TOOL_DRAW:
- BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings);
break;
}
}
@@ -3331,7 +3316,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, vc->ar, ss->cache->mouse);
+ paint_last_stroke_update(scene, ss->cache->location);
ED_region_tag_redraw(vc->ar);
@@ -3388,7 +3373,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
event->type);
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
index 068c36abdaa..71865d0de73 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_color_utils.c
@@ -20,13 +20,9 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_color_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_brush_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
#include "BLI_math_base.h"
#include "BLI_math_color.h"
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 4aa9dc8a295..f0fe2d4ebdc 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c
@@ -24,13 +24,8 @@
#include "BLI_math.h"
#include "BLI_bitmap.h"
-#include "IMB_imbuf.h"
-#include "IMB_imbuf_types.h"
-#include "IMB_colormanagement.h"
-
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
-#include "DNA_particle_types.h"
#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -44,7 +39,6 @@
#include "BKE_deform.h"
#include "BKE_mesh.h"
#include "BKE_mesh_iterators.h"
-#include "BKE_mesh_mapping.h"
#include "BKE_mesh_runtime.h"
#include "BKE_modifier.h"
#include "BKE_object_deform.h"
@@ -178,11 +172,12 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
static int weight_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Mesh *me;
bool changed = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && (vc.obact->actdef != 0)) {
@@ -308,10 +303,11 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
if (C) {
wmWindow *win = CTX_wm_window(C);
if (win && win->eventstate) {
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
ViewContext vc;
Mesh *me;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
me = BKE_mesh_from_object(vc.obact);
if (me && me->dvert && vc.v3d && vc.rv3d && vc.obact->defbase.first) {
@@ -379,8 +375,9 @@ static const EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C,
static int weight_sample_group_exec(bContext *C, wmOperator *op)
{
int type = RNA_enum_get(op->ptr, "group");
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
BLI_assert(type + 1 >= 0);
vc.obact->actdef = type + 1;
@@ -885,7 +882,7 @@ void PAINT_OT_weight_gradient(wmOperatorType *ot)
prop = RNA_def_enum(ot->srna, "type", gradient_types, 0, "Type", "");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
/** \} */
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 c71315872f6..28699b45add 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c
@@ -20,16 +20,12 @@
* Intended for use by `paint_vertex.c` & `paint_vertex_weight_ops.c`.
*/
-#include "MEM_guardedalloc.h"
-
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_string_utils.h"
#include "DNA_armature_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_brush_types.h"
#include "DNA_object_types.h"
#include "BKE_action.h"
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 351e4c0482b..06fa03ccbc6 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -27,13 +27,11 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
-#include "BLI_hash.h"
#include "BLI_gsqueue.h"
-#include "BLI_stack.h"
+#include "BLI_ghash.h"
+#include "BLI_hash.h"
#include "BLI_task.h"
-#include "BLI_stack.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "BLT_translation.h"
@@ -66,10 +64,10 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_subdiv_ccg.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_query.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -96,21 +94,13 @@
#include <stdlib.h>
#include <string.h>
-/* Sculpt PBVH abstraction API */
-
-/* Do not use these functions while working with PBVH_GRIDS data in SculptSession */
-
-float *sculpt_vertex_co_get(SculptSession *ss, int index)
-{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- return ss->mvert[index].co;
- case PBVH_BMESH:
- return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
- default:
- return NULL;
- }
-}
+/* Sculpt PBVH abstraction API
+ *
+ * This is read-only, for writing use PBVH vertex iterators. There vd.index matches
+ * the indices used here.
+ *
+ * For multires, the same vertex in multiple grids is counted multiple times, with
+ * different index for each grid. */
static void sculpt_vertex_random_access_init(SculptSession *ss)
{
@@ -119,28 +109,36 @@ static void sculpt_vertex_random_access_init(SculptSession *ss)
}
}
-static int sculpt_active_vertex_get(SculptSession *ss)
+static int sculpt_vertex_count_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->active_vertex_index;
+ return ss->totvert;
case PBVH_BMESH:
- return ss->active_vertex_index;
- default:
- return 0;
+ return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
+ case PBVH_GRIDS:
+ return BKE_pbvh_get_grid_num_vertices(ss->pbvh);
}
+
+ return 0;
}
-static int sculpt_vertex_count_get(SculptSession *ss)
+const float *sculpt_vertex_co_get(SculptSession *ss, int index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- return ss->totvert;
+ return ss->mvert[index].co;
case PBVH_BMESH:
- return BM_mesh_elem_count(BKE_pbvh_get_bmesh(ss->pbvh), BM_VERT);
- default:
- return 0;
+ return BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co;
+ case PBVH_GRIDS: {
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return CCG_elem_co(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+ return NULL;
}
static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
@@ -152,27 +150,14 @@ static void sculpt_vertex_normal_get(SculptSession *ss, int index, float no[3])
case PBVH_BMESH:
copy_v3_v3(no, BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->no);
break;
- default:
- zero_v3(no);
- return;
- }
-}
-
-static void sculpt_vertex_mask_set(SculptSession *ss, int index, float mask)
-{
- BMVert *v;
- float *mask_p;
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- ss->vmask[index] = mask;
- return;
- case PBVH_BMESH:
- v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
- mask_p = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
- *(mask_p) = mask;
- return;
- default:
- return;
+ 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;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ copy_v3_v3(no, CCG_elem_no(key, CCG_elem_offset(key, elem, vertex_index)));
+ break;
+ }
}
}
@@ -187,49 +172,58 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index)
v = BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index);
mask = BM_ELEM_CD_GET_VOID_P(v, CustomData_get_offset(&ss->bm->vdata, CD_PAINT_MASK));
return *mask;
- default:
- 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 vertex_index = index - grid_index * key->grid_area;
+ CCGElem *elem = BKE_pbvh_get_grids(ss->pbvh)[grid_index];
+ return *CCG_elem_mask(key, CCG_elem_offset(key, elem, vertex_index));
+ }
}
+
+ return 0.0f;
}
-static void UNUSED_FUNCTION(sculpt_vertex_co_set)(SculptSession *ss, int index, float co[3])
+static int sculpt_active_vertex_get(SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
- copy_v3_v3(ss->mvert[index].co, co);
- return;
+ return ss->active_vertex_index;
case PBVH_BMESH:
- copy_v3_v3(BM_vert_at_index(BKE_pbvh_get_bmesh(ss->pbvh), index)->co, co);
- return;
- default:
- return;
+ return ss->active_vertex_index;
+ case PBVH_GRIDS:
+ return ss->active_vertex_index;
}
+
+ return 0;
}
-static void UNUSED_FUNCTION(sculpt_vertex_tag_update)(SculptSession *ss, int index)
+static const float *sculpt_active_vertex_co_get(SculptSession *ss)
{
- switch (BKE_pbvh_type(ss->pbvh)) {
- case PBVH_FACES:
- ss->mvert[index].flag |= ME_VERT_PBVH_UPDATE;
- return;
- case PBVH_BMESH:
- return;
- default:
- return;
- }
+ return sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss));
+}
+
+static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3])
+{
+ sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), normal);
}
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
+ /* Storage */
int *neighbors;
int size;
int capacity;
-
int neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
- int index;
+ /* Internal iterator. */
+ int num_duplicates;
int i;
+
+ /* Public */
+ int index;
+ bool is_duplicate;
} SculptVertexNeighborIter;
static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter, int neighbor_index)
@@ -265,6 +259,7 @@ static void sculpt_vertex_neighbors_get_bmesh(SculptSession *ss,
BMIter liter;
BMLoop *l;
iter->size = 0;
+ iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@@ -287,6 +282,7 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
int i;
MeshElemMap *vert_map = &ss->pmap[(int)index];
iter->size = 0;
+ iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
iter->neighbors = iter->neighbors_fixed;
@@ -296,18 +292,52 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss,
if (poly_get_adj_loops_from_vert(p, ss->mloop, (int)index, f_adj_v) != -1) {
int j;
for (j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
- if (vert_map->count != 2 || ss->pmap[f_adj_v[j]].count <= 2) {
- if (f_adj_v[j] != (int)index) {
- sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
- }
+ if (f_adj_v[j] != (int)index) {
+ sculpt_vertex_neighbor_add(iter, f_adj_v[j]);
}
}
}
}
}
+static void sculpt_vertex_neighbors_get_grids(SculptSession *ss,
+ const int index,
+ const bool include_duplicates,
+ SculptVertexNeighborIter *iter)
+{
+ /* TODO: optimize this. We could fill SculptVertexNeighborIter directly,
+ * maybe provide coordinate and mask pointers directly rather than converting
+ * back and forth between CCGElem and global index. */
+ const CCGKey *key = BKE_pbvh_get_grid_key(ss->pbvh);
+ const int grid_index = index / key->grid_area;
+ const int vertex_index = index - grid_index * key->grid_area;
+
+ SubdivCCGCoord coord = {.grid_index = grid_index,
+ .x = vertex_index % key->grid_size,
+ .y = vertex_index / key->grid_size};
+
+ SubdivCCGNeighbors neighbors;
+ BKE_subdiv_ccg_neighbor_coords_get(ss->subdiv_ccg, &coord, include_duplicates, &neighbors);
+
+ iter->size = 0;
+ iter->num_duplicates = neighbors.num_duplicates;
+ iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
+ iter->neighbors = iter->neighbors_fixed;
+
+ for (int i = 0; i < neighbors.size; i++) {
+ sculpt_vertex_neighbor_add(iter,
+ neighbors.coords[i].grid_index * key->grid_area +
+ neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x);
+ }
+
+ if (neighbors.coords != neighbors.coords_fixed) {
+ MEM_freeN(neighbors.coords);
+ }
+}
+
static void sculpt_vertex_neighbors_get(SculptSession *ss,
- int index,
+ const int index,
+ const bool include_duplicates,
SculptVertexNeighborIter *iter)
{
switch (BKE_pbvh_type(ss->pbvh)) {
@@ -317,17 +347,29 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
case PBVH_BMESH:
sculpt_vertex_neighbors_get_bmesh(ss, index, iter);
return;
- default:
- break;
+ case PBVH_GRIDS:
+ sculpt_vertex_neighbors_get_grids(ss, index, include_duplicates, iter);
+ return;
}
}
+/* Iterator over neighboring vertices. */
#define sculpt_vertex_neighbors_iter_begin(ss, v_index, neighbor_iterator) \
- sculpt_vertex_neighbors_get(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];
+/* 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) \
+ 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.size - neighbor_iterator.num_duplicates);
+
#define sculpt_vertex_neighbors_iter_end(neighbor_iterator) \
} \
if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \
@@ -336,17 +378,6 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss,
((void)0)
/* Utils */
-static void sculpt_vertex_mask_clamp(SculptSession *ss, int index, float min, float max)
-{
- float mask = sculpt_vertex_mask_get(ss, index);
- if (mask > max) {
- sculpt_vertex_mask_set(ss, index, max);
- }
- else if (mask < min) {
- sculpt_vertex_mask_set(ss, index, min);
- }
-}
-
static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
{
bool is_in_symmetry_area = true;
@@ -366,37 +397,46 @@ static bool check_vertex_pivot_symmetry(const float vco[3], const float pco[3],
return is_in_symmetry_area;
}
+typedef struct NearestVertexTLSData {
+ int nearest_vertex_index;
+ float nearest_vertex_distance_squared;
+} NearestVertexTLSData;
+
static void do_nearest_vertex_get_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
+ NearestVertexTLSData *nvtd = tls->userdata_chunk;
PBVHVertexIter vd;
- int node_nearest_vertex_index = -1;
- float node_nearest_vertex_distance_squared = FLT_MAX;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
float distance_squared = len_squared_v3v3(vd.co, data->nearest_vertex_search_co);
- if (distance_squared < node_nearest_vertex_distance_squared &&
+ if (distance_squared < nvtd->nearest_vertex_distance_squared &&
distance_squared < data->max_distance_squared) {
- node_nearest_vertex_index = vd.index;
- node_nearest_vertex_distance_squared = distance_squared;
+ nvtd->nearest_vertex_index = vd.index;
+ nvtd->nearest_vertex_distance_squared = distance_squared;
}
}
BKE_pbvh_vertex_iter_end;
+}
- BLI_mutex_lock(&data->mutex);
- if (data->nearest_vertex_index == -1) {
- data->nearest_vertex_index = node_nearest_vertex_index;
+static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ NearestVertexTLSData *join = chunk_join;
+ NearestVertexTLSData *nvtd = chunk;
+ if (join->nearest_vertex_index == -1) {
+ join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
- else if (node_nearest_vertex_distance_squared <
- len_squared_v3v3(data->nearest_vertex_search_co,
- sculpt_vertex_co_get(ss, data->nearest_vertex_index))) {
- data->nearest_vertex_index = node_nearest_vertex_index;
+ else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) {
+ join->nearest_vertex_index = nvtd->nearest_vertex_index;
+ join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared;
}
- BLI_mutex_unlock(&data->mutex);
}
static int sculpt_nearest_vertex_get(
@@ -422,19 +462,23 @@ static int sculpt_nearest_vertex_get(
.ob = ob,
.nodes = nodes,
.max_distance_squared = max_distance * max_distance,
- .nearest_vertex_index = -1,
};
copy_v3_v3(task_data.nearest_vertex_search_co, co);
+ NearestVertexTLSData nvtd;
+ nvtd.nearest_vertex_index = -1;
+ nvtd.nearest_vertex_distance_squared = FLT_MAX;
- BLI_mutex_init(&task_data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings);
- BLI_mutex_end(&task_data.mutex);
+ PBVHParallelSettings 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);
- return task_data.nearest_vertex_index;
+ MEM_SAFE_FREE(nodes);
+
+ return nvtd.nearest_vertex_index;
}
static bool is_symmetry_iteration_valid(char i, char symm)
@@ -443,7 +487,7 @@ static bool 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(float vertex[3],
+static bool sculpt_is_vertex_inside_brush_radius_symm(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -460,6 +504,85 @@ static bool sculpt_is_vertex_inside_brush_radius_symm(float vertex[3],
return false;
}
+/* Sculpt Flood Fill API
+ *
+ * Iterate over connected vertices, starting from one or more initial vertices. */
+
+typedef struct SculptFloodFill {
+ GSQueue *queue;
+ char *visited_vertices;
+} SculptFloodFill;
+
+static void sculpt_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
+{
+ int vertex_count = sculpt_vertex_count_get(ss);
+ sculpt_vertex_random_access_init(ss);
+
+ flood->queue = BLI_gsqueue_new(sizeof(int));
+ flood->visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+}
+
+static void sculpt_floodfill_add_initial(SculptFloodFill *flood, int index)
+{
+ BLI_gsqueue_push(flood->queue, &index);
+}
+
+static void sculpt_floodfill_add_active(
+ Sculpt *sd, Object *ob, SculptSession *ss, SculptFloodFill *flood, 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 (is_symmetry_iteration_valid(i, symm)) {
+ int v = -1;
+ if (i == 0) {
+ v = sculpt_active_vertex_get(ss);
+ }
+ else if (radius > 0.0f) {
+ float radius_squared = (radius == FLT_MAX) ? FLT_MAX : radius * radius;
+ float location[3];
+ flip_v3_v3(location, sculpt_active_vertex_co_get(ss), i);
+ v = sculpt_nearest_vertex_get(sd, ob, location, radius_squared, false);
+ }
+ if (v != -1) {
+ sculpt_floodfill_add_initial(flood, v);
+ }
+ }
+ }
+}
+
+static void sculpt_floodfill_execute(
+ SculptSession *ss,
+ SculptFloodFill *flood,
+ bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata),
+ void *userdata)
+{
+ while (!BLI_gsqueue_is_empty(flood->queue)) {
+ int from_v;
+ BLI_gsqueue_pop(flood->queue, &from_v);
+ SculptVertexNeighborIter ni;
+ sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni)
+ {
+ const int to_v = ni.index;
+ if (flood->visited_vertices[to_v] == 0) {
+ flood->visited_vertices[to_v] = 1;
+
+ if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) {
+ BLI_gsqueue_push(flood->queue, &to_v);
+ }
+ }
+ }
+ sculpt_vertex_neighbors_iter_end(ni);
+ }
+}
+
+static void sculpt_floodfill_free(SculptFloodFill *flood)
+{
+ MEM_SAFE_FREE(flood->visited_vertices);
+ BLI_gsqueue_free(flood->queue);
+ flood->queue = NULL;
+}
+
/** \name Tool Capabilities
*
* Avoid duplicate checks, internal logic only,
@@ -814,15 +937,11 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm &&
- totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings);
+ PBVHParallelSettings 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);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/*** BVH Tree ***/
@@ -1003,9 +1122,8 @@ bool sculpt_brush_test_cube(SculptBrushTest *test, const float co[3], float loca
local_co[1] = fabsf(local_co[1]);
local_co[2] = fabsf(local_co[2]);
+ const float p = 8.0f;
if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
- float p = 4.0f;
-
test->dist = ((powf(local_co[0], p) + powf(local_co[1], p) + powf(local_co[2], p)) /
powf(side, p));
@@ -1100,11 +1218,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test,
static bool sculpt_automasking_enabled(SculptSession *ss, const Brush *br)
{
- // REMOVE WITH PBVH_GRIDS
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return false;
- }
-
if (sculpt_stroke_is_dynamic_topology(ss, br)) {
return false;
}
@@ -1134,21 +1247,38 @@ static void sculpt_automasking_end(Object *ob)
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)) {
return true;
}
return false;
}
-typedef struct VertexTopologyIterator {
- int v;
- int it;
- float edge_factor;
-} VertexTopologyIterator;
+typedef struct AutomaskFloodFillData {
+ float *automask_factor;
+ float radius;
+ bool use_radius;
+ float location[3];
+ char symm;
+} AutomaskFloodFillData;
-static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *automask_factor)
+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);
@@ -1161,63 +1291,21 @@ static float *sculpt_topology_automasking_init(Sculpt *sd, Object *ob, float *au
return NULL;
}
- bool *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(bool),
- "visited vertices");
-
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "not vertices stack");
-
- VertexTopologyIterator mevit;
-
- /* Add active vertex and symmetric vertices to the stack. */
- float location[3];
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(
- sd, ob, location, ss->cache->radius * ss->cache->radius, false);
- }
- if (mevit.v != -1) {
- mevit.it = 1;
- BLI_stack_push(not_visited_vertices, &mevit);
- }
- }
- }
+ /* 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);
- copy_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
- bool use_radius = sculpt_automasking_is_constrained_by_radius(brush);
-
- /* Flood fill automask to connected vertices. Limited to vertices inside the brush radius if the
- * tool requires it */
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
- {
- if (!visited_vertices[(int)ni.index]) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- automask_factor[new_entry.v] = 1.0f;
- visited_vertices[(int)ni.index] = true;
- if (!use_radius ||
- sculpt_is_vertex_inside_brush_radius_symm(
- sculpt_vertex_co_get(ss, new_entry.v), location, ss->cache->radius, symm)) {
- BLI_stack_push(not_visited_vertices, &new_entry);
- }
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
-
- BLI_stack_free(not_visited_vertices);
-
- MEM_freeN(visited_vertices);
+ 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;
}
@@ -1324,21 +1412,26 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
* \note These are all _very_ similar, when changing one, check others.
* \{ */
+typedef struct AreaNormalCenterTLSData {
+ /* 0=towards view, 1=flipped */
+ float area_cos[2][3];
+ float area_nos[2][3];
+ int area_count[2];
+} AreaNormalCenterTLSData;
+
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
SculptSession *ss = data->ob->sculpt;
- float(*area_nos)[3] = data->area_nos;
- float(*area_cos)[3] = data->area_cos;
+ AreaNormalCenterTLSData *anctd = tls->userdata_chunk;
+ const bool use_area_nos = data->use_area_nos;
+ const bool use_area_cos = data->use_area_cos;
PBVHVertexIter vd;
SculptUndoNode *unode = NULL;
- float private_co[2][3] = {{0.0f}};
- float private_no[2][3] = {{0.0f}};
- int private_count[2] = {0};
bool use_original = false;
if (ss->cache && ss->cache->original) {
@@ -1353,7 +1446,10 @@ 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(test.radius_squared);
- test_radius *= data->brush->normal_radius_factor;
+ /* Layer brush produces artifacts with normal radius */
+ if (!(ss->cache && data->brush->sculpt_tool == SCULPT_TOOL_LAYER)) {
+ test_radius *= data->brush->normal_radius_factor;
+ }
test.radius_squared = test_radius * test_radius;
}
@@ -1384,13 +1480,13 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
normal_tri_v3(no, UNPACK3(co_tri));
flip_index = (dot_v3v3(ss->cache->view_normal, no) <= 0.0f);
- if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ if (use_area_cos) {
+ add_v3_v3(anctd->area_cos[flip_index], co);
}
- if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ if (use_area_nos) {
+ add_v3_v3(anctd->area_nos[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->area_count[flip_index] += 1;
}
}
}
@@ -1436,37 +1532,37 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
flip_index = (dot_v3v3(ss->cache ? ss->cache->view_normal : ss->cursor_view_normal, no) <=
0.0f);
- if (area_cos) {
- add_v3_v3(private_co[flip_index], co);
+ if (use_area_cos) {
+ add_v3_v3(anctd->area_cos[flip_index], co);
}
- if (area_nos) {
- add_v3_v3(private_no[flip_index], no);
+ if (use_area_nos) {
+ add_v3_v3(anctd->area_nos[flip_index], no);
}
- private_count[flip_index] += 1;
+ anctd->area_count[flip_index] += 1;
}
}
BKE_pbvh_vertex_iter_end;
}
+}
- BLI_mutex_lock(&data->mutex);
+static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ AreaNormalCenterTLSData *join = chunk_join;
+ AreaNormalCenterTLSData *anctd = chunk;
/* for flatten center */
- if (area_cos) {
- add_v3_v3(area_cos[0], private_co[0]);
- add_v3_v3(area_cos[1], private_co[1]);
- }
+ add_v3_v3(join->area_cos[0], anctd->area_cos[0]);
+ add_v3_v3(join->area_cos[1], anctd->area_cos[1]);
/* for area normal */
- if (area_nos) {
- add_v3_v3(area_nos[0], private_no[0]);
- add_v3_v3(area_nos[1], private_no[1]);
- }
+ add_v3_v3(join->area_nos[0], anctd->area_nos[0]);
+ add_v3_v3(join->area_nos[1], anctd->area_nos[1]);
/* weights */
- data->count[0] += private_count[0];
- data->count[1] += private_count[1];
-
- BLI_mutex_unlock(&data->mutex);
+ join->area_count[0] += anctd->area_count[0];
+ join->area_count[1] += anctd->area_count[1];
}
static void calc_area_center(
@@ -1477,11 +1573,6 @@ static void calc_area_center(
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
int n;
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since we share logic with vertex paint. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1490,23 +1581,22 @@ static void calc_area_center(
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = area_cos,
- .area_nos = NULL,
- .count = count,
+ .use_area_cos = true,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings 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);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
+ if (anctd.area_count[n] != 0) {
+ mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]);
break;
}
}
@@ -1519,7 +1609,7 @@ static void calc_area_normal(
Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3])
{
const Brush *brush = BKE_paint_brush(&sd->paint);
- bool use_threading = (sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT;
+ bool use_threading = (sd->flags & SCULPT_USE_OPENMP);
sculpt_pbvh_calc_area_normal(brush, ob, nodes, totnode, use_threading, r_area_no);
}
@@ -1534,11 +1624,6 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush,
SculptSession *ss = ob->sculpt;
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
- /* 0=towards view, 1=flipped */
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1547,23 +1632,22 @@ bool sculpt_pbvh_calc_area_normal(const Brush *brush,
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = NULL,
- .area_nos = area_nos,
- .count = count,
+ .use_area_nos = true,
.any_vertex_sampled = false,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = use_threading;
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings 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);
/* for area normal */
- for (int i = 0; i < ARRAY_SIZE(area_nos); i++) {
- if (normalize_v3_v3(r_area_no, area_nos[i]) != 0.0f) {
+ for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) {
+ if (normalize_v3_v3(r_area_no, anctd.area_nos[i]) != 0.0f) {
break;
}
}
@@ -1581,12 +1665,6 @@ static void calc_area_normal_and_center(
const bool has_bm_orco = ss->bm && sculpt_stroke_is_dynamic_topology(ss, brush);
int n;
- /* 0=towards view, 1=flipped */
- float area_cos[2][3] = {{0.0f}};
- float area_nos[2][3] = {{0.0f}};
-
- int count[2] = {0};
-
/* Intentionally set 'sd' to NULL since this is used for vertex paint too. */
SculptThreadedTaskData data = {
.sd = NULL,
@@ -1595,23 +1673,23 @@ static void calc_area_normal_and_center(
.nodes = nodes,
.totnode = totnode,
.has_bm_orco = has_bm_orco,
- .area_cos = area_cos,
- .area_nos = area_nos,
- .count = count,
+ .use_area_cos = true,
+ .use_area_nos = true,
};
- BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings);
+ AreaNormalCenterTLSData anctd = {{{0}}};
- BLI_mutex_end(&data.mutex);
+ PBVHParallelSettings 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);
/* for flatten center */
- for (n = 0; n < ARRAY_SIZE(area_cos); n++) {
- if (count[n] != 0) {
- mul_v3_v3fl(r_area_co, area_cos[n], 1.0f / count[n]);
+ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) {
+ if (anctd.area_count[n] != 0) {
+ mul_v3_v3fl(r_area_co, anctd.area_cos[n], 1.0f / anctd.area_count[n]);
break;
}
}
@@ -1620,8 +1698,8 @@ static void calc_area_normal_and_center(
}
/* for area normal */
- for (n = 0; n < ARRAY_SIZE(area_nos); n++) {
- if (normalize_v3_v3(r_area_no, area_nos[n]) != 0.0f) {
+ for (n = 0; n < ARRAY_SIZE(anctd.area_nos); n++) {
+ if (normalize_v3_v3(r_area_no, anctd.area_nos[n]) != 0.0f) {
break;
}
}
@@ -1655,11 +1733,13 @@ static float brush_strength(const Sculpt *sd,
switch (brush->sculpt_tool) {
case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_CLAY_STRIPS:
case SCULPT_TOOL_DRAW:
case SCULPT_TOOL_DRAW_SHARP:
case SCULPT_TOOL_LAYER:
return alpha * flip * pressure * overlap * feather;
+ case SCULPT_TOOL_CLAY_STRIPS:
+ /* Clay Strips needs extra strength to compensate for its default normal radius */
+ return alpha * flip * pressure * overlap * feather * 1.3f;
case SCULPT_TOOL_MASK:
overlap = (1 + overlap) / 2;
@@ -1831,6 +1911,12 @@ bool sculpt_search_sphere_cb(PBVHNode *node, void *data_v)
float t[3], bb_min[3], bb_max[3];
int i;
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1861,6 +1947,12 @@ bool sculpt_search_circle_cb(PBVHNode *node, void *data_v)
SculptSearchCircleData *data = data_v;
float bb_min[3], bb_max[3];
+ if (data->ignore_fully_masked) {
+ if (BKE_pbvh_node_fully_masked_get(node)) {
+ return false;
+ }
+ }
+
if (data->original) {
BKE_pbvh_node_get_original_BB(node, bb_min, bb_max);
}
@@ -1894,6 +1986,25 @@ static void sculpt_clip(Sculpt *sd, SculptSession *ss, float co[3], const float
}
}
+static PBVHNode **sculpt_pbvh_gather_cursor_update(Object *ob,
+ Sculpt *sd,
+ bool use_original,
+ int *r_totnode)
+{
+ SculptSession *ss = ob->sculpt;
+ PBVHNode **nodes = NULL;
+ SculptSearchSphereData data = {
+ .ss = ss,
+ .sd = sd,
+ .radius_squared = ss->cursor_radius,
+ .original = use_original,
+ .ignore_fully_masked = false,
+ .center = NULL,
+ };
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
+ return nodes;
+}
+
static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
Sculpt *sd,
const Brush *brush,
@@ -1910,8 +2021,9 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
- .radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
+ .radius_squared = SQUARE(ss->cache->radius * radius_scale),
.original = use_original,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
.center = NULL,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, r_totnode);
@@ -1926,6 +2038,7 @@ static PBVHNode **sculpt_pbvh_gather_generic(Object *ob,
.radius_squared = ss->cache ? SQUARE(ss->cache->radius * radius_scale) : ss->cursor_radius,
.original = use_original,
.dist_ray_to_aabb_precalc = &dist_ray_to_aabb_precalc,
+ .ignore_fully_masked = brush->sculpt_tool != SCULPT_TOOL_MASK,
};
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_circle_cb, &data, &nodes, r_totnode);
}
@@ -1969,9 +2082,15 @@ static void update_sculpt_normal(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
{
const Brush *brush = BKE_paint_brush(&sd->paint);
StrokeCache *cache = ob->sculpt->cache;
+ /* Grab brush does not update the sculpt normal during a stroke */
+ const bool update_normal = !(brush->flag & BRUSH_ORIGINAL_NORMAL) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_GRAB) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) &&
+ !(brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK &&
+ cache->normal_weight > 0.0f);
if (cache->mirror_symmetry_pass == 0 && cache->radial_symmetry_pass == 0 &&
- (cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (cache->first_time || update_normal)) {
calc_sculpt_normal(sd, ob, nodes, totnode, cache->sculpt_normal);
if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
project_plane_v3_v3v3(cache->sculpt_normal, cache->sculpt_normal, cache->view_normal);
@@ -2160,92 +2279,51 @@ static void bmesh_neighbor_average(float avg[3], BMVert *v)
copy_v3_v3(avg, v->co);
}
-/* For bmesh: average only the four most aligned (parallel and perpendicular) edges
- * relative to a direction. Naturally converges to a quad-like tessellation. */
+/* 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)
{
- /* 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 < 2) {
- copy_v3_v3(avg, v->co);
- return;
- }
-
- /* Project the direction to the vertex normal and create an additional
- * parallel vector. */
- float dir_a[3], dir_b[3];
- cross_v3_v3v3(dir_a, direction, v->no);
- cross_v3_v3v3(dir_b, dir_a, v->no);
-
- /* The four vectors which will be used for smoothing.
- * Occasionally less than 4 verts match the requirements in that case
- * use 'v' as fallback. */
- BMVert *pos_a = v;
- BMVert *neg_a = v;
- BMVert *pos_b = v;
- BMVert *neg_b = v;
-
- float pos_score_a = 0.0f;
- float neg_score_a = 0.0f;
- float pos_score_b = 0.0f;
- float neg_score_b = 0.0f;
-
- BMIter liter;
- BMLoop *l;
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
- BMVert *adj_v[2] = {l->prev->v, l->next->v};
-
- for (int i = 0; i < ARRAY_SIZE(adj_v); i++) {
- BMVert *v_other = adj_v[i];
-
- if (vfcount != 2 || BM_vert_face_count_at_most(v_other, 2) <= 2) {
- float vec[3];
- sub_v3_v3v3(vec, v_other->co, v->co);
- normalize_v3(vec);
+ float avg_co[3] = {0, 0, 0};
+ float tot_co = 0;
- /* The score is a measure of how orthogonal the edge is. */
- float score = dot_v3v3(vec, dir_a);
+ BMIter eiter;
+ BMEdge *e;
- if (score >= pos_score_a) {
- pos_a = v_other;
- pos_score_a = score;
- }
- else if (score < neg_score_a) {
- neg_a = v_other;
- neg_score_a = score;
- }
- /* The same scoring but for the perpendicular direction. */
- score = dot_v3v3(vec, dir_b);
-
- if (score >= pos_score_b) {
- pos_b = v_other;
- pos_score_b = score;
- }
- else if (score < neg_score_b) {
- neg_b = v_other;
- neg_score_b = score;
- }
- }
+ 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;
}
- /* Average everything together. */
- zero_v3(avg);
- add_v3_v3(avg, pos_a->co);
- add_v3_v3(avg, neg_a->co);
- add_v3_v3(avg, pos_b->co);
- add_v3_v3(avg, neg_b->co);
- mul_v3_fl(avg, 0.25f);
+ /* In case vert has no Edge s */
+ if (tot_co > 0) {
+ 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);
+ /* 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 */
@@ -2277,6 +2355,48 @@ static float bmesh_neighbor_average_mask(BMVert *v, const int cd_vert_mask_offse
}
}
+static void grids_neighbor_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;
@@ -2442,6 +2562,7 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata,
mul_v3_v3fl(
tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction));
sub_v3_v3(direction, tmp);
+ normalize_v3(direction);
/* Cancel if there's no grab data. */
if (is_zero_v3(direction)) {
@@ -2502,7 +2623,6 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
float bstrength = data->strength;
CCGElem **griddata, *gddata;
- CCGKey key;
float(*tmpgrid_co)[3] = NULL;
float tmprow_co[2][3];
@@ -2521,7 +2641,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata,
BKE_pbvh_node_get_grids(
ss->pbvh, data->nodes[n], &grid_indices, &totgrid, NULL, &gridsize, &griddata);
- BKE_pbvh_get_grid_key(ss->pbvh, &key);
+ CCGKey key = *BKE_pbvh_get_grid_key(ss->pbvh);
grid_hidden = BKE_pbvh_grid_hidden(ss->pbvh);
@@ -2681,9 +2801,8 @@ static void smooth(Sculpt *sd,
.strength = strength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
switch (type) {
case PBVH_GRIDS: {
@@ -2700,16 +2819,16 @@ static void smooth(Sculpt *sd,
settings.userdata_chunk = data_chunk;
settings.userdata_chunk_size = size;
- BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings);
MEM_freeN(data_chunk);
break;
}
case PBVH_FACES:
- BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings);
+ BKE_pbvh_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);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings);
break;
}
@@ -2741,11 +2860,10 @@ static void bmesh_topology_rake(
.nodes = nodes,
.strength = factor,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
+ BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings);
}
}
@@ -2799,10 +2917,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
@@ -2887,10 +3004,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings);
+ 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_sharp_brush_task_cb_ex(void *__restrict userdata,
@@ -2964,10 +3080,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
/**
@@ -3081,10 +3196,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.flippedbstrength = flippedbstrength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_pinch_brush_task_cb_ex(void *__restrict userdata,
@@ -3144,10 +3258,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_grab_brush_task_cb_ex(void *__restrict userdata,
@@ -3217,10 +3330,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
/* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity
@@ -3459,6 +3571,10 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
+ if (ss->cache->normal_weight > 0.0f) {
+ sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta);
+ }
+
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
@@ -3467,10 +3583,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_pose_brush_task_cb_ex(void *__restrict userdata,
@@ -3522,10 +3637,6 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
float pose_initial_co[3];
float transform_rot[4][4], transform_trans[4][4], transform_trans_inv[4][4];
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return;
- }
-
copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry);
copy_v3_v3(pose_origin, ss->cache->pose_origin);
@@ -3561,39 +3672,115 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.transform_trans_inv = transform_trans_inv,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
-static void pose_brush_init_task_cb_ex(void *__restrict userdata,
- const int n,
- const TaskParallelTLS *__restrict UNUSED(tls))
+typedef struct PoseGrowFactorTLSData {
+ float pos_avg[3];
+ int pos_count;
+} PoseGrowFactorTLSData;
+
+static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict tls)
{
SculptThreadedTaskData *data = userdata;
+ PoseGrowFactorTLSData *gftd = tls->userdata_chunk;
SculptSession *ss = data->ob->sculpt;
+ const char symm = data->sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ const float *active_co = sculpt_active_vertex_co_get(ss);
PBVHVertexIter vd;
BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
{
SculptVertexNeighborIter ni;
- float avg = 0;
- int total = 0;
+ float max = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- avg += ss->cache->pose_factor[ni.index];
- total++;
+ float vmask_f = data->prev_mask[ni.index];
+ if (vmask_f > max) {
+ max = vmask_f;
+ }
}
sculpt_vertex_neighbors_iter_end(ni);
-
- if (total > 0) {
- ss->cache->pose_factor[vd.index] = avg / (float)total;
+ if (max != data->prev_mask[vd.index]) {
+ data->pose_factor[vd.index] = max;
+ if (check_vertex_pivot_symmetry(vd.co, active_co, symm)) {
+ add_v3_v3(gftd->pos_avg, vd.co);
+ gftd->pos_count++;
+ }
}
}
+
BKE_pbvh_vertex_iter_end;
}
-static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
+static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata),
+ void *__restrict chunk_join,
+ void *__restrict chunk)
+{
+ PoseGrowFactorTLSData *join = chunk_join;
+ PoseGrowFactorTLSData *gftd = chunk;
+ add_v3_v3(join->pos_avg, gftd->pos_avg);
+ join->pos_count += gftd->pos_count;
+}
+
+/* Grow the factor until its boundary is near to the offset pose origin */
+static void sculpt_pose_grow_pose_factor(
+ Sculpt *sd, Object *ob, SculptSession *ss, float pose_origin[3], float *pose_factor)
+{
+ PBVHNode **nodes;
+ PBVH *pbvh = ob->sculpt->pbvh;
+ int totnode;
+
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = nodes,
+ .totnode = totnode,
+ .pose_factor = pose_factor,
+ };
+ PBVHParallelSettings settings;
+ PoseGrowFactorTLSData gftd;
+ gftd.pos_count = 0;
+ zero_v3(gftd.pos_avg);
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ settings.func_reduce = pose_brush_grow_factor_reduce;
+ settings.userdata_chunk = &gftd;
+ settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData);
+
+ bool grow_next_iteration = true;
+ float prev_len = FLT_MAX;
+ data.prev_mask = MEM_mallocN(sculpt_vertex_count_get(ss) * sizeof(float), "prev mask");
+ while (grow_next_iteration) {
+ 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);
+ if (gftd.pos_count != 0) {
+ mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count);
+ float len = len_v3v3(gftd.pos_avg, pose_origin);
+ if (len < prev_len) {
+ prev_len = len;
+ grow_next_iteration = true;
+ }
+ else {
+ grow_next_iteration = false;
+ memcpy(pose_factor, data.prev_mask, sculpt_vertex_count_get(ss) * sizeof(float));
+ }
+ }
+ else {
+ grow_next_iteration = false;
+ }
+ }
+ MEM_freeN(data.prev_mask);
+
+ MEM_SAFE_FREE(nodes);
+}
+
+static bool sculpt_pose_brush_is_vertex_inside_brush_radius(const float vertex[3],
const float br_co[3],
float radius,
char symm)
@@ -3610,85 +3797,123 @@ static bool sculpt_pose_brush_is_vertex_inside_brush_radius(float vertex[3],
return false;
}
-static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br)
+/* Calculate the pose origin and (Optionaly the pose factor) that is used when using the pose brush
+ *
+ * r_pose_origin must be a valid pointer. the r_pose_factor is optional. When set to NULL it won't
+ * be calculated. */
+typedef struct PoseFloodFillData {
+ float pose_initial_co[3];
+ float radius;
+ int symm;
+
+ float *pose_factor;
+ float pose_origin[3];
+ int tot_co;
+} PoseFloodFillData;
+
+static bool pose_floodfill_cb(
+ SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata)
{
- sculpt_vertex_random_access_init(ss);
+ PoseFloodFillData *data = userdata;
- ss->cache->pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
+ if (data->pose_factor) {
+ data->pose_factor[to_v] = 1.0f;
+ }
- copy_v3_v3(ss->cache->pose_initial_co, ss->cache->location);
+ const float *co = sculpt_vertex_co_get(ss, to_v);
+ if (sculpt_pose_brush_is_vertex_inside_brush_radius(
+ co, data->pose_initial_co, data->radius, data->symm)) {
+ return true;
+ }
+ else if (check_vertex_pivot_symmetry(co, data->pose_initial_co, data->symm)) {
+ if (!is_duplicate) {
+ add_v3_v3(data->pose_origin, co);
+ data->tot_co++;
+ }
+ }
- char *visited_vertices = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(char),
- "Visited vertices");
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "not visited vertices stack");
+ return false;
+}
- float tot_co = 0;
- zero_v3(ss->cache->pose_origin);
+void sculpt_pose_calc_pose_data(Sculpt *sd,
+ Object *ob,
+ SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor)
+{
+ sculpt_vertex_random_access_init(ss);
- VertexTopologyIterator mevit;
+ /* Calculate the pose rotation point based on the boundaries of the brush factor. */
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, (r_pose_factor) ? radius : 0.0f);
- /* Add active vertex and symmetric vertices to the stack. */
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- float location[3];
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), (char)i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(
- sd, ob, location, ss->cache->radius * ss->cache->radius, false);
- }
- if (mevit.v != -1) {
- mevit.it = 1;
- BLI_stack_push(not_visited_vertices, &mevit);
- }
- }
+ PoseFloodFillData fdata = {
+ .radius = radius,
+ .symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL,
+ .pose_factor = r_pose_factor,
+ .tot_co = 0,
+ };
+ zero_v3(fdata.pose_origin);
+ copy_v3_v3(fdata.pose_initial_co, initial_location);
+ sculpt_floodfill_execute(ss, &flood, pose_floodfill_cb, &fdata);
+ sculpt_floodfill_free(&flood);
+
+ if (fdata.tot_co > 0) {
+ mul_v3_fl(fdata.pose_origin, 1.0f / (float)fdata.tot_co);
}
- /* Flood fill the internal pose brush factor. Calculate the pose rotation point based on the
- * boundaries of the brush factor*/
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
+ /* Offset the pose origin */
+ float pose_d[3];
+ sub_v3_v3v3(pose_d, fdata.pose_origin, fdata.pose_initial_co);
+ normalize_v3(pose_d);
+ madd_v3_v3fl(fdata.pose_origin, pose_d, radius * pose_offset);
+ copy_v3_v3(r_pose_origin, fdata.pose_origin);
+
+ if (pose_offset != 0.0f && r_pose_factor) {
+ sculpt_pose_grow_pose_factor(sd, ob, ss, fdata.pose_origin, r_pose_factor);
+ }
+}
+
+static void pose_brush_init_task_cb_ex(void *__restrict userdata,
+ const int n,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHVertexIter vd;
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE)
+ {
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
+ float avg = 0;
+ int total = 0;
+ sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
{
- if (visited_vertices[(int)ni.index] == 0) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->cache->pose_factor[new_entry.v] = 1.0f;
- visited_vertices[(int)ni.index] = 1;
- if (sculpt_pose_brush_is_vertex_inside_brush_radius(sculpt_vertex_co_get(ss, new_entry.v),
- ss->cache->pose_initial_co,
- ss->cache->radius,
- symm)) {
- BLI_stack_push(not_visited_vertices, &new_entry);
- }
- else {
- if (check_vertex_pivot_symmetry(
- sculpt_vertex_co_get(ss, new_entry.v), ss->cache->pose_initial_co, symm)) {
- tot_co++;
- add_v3_v3(ss->cache->pose_origin, sculpt_vertex_co_get(ss, new_entry.v));
- }
- }
- }
+ avg += ss->cache->pose_factor[ni.index];
+ total++;
}
sculpt_vertex_neighbors_iter_end(ni);
- }
- BLI_stack_free(not_visited_vertices);
+ if (total > 0) {
+ ss->cache->pose_factor[vd.index] = avg / (float)total;
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
- MEM_freeN(visited_vertices);
+static void sculpt_pose_brush_init(
+ Sculpt *sd, Object *ob, SculptSession *ss, Brush *br, float initial_location[3], float radius)
+{
+ float *pose_factor = MEM_callocN(sculpt_vertex_count_get(ss) * sizeof(float), "Pose factor");
- if (tot_co > 0) {
- mul_v3_fl(ss->cache->pose_origin, 1.0f / (float)tot_co);
- }
+ sculpt_pose_calc_pose_data(
+ sd, ob, ss, initial_location, radius, br->pose_offset, ss->cache->pose_origin, pose_factor);
- /* Smooth the pose brush factor for cleaner deformation */
+ copy_v3_v3(ss->cache->pose_initial_co, initial_location);
+ ss->cache->pose_factor = pose_factor;
PBVHNode **nodes;
PBVH *pbvh = ob->sculpt->pbvh;
@@ -3703,12 +3928,14 @@ static void sculpt_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Br
.nodes = nodes,
};
+ /* Smooth the pose brush factor for cleaner deformation */
for (int i = 0; i < 4; i++) {
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
+
+ MEM_SAFE_FREE(nodes);
}
static void do_nudge_brush_task_cb_ex(void *__restrict userdata,
@@ -3773,10 +4000,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata,
@@ -3895,10 +4121,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
.grab_delta = grab_delta,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_thumb_brush_task_cb_ex(void *__restrict userdata,
@@ -3968,10 +4193,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
.cono = cono,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_rotate_brush_task_cb_ex(void *__restrict userdata,
@@ -4042,10 +4266,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.angle = angle,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_layer_brush_task_cb_ex(void *__restrict userdata,
@@ -4140,10 +4363,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
};
BLI_mutex_init(&data.mutex);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
@@ -4209,10 +4431,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void calc_sculpt_plane(
@@ -4223,7 +4444,8 @@ static void calc_sculpt_plane(
if (ss->cache->mirror_symmetry_pass == 0 && ss->cache->radial_symmetry_pass == 0 &&
ss->cache->tile_pass == 0 &&
- (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
+ (ss->cache->first_time || !(brush->flag & BRUSH_ORIGINAL_PLANE) ||
+ !(brush->flag & BRUSH_ORIGINAL_NORMAL))) {
switch (brush->sculpt_plane) {
case SCULPT_DISP_DIR_VIEW:
copy_v3_v3(r_area_no, ss->cache->true_view_normal);
@@ -4260,10 +4482,20 @@ static void calc_sculpt_plane(
}
/* for area normal */
- copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_NORMAL)) {
+ copy_v3_v3(r_area_no, ss->cache->sculpt_normal);
+ }
+ else {
+ copy_v3_v3(ss->cache->sculpt_normal, r_area_no);
+ }
/* for flatten center */
- copy_v3_v3(ss->cache->last_center, r_area_co);
+ if ((!ss->cache->first_time) && (brush->flag & BRUSH_ORIGINAL_PLANE)) {
+ copy_v3_v3(r_area_co, ss->cache->last_center);
+ }
+ else {
+ copy_v3_v3(ss->cache->last_center, r_area_co);
+ }
}
else {
/* for area normal */
@@ -4408,10 +4640,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_clay_brush_task_cb_ex(void *__restrict userdata,
@@ -4507,10 +4738,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata,
@@ -4638,10 +4868,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
.mat = mat,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_fill_brush_task_cb_ex(void *__restrict userdata,
@@ -4732,10 +4961,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_scrape_brush_task_cb_ex(void *__restrict userdata,
@@ -4825,10 +5053,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
.area_co = area_co,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
static void do_gravity_task_cb_ex(void *__restrict userdata,
@@ -4895,10 +5122,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
.offset = offset,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings);
+ PBVHParallelSettings 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);
}
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3])
@@ -4999,7 +5225,7 @@ static void sculpt_topology_update(Sculpt *sd,
(brush->falloff_shape != PAINT_FALLOFF_SHAPE_SPHERE));
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -5017,7 +5243,12 @@ static void do_brush_action_task_cb(void *__restrict userdata,
data->nodes[n],
data->brush->sculpt_tool == SCULPT_TOOL_MASK ? SCULPT_UNDO_MASK :
SCULPT_UNDO_COORDS);
- BKE_pbvh_node_mark_update(data->nodes[n]);
+ if (data->brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ BKE_pbvh_node_mark_update_mask(data->nodes[n]);
+ }
+ else {
+ BKE_pbvh_node_mark_update(data->nodes[n]);
+ }
}
static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSettings *ups)
@@ -5030,18 +5261,27 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
/* These brushes need to update all nodes as they are not constrained by the brush radius */
if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) {
+ BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
+ }
+ else if (brush->sculpt_tool == SCULPT_TOOL_POSE) {
+ float final_radius = ss->cache->radius * (1 + brush->pose_offset);
SculptSearchSphereData data = {
.ss = ss,
.sd = sd,
- .radius_squared = FLT_MAX,
+ .radius_squared = final_radius * final_radius,
.original = true,
};
- BKE_pbvh_search_gather(ss->pbvh, NULL, &data, &nodes, &totnode);
+ BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
}
else {
const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true :
ss->cache->original;
- const float radius_scale = 1.0f;
+ float radius_scale = 1.0f;
+ /* With these options enabled not all required nodes are inside the original brush radius, so
+ * the brush can produce artifacts in some situations */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW && brush->flag & BRUSH_ORIGINAL_NORMAL) {
+ radius_scale = 2.0f;
+ }
nodes = sculpt_pbvh_gather_generic(ob, sd, brush, use_original, radius_scale, &totnode);
}
@@ -5056,10 +5296,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings);
+ PBVHParallelSettings 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);
if (sculpt_brush_needs_normal(ss, brush)) {
update_sculpt_normal(sd, ob, nodes, totnode);
@@ -5077,9 +5316,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
if (brush->sculpt_tool == SCULPT_TOOL_POSE && ss->cache->first_time &&
ss->cache->mirror_symmetry_pass == 0) {
- if (BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
- sculpt_pose_brush_init(sd, ob, ss, brush);
- }
+ sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius);
}
/* Apply one type of brush action */
@@ -5168,7 +5405,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
do_gravity(sd, ob, nodes, totnode, sd->gravity_factor);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* update average stroke position */
copy_v3_v3(location, ss->cache->true_location);
@@ -5196,7 +5433,7 @@ static void sculpt_flush_pbvhvert_deform(Object *ob, PBVHVertexIter *vd)
copy_v3_v3(ss->deform_cos[index], vd->co);
copy_v3_v3(ss->orig_cos[index], newco);
- if (!ss->kb) {
+ if (!ss->shapekey_active) {
copy_v3_v3(me->mvert[index].co, newco);
}
}
@@ -5252,7 +5489,7 @@ static void sculpt_combine_proxies_task_cb(void *__restrict userdata,
sculpt_clip(sd, ss, vd.co, val);
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
sculpt_flush_pbvhvert_deform(ob, &vd);
}
}
@@ -5279,15 +5516,12 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
.nodes = nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings);
+ PBVHParallelSettings 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);
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
}
/* copy the modified vertices from bvh to the active key */
@@ -5306,7 +5540,7 @@ static void sculpt_update_keyblock(Object *ob)
}
if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
if (vertCos != ss->orig_cos) {
MEM_freeN(vertCos);
@@ -5352,7 +5586,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
PBVHNode **nodes;
float(*vertCos)[3] = NULL;
- if (ss->kb) {
+ if (ss->shapekey_active) {
vertCos = MEM_mallocN(sizeof(*vertCos) * me->totvert, "flushStrokeDeofrm keyVerts");
/* mesh could have isolated verts which wouldn't be in BVH,
@@ -5372,24 +5606,23 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use
.vertCos = vertCos,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings);
+ PBVHParallelSettings 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);
if (vertCos) {
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
MEM_freeN(vertCos);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
/* Modifiers could depend on mesh normals, so we should update them/
* Note, then if sculpting happens on locked key, normals should be re-calculated
* after applying coords from keyblock on base mesh */
BKE_mesh_calc_normals(me);
}
- else if (ss->kb) {
+ else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
}
}
@@ -5676,6 +5909,9 @@ void sculpt_cache_free(StrokeCache *cache)
if (cache->dial) {
MEM_freeN(cache->dial);
}
+ if (cache->pose_factor) {
+ MEM_freeN(cache->pose_factor);
+ }
MEM_freeN(cache);
}
@@ -5869,12 +6105,21 @@ static void sculpt_update_cache_invariants(
/* Make copies of the mesh vertex locations and normals for some tools */
if (brush->flag & BRUSH_ANCHORED) {
- cache->original = 1;
+ cache->original = true;
+ }
+
+ /* Draw sharp does not need the original coordinates to produce the accumulate effect, so it
+ * should work the opposite way. */
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = true;
}
if (SCULPT_TOOL_HAS_ACCUMULATE(brush->sculpt_tool)) {
if (!(brush->flag & BRUSH_ACCUMULATE)) {
- cache->original = 1;
+ cache->original = true;
+ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_SHARP) {
+ cache->original = false;
+ }
}
}
@@ -5911,8 +6156,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
if (cache->first_time) {
if (tool == SCULPT_TOOL_GRAB && brush->flag & BRUSH_GRAB_ACTIVE_VERTEX) {
- copy_v3_v3(cache->orig_grab_location,
- sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+ copy_v3_v3(cache->orig_grab_location, sculpt_active_vertex_co_get(ss));
}
else {
copy_v3_v3(cache->orig_grab_location, cache->true_location);
@@ -6125,9 +6369,9 @@ 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_conectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
+static bool sculpt_needs_connectivity_info(const Brush *brush, SculptSession *ss, int stroke_mode)
{
- if (ss && sculpt_automasking_enabled(ss, brush)) {
+ if (ss && ss->pbvh && sculpt_automasking_enabled(ss, brush)) {
return true;
}
return ((stroke_mode == BRUSH_STROKE_SMOOTH) || (ss && ss->cache && ss->cache->alt_smooth) ||
@@ -6141,8 +6385,9 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B
SculptSession *ss = ob->sculpt;
View3D *v3d = CTX_wm_view3d(C);
- bool need_pmap = sculpt_needs_conectivity_info(brush, ss, 0);
- if (ss->kb || ss->modifiers_active || (!BKE_sculptsession_use_pbvh_draw(ob, v3d) && need_pmap)) {
+ bool need_pmap = sculpt_needs_connectivity_info(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);
BKE_sculpt_update_object_for_edit(depsgraph, ob, need_pmap, false);
}
@@ -6272,6 +6517,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
const float mouse[2],
bool use_sampled_normal)
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Scene *scene = CTX_data_scene(C);
Sculpt *sd = scene->toolsettings->sculpt;
Object *ob;
@@ -6284,15 +6530,15 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
int totnode;
bool original = false, hit = false;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
if (!ss->pbvh) {
- copy_v3_fl(out->location, 0.0f);
- copy_v3_fl(out->normal, 0.0f);
- copy_v3_fl(out->active_vertex_co, 0.0f);
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
return false;
}
@@ -6314,16 +6560,16 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
/* Cursor is not over the mesh, return default values */
if (!srd.hit) {
- copy_v3_fl(out->location, 0.0f);
- copy_v3_fl(out->normal, 0.0f);
- copy_v3_fl(out->active_vertex_co, 0.0f);
+ zero_v3(out->location);
+ zero_v3(out->normal);
+ zero_v3(out->active_vertex_co);
return false;
}
/* Update the active vertex of the SculptSession */
ss->active_vertex_index = srd.active_vertex_index;
+ copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss));
- copy_v3_v3(out->active_vertex_co, sculpt_vertex_co_get(ss, srd.active_vertex_index));
copy_v3_v3(out->location, ray_normal);
mul_v3_fl(out->location, srd.depth);
add_v3_v3(out->location, ray_start);
@@ -6335,7 +6581,6 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
}
/* Sampled normal calculation */
- const float radius_scale = 1.0f;
float radius;
/* Update cursor data in SculptSession */
@@ -6357,11 +6602,11 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
}
ss->cursor_radius = radius;
- PBVHNode **nodes = sculpt_pbvh_gather_generic(ob, sd, brush, original, radius_scale, &totnode);
+ PBVHNode **nodes = sculpt_pbvh_gather_cursor_update(ob, sd, original, &totnode);
/* In case there are no nodes under the cursor, return the face normal */
if (!totnode) {
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
copy_v3_v3(out->normal, srd.face_normal);
return true;
}
@@ -6374,7 +6619,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
/* Use face normal when there are no vertices to sample inside the cursor radius */
copy_v3_v3(out->normal, srd.face_normal);
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
return true;
}
@@ -6384,6 +6629,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
*/
bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
{
+ Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob;
SculptSession *ss;
StrokeCache *cache;
@@ -6391,13 +6637,13 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
bool original;
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ob = vc.obact;
ss = ob->sculpt;
cache = ss->cache;
- original = (cache) ? cache->original : 0;
+ original = (cache) ? cache->original : false;
const Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
@@ -6453,10 +6699,6 @@ bool sculpt_stroke_get_location(bContext *C, float out[3], const float mouse[2])
}
}
- if (cache && hit) {
- copy_v3_v3(cache->true_location, out);
- }
-
return hit;
}
@@ -6496,7 +6738,7 @@ 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_conectivity_info(brush, ss, mode);
+ is_smooth = sculpt_needs_connectivity_info(brush, ss, mode);
BKE_sculpt_update_object_for_edit(depsgraph, ob, is_smooth, need_mask);
}
@@ -6526,7 +6768,7 @@ void sculpt_update_object_bounding_box(Object *ob)
}
}
-static void sculpt_flush_update_step(bContext *C)
+static void sculpt_flush_update_step(bContext *C, SculptUpdateType update_flags)
{
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
Object *ob = CTX_data_active_object(C);
@@ -6534,6 +6776,12 @@ static void sculpt_flush_update_step(bContext *C)
ARegion *ar = CTX_wm_region(C);
MultiresModifierData *mmd = ss->multires;
View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ if (rv3d) {
+ /* Mark for faster 3D viewport redraws. */
+ rv3d->rflag |= RV3D_PAINTING;
+ }
if (mmd != NULL) {
multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED);
@@ -6554,11 +6802,13 @@ static void sculpt_flush_update_step(bContext *C)
* only the part of the 3D viewport where changes happened. */
rcti r;
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
- /* Update the object's bounding box too so that the object
- * doesn't get incorrectly clipped during drawing in
- * draw_mesh_object(). [#33790] */
- sculpt_update_object_bounding_box(ob);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB);
+ /* Update the object's bounding box too so that the object
+ * doesn't get incorrectly clipped during drawing in
+ * draw_mesh_object(). [#33790] */
+ sculpt_update_object_bounding_box(ob);
+ }
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
if (ss->cache) {
@@ -6578,16 +6828,21 @@ static void sculpt_flush_update_step(bContext *C)
}
}
-static void sculpt_flush_update_done(const bContext *C, Object *ob)
+static 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. */
wmWindowManager *wm = CTX_wm_manager(C);
View3D *current_v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
SculptSession *ss = ob->sculpt;
Mesh *mesh = ob->data;
bool need_tag = (mesh->id.us > 1); /* Always needed for linked duplicates. */
+ if (rv3d) {
+ rv3d->rflag &= ~RV3D_PAINTING;
+ }
+
for (wmWindow *win = wm->windows.first; win; win = win->next) {
bScreen *screen = WM_window_get_active_screen(win);
for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
@@ -6597,11 +6852,26 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
if (v3d != current_v3d) {
need_tag |= !BKE_sculptsession_use_pbvh_draw(ob, v3d);
}
+
+ /* 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 *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ED_region_tag_redraw(ar);
+ }
+ }
}
}
}
- BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ if (update_flags & SCULPT_UPDATE_COORDS) {
+ BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateOriginalBB);
+ }
+
+ if (update_flags & SCULPT_UPDATE_MASK) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BKE_pbvh_bmesh_after_stroke(ss->pbvh);
@@ -6610,7 +6880,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob)
/* optimization: if there is locked key and active modifiers present in */
/* the stack, keyblock is updating at each step. otherwise we could update */
/* keyblock only when stroke is finished */
- if (ss->kb && !ss->modifiers_active) {
+ if (ss->shapekey_active && !ss->deform_modifiers_active) {
sculpt_update_keyblock(ob);
}
@@ -6703,17 +6973,22 @@ static void sculpt_stroke_update_step(bContext *C,
* Same applies to the DEG_id_tag_update() invoked from
* sculpt_flush_update_step().
*/
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
sculpt_flush_stroke_deform(sd, ob, sculpt_tool_is_proxy_used(brush->sculpt_tool));
}
- else if (ss->kb) {
+ else if (ss->shapekey_active) {
sculpt_update_keyblock(ob);
}
ss->cache->first_time = false;
/* Cleanup */
- sculpt_flush_update_step(C);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
+ }
}
static void sculpt_brush_exit_tex(Sculpt *sd)
@@ -6766,7 +7041,12 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ if (brush->sculpt_tool == SCULPT_TOOL_MASK) {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
+ }
+ else {
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
+ }
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
@@ -6797,12 +7077,12 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
ignore_background_click = RNA_boolean_get(op->ptr, "ignore_background_click");
if (ignore_background_click && !over_mesh(C, op, event->x, event->y)) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_PASS_THROUGH;
}
if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
- paint_stroke_data_free(op);
+ paint_stroke_free(C, op);
return OPERATOR_FINISHED;
}
/* add modal handler */
@@ -6931,8 +7211,19 @@ void sculpt_pbvh_clear(Object *ob)
/* 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;
}
- ss->pbvh = 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. */
@@ -7502,13 +7793,11 @@ void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scen
const int mode_flag = OB_MODE_SCULPT;
Mesh *me = BKE_mesh_from_object(ob);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
- if (mmd) {
- multires_force_update(ob);
- }
+ multires_flush_sculpt_updates(ob);
/* Not needed for now. */
#if 0
+ MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd);
#endif
@@ -7653,7 +7942,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- MEM_freeN(nodes);
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
/* force rebuild of pbvh for better BB placement */
@@ -7694,8 +7983,9 @@ static void sample_detail(bContext *C, int mx, int my)
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
/* Pick sample detail. */
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
@@ -7738,7 +8028,7 @@ static int sculpt_sample_detail_size_exec(bContext *C, wmOperator *op)
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), BC_EYEDROPPER_CURSOR);
+ WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -7859,43 +8149,36 @@ static void filter_cache_init_task_cb(void *__restrict userdata,
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)
- {
- if (!vd.mask || (vd.mask && *vd.mask < 1.0f)) {
- data->node_mask[i] = 1;
- }
- }
- BKE_pbvh_vertex_iter_end;
-
- if (data->node_mask[i] == 1) {
- sculpt_undo_push_node(data->ob, node, SCULPT_UNDO_COORDS);
- }
+ 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;
- PBVHNode **nodes;
- int totnode;
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,
- };
- BKE_pbvh_search_gather(pbvh, NULL, &search_data, &nodes, &totnode);
+ .center = center,
+ .radius_squared = FLT_MAX,
+ .ignore_fully_masked = true,
- int *node_mask = MEM_callocN((unsigned int)totnode * sizeof(int), "node mask");
+ };
+ BKE_pbvh_search_gather(pbvh,
+ sculpt_search_sphere_cb,
+ &search_data,
+ &ss->filter_cache->nodes,
+ &ss->filter_cache->totnode);
- for (int i = 0; i < totnode; i++) {
- BKE_pbvh_node_mark_normals_update(nodes[i]);
+ 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.
@@ -7907,45 +8190,14 @@ static void sculpt_filter_cache_init(Object *ob, Sculpt *sd)
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
- .nodes = nodes,
- .node_mask = node_mask,
+ .nodes = ss->filter_cache->nodes,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, filter_cache_init_task_cb, &settings);
-
- int tot_active_nodes = 0;
- int active_node_index = 0;
- PBVHNode **active_nodes;
-
- /* Count number of PBVH nodes that are not fully masked */
- for (int i = 0; i < totnode; i++) {
- if (node_mask[i] == 1) {
- tot_active_nodes++;
- }
- }
-
- /* Create the final list of nodes that is going to be processed in the filter */
- active_nodes = MEM_callocN(tot_active_nodes * sizeof(PBVHNode *), "active nodes");
-
- for (int i = 0; i < totnode; i++) {
- if (node_mask[i] == 1) {
- active_nodes[active_node_index] = nodes[i];
- active_node_index++;
- }
- }
-
- ss->filter_cache->nodes = active_nodes;
- ss->filter_cache->totnode = tot_active_nodes;
-
- if (nodes) {
- MEM_freeN(nodes);
- }
- if (node_mask) {
- MEM_freeN(node_mask);
- }
+ 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)
@@ -8017,15 +8269,25 @@ static void mesh_filter_task_cb(void *__restrict userdata,
float fade = vd.mask ? *vd.mask : 0.0f;
fade = 1 - fade;
fade *= data->filter_strength;
+
+ if (fade == 0.0f) {
+ continue;
+ }
+
copy_v3_v3(orig_co, orig_data.co);
switch (filter_type) {
case MESH_FILTER_SMOOTH:
CLAMP(fade, -1.0f, 1.0f);
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- neighbor_average(ss, avg, vd.index);
- }
- else if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
- bmesh_neighbor_average(avg, vd.bm_vert);
+ 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:
+ grids_neighbor_average(ss, avg, vd.index);
+ break;
}
sub_v3_v3v3(val, avg, orig_co);
madd_v3_v3v3fl(val, orig_co, val, fade);
@@ -8064,11 +8326,16 @@ static void mesh_filter_task_cb(void *__restrict userdata,
mid_v3_v3v3(disp, disp, disp2);
break;
- case MESH_FILTER_RANDOM:
+ case MESH_FILTER_RANDOM: {
normal_short_to_float_v3(normal, orig_data.no);
- mul_v3_fl(normal, BLI_hash_int_01(vd.index ^ ss->filter_cache->random_seed) - 0.5f);
+ /* 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;
+ }
}
for (int it = 0; it < 3; it++) {
@@ -8079,8 +8346,9 @@ static void mesh_filter_task_cb(void *__restrict userdata,
add_v3_v3v3(final_pos, orig_co, disp);
copy_v3_v3(vd.co, final_pos);
- if (vd.mvert)
+ if (vd.mvert) {
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
}
BKE_pbvh_vertex_iter_end;
@@ -8100,7 +8368,7 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
return OPERATOR_FINISHED;
}
@@ -8124,17 +8392,16 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent *
.filter_strength = filter_strength,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings);
+ 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 (ss->modifiers_active || ss->kb) {
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
sculpt_flush_stroke_deform(sd, ob, true);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
return OPERATOR_RUNNING_MODAL;
}
@@ -8148,10 +8415,6 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
SculptSession *ss = ob->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
int deform_axis = RNA_enum_get(op->ptr, "deform_axis");
if (deform_axis == 0) {
return OPERATOR_CANCELLED;
@@ -8260,35 +8523,42 @@ static void mask_filter_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
- float val;
float delta, gain, offset, max, min;
float prev_val = *vd.mask;
SculptVertexNeighborIter ni;
switch (mode) {
case MASK_FILTER_SMOOTH:
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- val = neighbor_average_mask(ss, vd.index) - *vd.mask;
+ 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;
}
- else {
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- }
- *vd.mask += val;
- break;
- case MASK_FILTER_SHARPEN:
- if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) {
- val = neighbor_average_mask(ss, vd.index) - *vd.mask;
- }
- else {
- val = bmesh_neighbor_average_mask(vd.bm_vert, vd.cd_vert_mask_offset) - *vd.mask;
- }
- if (*vd.mask > 0.5f) {
- *vd.mask += 0.05f;
+
+ val -= *vd.mask;
+
+ if (mode == MASK_FILTER_SMOOTH) {
+ *vd.mask += val;
}
- else {
- *vd.mask -= 0.05f;
+ else if (mode == MASK_FILTER_SHARPEN) {
+ if (*vd.mask > 0.5f) {
+ *vd.mask += 0.05f;
+ }
+ else {
+ *vd.mask -= 0.05f;
+ }
+ *vd.mask += val / 2;
}
- *vd.mask += val / 2;
break;
+ }
case MASK_FILTER_GROW:
max = 0.0f;
sculpt_vertex_neighbors_iter_begin(ss, vd.index, ni)
@@ -8339,7 +8609,7 @@ static void mask_filter_task_cb(void *__restrict userdata,
BKE_pbvh_vertex_iter_end;
if (update) {
- BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
}
@@ -8355,10 +8625,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
int totnode;
int filter_type = RNA_enum_get(op->ptr, "filter_type");
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
sculpt_vertex_random_access_init(ss);
@@ -8380,16 +8646,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
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 unnecesary ammount 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 */
+ * 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((unsigned long)num_verts * sizeof(float), "prevmask");
+ 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);
}
@@ -8403,19 +8669,16 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
.prev_mask = prev_mask,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings);
+ 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);
}
}
- if (nodes) {
- MEM_freeN(nodes);
- }
+ MEM_SAFE_FREE(nodes);
sculpt_undo_push_end();
@@ -8461,17 +8724,17 @@ static void SCULPT_OT_mask_filter(struct wmOperatorType *ot)
"Use a automatic number of iterations based on the number of vertices of the sculpt");
}
-static float neighbor_dirty_mask(SculptSession *ss, const int vert)
+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, vert, ni)
+ sculpt_vertex_neighbors_iter_begin(ss, vd->index, ni)
{
float normalized[3];
- sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), sculpt_vertex_co_get(ss, vert));
+ sub_v3_v3v3(normalized, sculpt_vertex_co_get(ss, ni.index), vd->co);
normalize_v3(normalized);
add_v3_v3(avg, normalized);
total++;
@@ -8481,7 +8744,12 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert)
if (total > 0) {
mul_v3_fl(avg, 1.0f / total);
float normal[3];
- sculpt_vertex_normal_get(ss, vert, normal);
+ 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;
@@ -8489,25 +8757,75 @@ static float neighbor_dirty_mask(SculptSession *ss, const int vert)
return 0;
}
-static void dirty_mask_task_cb(void *__restrict userdata,
- const int i,
- const TaskParallelTLS *__restrict UNUSED(tls))
+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;
+ }
+ else {
+ range = 1.0f / range;
+ }
+
BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_UNIQUE)
{
- float val;
- val = neighbor_dirty_mask(ss, vd.index);
- data->prev_mask[vd.index] = val;
+ float dirty_mask = neighbor_dirty_mask(ss, &vd);
+ float mask = *vd.mask + (1 - ((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_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
@@ -8521,10 +8839,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
int totnode;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true);
sculpt_vertex_random_access_init(ss);
@@ -8533,8 +8847,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- int num_verts = sculpt_vertex_count_get(ss);
-
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
sculpt_undo_push_begin("Dirty Mask");
@@ -8542,59 +8854,32 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op)
sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
}
- float *prev_mask = NULL;
-
- prev_mask = MEM_mallocN((unsigned long)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,
- .prev_mask = prev_mask,
+ .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"),
+ };
+ DirtyMaskRangeData range = {
+ .min = FLT_MAX,
+ .max = -FLT_MAX,
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, totnode, &data, dirty_mask_task_cb, &settings);
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
- float min = FLT_MAX;
- float max = FLT_MIN;
- for (int i = 0; i < num_verts; i++) {
- float val = prev_mask[i];
- if (val < min) {
- min = val;
- }
- if (val > max) {
- max = val;
- }
- }
+ settings.func_reduce = dirty_mask_compute_range_reduce;
+ settings.userdata_chunk = &range;
+ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData);
- float range = max - min;
- if (range < 0.0001f) {
- range = 0;
- }
- else {
- range = 1.0f / range;
- }
+ 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);
- bool dirty_only = RNA_boolean_get(op->ptr, "dirty_only");
- for (int i = 0; i < num_verts; i++) {
- sculpt_vertex_mask_set(
- ss, i, sculpt_vertex_mask_get(ss, i) + (1 - ((prev_mask[i] - min) * range)));
- if (dirty_only) {
- sculpt_vertex_mask_set(ss, i, fminf(sculpt_vertex_mask_get(ss, i), 0.5f) * 2.0f);
- }
- sculpt_vertex_mask_clamp(ss, i, 0.0f, 1.0f);
- }
- MEM_freeN(prev_mask);
+ MEM_SAFE_FREE(nodes);
- if (nodes) {
- MEM_freeN(nodes);
- }
+ BKE_pbvh_update_vertex_data(pbvh, SCULPT_UPDATE_MASK);
sculpt_undo_push_end();
@@ -8630,19 +8915,22 @@ static void sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
MEM_freeN(op->customdata);
- int vert_count = sculpt_vertex_count_get(ss);
- for (int i = 0; i < vert_count; i++) {
- sculpt_vertex_mask_set(ss, i, ss->filter_cache->prev_mask[i]);
- }
+ for (int n = 0; n < ss->filter_cache->totnode; n++) {
+ PBVHNode *node = ss->filter_cache->nodes[n];
+ 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;
- for (int i = 0; i < ss->filter_cache->totnode; i++) {
- BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ BKE_pbvh_node_mark_redraw(node);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
}
@@ -8692,7 +8980,7 @@ static void sculpt_expand_task_cb(void *__restrict userdata,
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
*vd.mask = final_mask;
- BKE_pbvh_node_mark_redraw(node);
+ BKE_pbvh_node_mark_update_mask(node);
}
}
BKE_pbvh_vertex_iter_end;
@@ -8724,8 +9012,11 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
if ((event->type == 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_CANCELLED;
+ return OPERATOR_FINISHED;
}
if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
@@ -8743,30 +9034,36 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
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++) {
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ 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;
- float threshold = 0.2f;
zero_v3(avg);
- int vertex_count = sculpt_vertex_count_get(ss);
- for (int i = 0; i < vertex_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
- sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
- check_vertex_pivot_symmetry(
- sculpt_vertex_co_get(ss, i), ss->filter_cache->mask_expand_initial_co, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+
+ 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 (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);
@@ -8783,7 +9080,7 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
sculpt_filter_cache_free(ss);
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_MASK);
ED_workspace_status_text(C, NULL);
return OPERATOR_FINISHED;
}
@@ -8806,20 +9103,60 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *
.mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ 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_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);
@@ -8827,20 +9164,14 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
SculptSession *ss = ob->sculpt;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
PBVH *pbvh = ob->sculpt->pbvh;
- float original_normal[3];
bool use_normals = RNA_boolean_get(op->ptr, "use_normals");
- int edge_sensitivity = RNA_int_get(op->ptr, "edge_sensitivity");
SculptCursorGeometryInfo sgi;
float mouse[2];
mouse[0] = event->mval[0];
mouse[1] = event->mval[1];
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
sculpt_vertex_random_access_init(ss);
op->customdata = MEM_mallocN(2 * sizeof(float), "initial mouse position");
@@ -8854,16 +9185,7 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache = MEM_callocN(sizeof(FilterCache), "filter cache");
- SculptSearchSphereData searchdata = {
- .ss = ss,
- .sd = sd,
- .radius_squared = FLT_MAX,
- };
- BKE_pbvh_search_gather(pbvh,
- sculpt_search_sphere_cb,
- &searchdata,
- &ss->filter_cache->nodes,
- &ss->filter_cache->totnode);
+ BKE_pbvh_search_gather(pbvh, NULL, NULL, &ss->filter_cache->nodes, &ss->filter_cache->totnode);
sculpt_undo_push_begin("Mask Expand");
@@ -8877,6 +9199,11 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
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;
+ }
}
ss->filter_cache->prev_mask = MEM_callocN(sizeof(float) * vertex_count, "prev mask");
@@ -8886,68 +9213,21 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache->mask_update_last_it = 1;
ss->filter_cache->mask_update_current_it = 1;
- ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)] = 1;
-
- copy_v3_v3(ss->filter_cache->mask_expand_initial_co,
- sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
-
- char *visited_vertices = MEM_callocN(vertex_count * sizeof(char), "visited vertices");
+ ss->filter_cache->mask_update_it[sculpt_active_vertex_get(ss)] = 1;
- sculpt_vertex_normal_get(ss, sculpt_active_vertex_get(ss), original_normal);
+ copy_v3_v3(ss->filter_cache->mask_expand_initial_co, sculpt_active_vertex_co_get(ss));
- GSQueue *queue = BLI_gsqueue_new(sizeof(VertexTopologyIterator));
- VertexTopologyIterator mevit;
+ SculptFloodFill flood;
+ sculpt_floodfill_init(ss, &flood);
+ sculpt_floodfill_add_active(sd, ob, ss, &flood, FLT_MAX);
- const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- for (char i = 0; i <= symm; ++i) {
- if (is_symmetry_iteration_valid(i, symm)) {
- float location[3];
- flip_v3_v3(location, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)), i);
- if (i == 0) {
- mevit.v = sculpt_active_vertex_get(ss);
- mevit.edge_factor = 1.0f;
- }
- else {
- mevit.v = sculpt_nearest_vertex_get(sd, ob, location, FLT_MAX, false);
- mevit.edge_factor = 1.0f;
- }
- if (mevit.v != -1) {
- sculpt_vertex_mask_set(ss, mevit.v, 1.0f);
- mevit.it = 0;
- BLI_gsqueue_push(queue, &mevit);
- }
- }
- }
-
- while (!BLI_gsqueue_is_empty(queue)) {
- VertexTopologyIterator c_mevit;
- BLI_gsqueue_pop(queue, &c_mevit);
- SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
- {
- if (visited_vertices[(int)ni.index] == 0) {
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->filter_cache->mask_update_it[(int)new_entry.v] = new_entry.it;
- visited_vertices[(int)ni.index] = 1;
- if (ss->filter_cache->mask_update_last_it < new_entry.it) {
- ss->filter_cache->mask_update_last_it = new_entry.it;
- }
- if (use_normals) {
- float current_normal[3], prev_normal[3];
- sculpt_vertex_normal_get(ss, ni.index, current_normal);
- sculpt_vertex_normal_get(ss, c_mevit.v, prev_normal);
- new_entry.edge_factor = dot_v3v3(current_normal, prev_normal) * c_mevit.edge_factor;
- ss->filter_cache->normal_factor[ni.index] = dot_v3v3(original_normal, current_normal) *
- powf(c_mevit.edge_factor, edge_sensitivity);
- CLAMP(ss->filter_cache->normal_factor[ni.index], 0, 1);
- }
- BLI_gsqueue_push(queue, &new_entry);
- }
- }
- sculpt_vertex_neighbors_iter_end(ni);
- }
+ 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++) {
@@ -8962,11 +9242,9 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
ss->filter_cache->normal_factor[i] = avg / ni.size;
}
}
- }
-
- BLI_gsqueue_free(queue);
- MEM_freeN(visited_vertices);
+ MEM_SAFE_FREE(ss->filter_cache->edge_factor);
+ }
SculptThreadedTaskData data = {
.sd = sd,
@@ -8977,19 +9255,17 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent
.mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
.mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
};
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
-
- BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ 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. LBM: confirm mask, ESC/RMB: "
"cancel");
ED_workspace_status_text(C, status_str);
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_MASK);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -9061,46 +9337,47 @@ void sculpt_geometry_preview_lines_update(bContext *C, SculptSession *ss, float
}
float brush_co[3];
- copy_v3_v3(brush_co, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
+ 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");
+ /* Assuming an average of 6 edges per vertex in a triangulated mesh */
+ const int max_preview_vertices = sculpt_vertex_count_get(ss) * 3 * 2;
+
if (ss->preview_vert_index_list == NULL) {
- ss->preview_vert_index_list = MEM_callocN(4 * sizeof(int) * sculpt_vertex_count_get(ss),
- "preview lines");
+ ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines");
}
- BLI_Stack *not_visited_vertices = BLI_stack_new(sizeof(VertexTopologyIterator),
- "Not visited vertices stack");
- VertexTopologyIterator mevit;
- mevit.v = sculpt_active_vertex_get(ss);
- BLI_stack_push(not_visited_vertices, &mevit);
+ GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int));
+ int active_v = sculpt_active_vertex_get(ss);
+ BLI_gsqueue_push(not_visited_vertices, &active_v);
- while (!BLI_stack_is_empty(not_visited_vertices)) {
- VertexTopologyIterator c_mevit;
- BLI_stack_pop(not_visited_vertices, &c_mevit);
+ while (!BLI_gsqueue_is_empty(not_visited_vertices)) {
+ int from_v;
+ BLI_gsqueue_pop(not_visited_vertices, &from_v);
SculptVertexNeighborIter ni;
- sculpt_vertex_neighbors_iter_begin(ss, c_mevit.v, ni)
+ sculpt_vertex_neighbors_iter_begin(ss, from_v, ni)
{
- VertexTopologyIterator new_entry;
- new_entry.v = ni.index;
- new_entry.it = c_mevit.it + 1;
- ss->preview_vert_index_list[totpoints] = c_mevit.v;
- totpoints++;
- ss->preview_vert_index_list[totpoints] = new_entry.v;
- totpoints++;
- if (visited_vertices[(int)ni.index] == 0) {
- visited_vertices[(int)ni.index] = 1;
- if (len_squared_v3v3(brush_co, sculpt_vertex_co_get(ss, new_entry.v)) < radius * radius) {
- BLI_stack_push(not_visited_vertices, &new_entry);
+ 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;
+ 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);
+ }
}
}
}
sculpt_vertex_neighbors_iter_end(ni);
}
- BLI_stack_free(not_visited_vertices);
+ BLI_gsqueue_free(not_visited_vertices);
MEM_freeN(visited_vertices);
@@ -9234,8 +9511,7 @@ static void sculpt_transform_task_cb(void *__restrict userdata,
}
BKE_pbvh_vertex_iter_end;
- BKE_pbvh_node_mark_redraw(node);
- BKE_pbvh_node_mark_normals_update(node);
+ BKE_pbvh_node_mark_update(node);
}
void ED_sculpt_update_modal_transform(struct bContext *C)
@@ -9295,18 +9571,17 @@ void ED_sculpt_update_modal_transform(struct bContext *C)
mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]);
}
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
- ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
+ 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->modifiers_active || ss->kb) {
+ if (ss->deform_modifiers_active || ss->shapekey_active) {
sculpt_flush_stroke_deform(sd, ob, true);
}
- sculpt_flush_update_step(C);
+ sculpt_flush_update_step(C, SCULPT_UPDATE_COORDS);
}
void ED_sculpt_end_transform(struct bContext *C)
@@ -9317,7 +9592,7 @@ void ED_sculpt_end_transform(struct bContext *C)
sculpt_filter_cache_free(ss);
}
sculpt_undo_push_end();
- sculpt_flush_update_done(C, ob);
+ sculpt_flush_update_done(C, ob, SCULPT_UPDATE_COORDS);
}
typedef enum eSculptPivotPositionModes {
@@ -9366,73 +9641,80 @@ static int sculpt_set_pivot_position_invoke(bContext *C, wmOperator *op, const w
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
- return OPERATOR_CANCELLED;
- }
-
int mode = RNA_enum_get(op->ptr, "mode");
BKE_sculpt_update_object_for_edit(depsgraph, ob, false, true);
- int vert_count = sculpt_vertex_count_get(ss);
-
/* 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] = event->mval[0];
+ mouse[1] = event->mval[1];
+ 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);
- /* Pivot to unmasked */
- if (mode == SCULPT_PIVOT_POSITION_UNMASKED) {
float avg[3];
int total = 0;
zero_v3(avg);
- for (int i = 0; i < vert_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < 1.0f &&
- check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+
+ /* 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 (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);
- }
- }
+ /* Pivot to mask border */
+ else if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
+ const float threshold = 0.2f;
- /* Pivot to mask border */
- if (mode == SCULPT_PIVOT_POSITION_MASK_BORDER) {
- float avg[3];
- int total = 0;
- float threshold = 0.2f;
- zero_v3(avg);
- for (int i = 0; i < vert_count; i++) {
- if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
- sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
- check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
- total++;
- add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+ 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 (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);
}
- }
- /* Pivot to active vertex */
- if (mode == SCULPT_PIVOT_POSITION_ACTIVE_VERTEX) {
- copy_v3_v3(ss->pivot_pos, sculpt_vertex_co_get(ss, sculpt_active_vertex_get(ss)));
- }
-
- /* Pivot to raycast surface */
- if (mode == SCULPT_PIVOT_POSITION_CURSOR_SURFACE) {
- float stroke_location[3];
- float mouse[2];
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
- if (sculpt_stroke_get_location(C, stroke_location, mouse)) {
- copy_v3_v3(ss->pivot_pos, stroke_location);
- }
+ MEM_SAFE_FREE(nodes);
}
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index b814e87fcb0..93e4a777569 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -44,6 +44,13 @@ bool sculpt_mode_poll_view3d(struct bContext *C);
bool sculpt_poll(struct bContext *C);
bool sculpt_poll_view3d(struct bContext *C);
+/* Updates */
+
+typedef enum SculptUpdateType {
+ SCULPT_UPDATE_COORDS = 1 << 0,
+ SCULPT_UPDATE_MASK = 1 << 1,
+} SculptUpdateType;
+
/* Stroke */
typedef struct SculptCursorGeometryInfo {
@@ -58,9 +65,17 @@ bool sculpt_cursor_geometry_info_update(bContext *C,
const float mouse[2],
bool use_sampled_normal);
void sculpt_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius);
+void sculpt_pose_calc_pose_data(struct Sculpt *sd,
+ struct Object *ob,
+ struct SculptSession *ss,
+ float initial_location[3],
+ float radius,
+ float pose_offset,
+ float *r_pose_origin,
+ float *r_pose_factor);
/* Sculpt PBVH abstraction API */
-float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
+const float *sculpt_vertex_co_get(struct SculptSession *ss, int index);
/* Dynamic topology */
void sculpt_pbvh_clear(Object *ob);
@@ -179,23 +194,20 @@ typedef struct SculptThreadedTaskData {
int filter_type;
float filter_strength;
- int *node_mask;
- /* 0=towards view, 1=flipped */
- float (*area_cos)[3];
- float (*area_nos)[3];
- int *count;
+ bool use_area_cos;
+ bool use_area_nos;
bool any_vertex_sampled;
float *prev_mask;
float *pose_origin;
float *pose_initial_co;
+ float *pose_factor;
float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4];
float max_distance_squared;
float nearest_vertex_search_co[3];
- int nearest_vertex_index;
int mask_expand_update_it;
bool mask_expand_invert_mask;
@@ -204,6 +216,10 @@ typedef struct SculptThreadedTaskData {
float transform_mats[8][4][4];
+ float dirty_mask_min;
+ float dirty_mask_max;
+ bool dirty_mask_dirty_only;
+
ThreadMutex mutex;
} SculptThreadedTaskData;
@@ -233,6 +249,7 @@ typedef struct {
float radius_squared;
float *center;
bool original;
+ bool ignore_fully_masked;
} SculptSearchSphereData;
typedef struct {
@@ -240,6 +257,7 @@ typedef struct {
struct SculptSession *ss;
float radius_squared;
bool original;
+ bool ignore_fully_masked;
struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc;
} SculptSearchCircleData;
@@ -392,6 +410,7 @@ typedef struct FilterCache {
int mask_update_last_it;
int *mask_update_it;
float *normal_factor;
+ float *edge_factor;
float *prev_mask;
float mask_expand_initial_co[3];
} FilterCache;
@@ -413,6 +432,4 @@ void sculpt_update_object_bounding_box(struct Object *ob);
bool sculpt_get_redraw_rect(struct ARegion *ar, struct RegionView3D *rv3d, Object *ob, rcti *rect);
-#define SCULPT_THREADED_LIMIT 4
-
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 3783eb17562..5d95cc80280 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -39,8 +39,6 @@
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_screen_types.h"
-#include "DNA_space_types.h"
-#include "DNA_workspace_types.h"
#include "BKE_ccg.h"
#include "BKE_context.h"
@@ -49,7 +47,6 @@
#include "BKE_paint.h"
#include "BKE_key.h"
#include "BKE_mesh.h"
-#include "BKE_mesh_runtime.h"
#include "BKE_scene.h"
#include "BKE_subsurf.h"
#include "BKE_subdiv_ccg.h"
@@ -62,13 +59,11 @@
#include "WM_api.h"
#include "WM_types.h"
-#include "ED_paint.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_undo.h"
#include "bmesh.h"
-#include "paint_intern.h"
#include "sculpt_intern.h"
typedef struct UndoSculpt {
@@ -91,6 +86,7 @@ static void update_cb(PBVHNode *node, void *rebuild)
struct PartialUpdateData {
PBVH *pbvh;
bool rebuild;
+ char *modified_grids;
};
/**
@@ -99,8 +95,24 @@ struct PartialUpdateData {
static void update_cb_partial(PBVHNode *node, void *userdata)
{
struct PartialUpdateData *data = userdata;
- if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
- update_cb(node, &(data->rebuild));
+ if (BKE_pbvh_type(data->pbvh) == PBVH_GRIDS) {
+ int *node_grid_indices;
+ int totgrid;
+ bool update = false;
+ BKE_pbvh_node_get_grids(data->pbvh, node, &node_grid_indices, &totgrid, NULL, NULL, NULL);
+ for (int i = 0; i < totgrid; i++) {
+ if (data->modified_grids[node_grid_indices[i]] == 1) {
+ update = true;
+ }
+ }
+ if (update) {
+ update_cb(node, &(data->rebuild));
+ }
+ }
+ else {
+ if (BKE_pbvh_node_vert_update_check_any(data->pbvh, node)) {
+ update_cb(node, &(data->rebuild));
+ }
}
}
@@ -140,7 +152,7 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
if (unode->maxvert) {
/* regular mesh restore */
- if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
+ if (ss->shapekey_active && !STREQ(ss->shapekey_active->name, unode->shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key = BKE_key_from_object(ob);
@@ -162,12 +174,12 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
index = unode->index;
mvert = ss->mvert;
- if (ss->kb) {
+ if (ss->shapekey_active) {
float(*vertCos)[3];
- vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->kb);
+ vertCos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active);
if (unode->orig_co) {
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
sculpt_undo_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
}
@@ -185,36 +197,33 @@ static bool sculpt_undo_restore_coords(bContext *C, Depsgraph *depsgraph, Sculpt
}
/* propagate new coords to keyblock */
- sculpt_vertcos_to_key(ob, ss->kb, vertCos);
+ sculpt_vertcos_to_key(ob, ss->shapekey_active, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
- BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->kb->totelem);
+ BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, ss->shapekey_active->totelem);
MEM_freeN(vertCos);
}
else {
if (unode->orig_co) {
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
for (int i = 0; i < unode->totvert; i++) {
- if (sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co)) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ sculpt_undo_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->orig_co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ swap_v3_v3(mvert[index[i]].co, unode->orig_co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else {
for (int i = 0; i < unode->totvert; i++) {
- if (test_swap_v3_v3(mvert[index[i]].co, unode->co[i])) {
- mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
- }
+ swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
@@ -351,10 +360,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
- TaskParallelSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_THREADED_LIMIT);
- BLI_task_parallel_range(
+ PBVHParallelSettings settings;
+ BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode);
+ BKE_pbvh_parallel_range(
0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings);
if (nodes) {
@@ -491,7 +499,6 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
SculptUndoNode *unode;
bool update = false, rebuild = false;
bool need_mask = false;
- bool partial_update = true;
for (unode = lb->first; unode; unode = unode->next) {
/* restore pivot */
@@ -533,6 +540,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
return;
}
+ char *undo_modified_grids = NULL;
+ bool use_multires_undo = false;
+
for (unode = lb->first; unode; unode = unode->next) {
if (!STREQ(unode->idname, ob->id.name)) {
@@ -552,8 +562,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
continue;
}
- /* multi-res can't do partial updates since it doesn't flag edited vertices */
- partial_update = false;
+ use_multires_undo = true;
}
switch (unode->type) {
@@ -583,21 +592,29 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
}
}
+ 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) {
+ for (int i = 0; i < unode->totgrid; i++) {
+ undo_modified_grids[unode->grids[i]] = 1;
+ }
+ }
+ }
+
if (update || rebuild) {
bool tag_update = false;
/* we update all nodes still, should be more clever, but also
* needs to work correct when exiting/entering sculpt mode and
* the nodes get recreated, though in that case it could do all */
- if (partial_update) {
- struct PartialUpdateData data = {
- .rebuild = rebuild,
- .pbvh = ss->pbvh,
- };
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
- }
- else {
- BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, &rebuild);
- }
+ struct PartialUpdateData data = {
+ .rebuild = rebuild,
+ .pbvh = ss->pbvh,
+ .modified_grids = undo_modified_grids,
+ };
+ BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
if (BKE_sculpt_multires_active(scene, ob)) {
@@ -611,7 +628,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
tag_update |= ((Mesh *)ob->data)->id.us > 1 || !BKE_sculptsession_use_pbvh_draw(ob, v3d);
- if (ss->kb || ss->modifiers_active) {
+ if (ss->shapekey_active || ss->deform_modifiers_active) {
Mesh *mesh = ob->data;
BKE_mesh_calc_normals(mesh);
@@ -626,6 +643,8 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
sculpt_update_object_bounding_box(ob);
}
}
+
+ MEM_SAFE_FREE(undo_modified_grids);
}
static void sculpt_undo_free_list(ListBase *lb)
@@ -812,7 +831,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt
unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index");
}
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
unode->orig_co = MEM_callocN(allvert * sizeof(*unode->orig_co), "undoSculpt orig_cos");
}
@@ -834,7 +853,7 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode)
normal_float_to_short_v3(unode->no[vd.i], vd.fno);
}
- if (ss->modifiers_active) {
+ if (ss->deform_modifiers_active) {
copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
}
}
@@ -1063,8 +1082,8 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType
copy_v3_v3(unode->pivot_rot, ss->pivot_rot);
/* store active shape key */
- if (ss->kb) {
- BLI_strncpy(unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
+ if (ss->shapekey_active) {
+ BLI_strncpy(unode->shapeName, ss->shapekey_active->name, sizeof(ss->shapekey_active->name));
}
else {
unode->shapeName[0] = '\0';
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index de03fea7bb1..8fbaf3396bd 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -38,7 +38,6 @@
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
-#include "BKE_main.h"
#include "BKE_mesh_mapping.h"
#include "BKE_paint.h"
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 4e710d31cbb..69745663c02 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -273,8 +273,11 @@ static void sound_update_animation_flags(Scene *scene)
static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
{
+ Scene *scene = CTX_data_scene(C);
+
BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
sound_update_animation_flags(CTX_data_scene(C));
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 944a0c74f4c..242acfd0261 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -1663,7 +1663,7 @@ static const EnumPropertyItem prop_actkeys_snap_types[] = {
{ACTKEYS_SNAP_CFRA,
"CFRA",
0,
- "Current frame",
+ "Current Frame",
"Snap selected keyframes to the current frame"},
{ACTKEYS_SNAP_NEAREST_FRAME,
"NEAREST_FRAME",
@@ -1789,17 +1789,17 @@ static const EnumPropertyItem prop_actkeys_mirror_types[] = {
{ACTKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{ACTKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{ACTKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 912cd0407e3..ca6efb5f69e 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -153,7 +153,8 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
float region_x,
float *r_selx,
float *r_frame,
- bool *r_found)
+ bool *r_found,
+ bool *r_is_selected)
{
*r_found = false;
@@ -182,6 +183,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
*r_selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
*r_frame = ak->cfra;
*r_found = true;
+ *r_is_selected = (ak->sel & SELECT) != 0;
break;
}
}
@@ -197,14 +199,16 @@ static void actkeys_find_key_at_position(bAnimContext *ac,
bAnimListElem **r_ale,
float *r_selx,
float *r_frame,
- bool *r_found)
+ bool *r_found,
+ bool *r_is_selected)
{
*r_found = false;
*r_ale = actkeys_find_list_element_at_position(ac, filter, region_x, region_y);
if (*r_ale != NULL) {
- actkeys_find_key_in_list_element(ac, *r_ale, region_x, r_selx, r_frame, r_found);
+ actkeys_find_key_in_list_element(
+ ac, *r_ale, region_x, r_selx, r_frame, r_found, r_is_selected);
}
}
@@ -213,9 +217,11 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r
bAnimListElem *ale;
float selx, frame;
bool found;
+ bool is_selected;
int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
- actkeys_find_key_at_position(ac, filter, region_x, region_y, &ale, &selx, &frame, &found);
+ actkeys_find_key_at_position(
+ ac, filter, region_x, region_y, &ale, &selx, &frame, &found, &is_selected);
if (ale != NULL) {
MEM_freeN(ale);
@@ -339,7 +345,9 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -572,7 +580,9 @@ static int actkeys_box_select_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -805,7 +815,9 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -871,7 +883,9 @@ static int action_circle_select_exec(bContext *C, wmOperator *op)
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1099,7 +1113,9 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1159,7 +1175,9 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1243,7 +1261,9 @@ static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1278,7 +1298,9 @@ static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
-
+ if (ac.datatype == ANIMCONT_GPENCIL) {
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
+ }
return OPERATOR_FINISHED;
}
@@ -1665,20 +1687,29 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
/* ------------------- */
-static void mouse_action_keys(bAnimContext *ac,
- const int mval[2],
- short select_mode,
- const bool deselect_all,
- const bool column,
- const bool same_channel)
+static int mouse_action_keys(bAnimContext *ac,
+ const int mval[2],
+ short select_mode,
+ const bool deselect_all,
+ const bool column,
+ const bool same_channel,
+ bool wait_to_deselect_others)
{
int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
bAnimListElem *ale = NULL;
bool found = false;
+ bool is_selected = false;
float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
float selx = 0.0f; /* frame of keyframe under mouse */
- actkeys_find_key_at_position(ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found);
+ int ret_value = OPERATOR_FINISHED;
+
+ actkeys_find_key_at_position(
+ ac, filter, mval[0], mval[1], &ale, &selx, &frame, &found, &is_selected);
+
+ if (select_mode != SELECT_REPLACE) {
+ wait_to_deselect_others = false;
+ }
/* For replacing selection, if we have something to select, we have to clear existing selection.
* The same goes if we found nothing to select, and deselect_all is true
@@ -1687,56 +1718,61 @@ static void mouse_action_keys(bAnimContext *ac,
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- /* deselect all keyframes */
- deselect_action_keys(ac, 0, SELECT_SUBTRACT);
-
- /* highlight channel clicked on */
- if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-
- /* Highlight Action-Group or F-Curve? */
- if (ale != NULL && ale->data) {
- if (ale->type == ANIMTYPE_GROUP) {
- bActionGroup *agrp = ale->data;
-
- agrp->flag |= AGRP_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
- }
- else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
- FCurve *fcu = ale->data;
-
- fcu->flag |= FCURVE_SELECTED;
- ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
+ if (wait_to_deselect_others && is_selected) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ /* deselect all keyframes */
+ deselect_action_keys(ac, 0, SELECT_SUBTRACT);
+
+ /* highlight channel clicked on */
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_TIMELINE)) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+
+ /* Highlight Action-Group or F-Curve? */
+ if (ale != NULL && ale->data) {
+ if (ale->type == ANIMTYPE_GROUP) {
+ bActionGroup *agrp = ale->data;
+
+ agrp->flag |= AGRP_SELECTED;
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
+ }
+ else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
+ FCurve *fcu = ale->data;
+
+ fcu->flag |= FCURVE_SELECTED;
+ ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
+ }
}
}
- }
- else if (ac->datatype == ANIMCONT_GPENCIL) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
-
- /* Highlight GPencil Layer */
- if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
- bGPdata *gpd = (bGPdata *)ale->id;
- bGPDlayer *gpl = ale->data;
-
- gpl->flag |= GP_LAYER_SELECT;
- /* Update other layer status. */
- if (BKE_gpencil_layer_getactive(gpd) != gpl) {
- BKE_gpencil_layer_setactive(gpd, gpl);
- BKE_gpencil_layer_autolock_set(gpd, false);
- WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ else if (ac->datatype == ANIMCONT_GPENCIL) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+
+ /* Highlight GPencil Layer */
+ if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_GPLAYER) {
+ bGPdata *gpd = (bGPdata *)ale->id;
+ bGPDlayer *gpl = ale->data;
+
+ gpl->flag |= GP_LAYER_SELECT;
+ /* Update other layer status. */
+ if (BKE_gpencil_layer_getactive(gpd) != gpl) {
+ BKE_gpencil_layer_setactive(gpd, gpl);
+ BKE_gpencil_layer_autolock_set(gpd, false);
+ WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
}
}
- }
- else if (ac->datatype == ANIMCONT_MASK) {
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ else if (ac->datatype == ANIMCONT_MASK) {
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
- MaskLayer *masklay = ale->data;
+ if (ale != NULL && ale->data != NULL && ale->type == ANIMTYPE_MASKLAYER) {
+ MaskLayer *masklay = ale->data;
- masklay->flag |= MASK_LAYERFLAG_SELECT;
+ masklay->flag |= MASK_LAYERFLAG_SELECT;
+ }
}
}
}
@@ -1771,12 +1807,15 @@ static void mouse_action_keys(bAnimContext *ac,
/* free this channel */
MEM_freeN(ale);
}
+
+ return ret_value;
}
/* handle clicking */
-static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int actkeys_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+ int ret_value;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -1789,20 +1828,26 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent
/* select mode is either replace (deselect all, then add) or add/extend */
const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
+ int mval[2];
/* column selection */
const bool column = RNA_boolean_get(op->ptr, "column");
const bool channel = RNA_boolean_get(op->ptr, "channel");
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
+
/* select keyframe(s) based upon mouse position*/
- mouse_action_keys(&ac, event->mval, selectmode, deselect_all, column, channel);
+ ret_value = mouse_action_keys(
+ &ac, mval, selectmode, deselect_all, column, channel, wait_to_deselect_others);
/* set notifier that keyframe selection (and channels too) have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
/* for tweak grab to work */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value | OPERATOR_PASS_THROUGH;
}
void ACTION_OT_clickselect(wmOperatorType *ot)
@@ -1815,13 +1860,16 @@ void ACTION_OT_clickselect(wmOperatorType *ot)
ot->description = "Select keyframes by clicking on them";
/* callbacks */
- ot->invoke = actkeys_clickselect_invoke;
ot->poll = ED_operator_action_active;
+ ot->exec = actkeys_clickselect_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(
ot->srna,
"extend",
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index e96dc91cedb..80b58954c8f 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -161,7 +161,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *ar, MovieClip *clip, Sc
/* cache background */
ED_region_cache_draw_background(ar);
- /* cached segments -- could be usefu lto debug caching strategies */
+ /* cached segments -- could be useful to debug caching strategies */
BKE_movieclip_get_cache_segments(clip, &sc->user, &totseg, &points);
ED_region_cache_draw_cached_segments(ar, totseg, points, sfra, efra);
@@ -404,177 +404,185 @@ static void draw_stabilization_border(
}
}
-static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
-{
-#define MAX_STATIC_PATH 64
- int count = sc->path_length;
- int i, a, b, curindex = -1;
- float path_static[(MAX_STATIC_PATH + 1) * 2][2];
- float(*path)[2];
- int tiny = sc->flag & SC_SHOW_TINY_MARKER, framenr, start_frame;
- MovieTrackingMarker *marker;
+enum {
+ PATH_POINT_FLAG_KEYFRAME = (1 << 0),
+};
- if (count == 0) {
- return;
- }
+typedef struct TrachPathPoint {
+ float co[2];
+ uchar flag;
+} TrackPathPoint;
- start_frame = framenr = ED_space_clip_get_clip_frame_number(sc);
-
- marker = BKE_tracking_marker_get(track, framenr);
- if (marker->framenr != framenr || marker->flag & MARKER_DISABLED) {
- return;
- }
-
- if (count < MAX_STATIC_PATH) {
- path = path_static;
- }
- else {
- path = MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+static void marker_to_path_point(SpaceClip *sc,
+ const MovieTrackingTrack *track,
+ const MovieTrackingMarker *marker,
+ TrackPathPoint *point)
+{
+ add_v2_v2v2(point->co, marker->pos, track->offset);
+ ED_clip_point_undistorted_pos(sc, point->co, point->co);
+ point->flag = 0;
+ if ((marker->flag & MARKER_TRACKED) == 0) {
+ point->flag |= PATH_POINT_FLAG_KEYFRAME;
}
+}
- a = count;
- i = framenr - 1;
- while (i >= framenr - count) {
- marker = BKE_tracking_marker_get(track, i);
-
- if (!marker || marker->flag & MARKER_DISABLED) {
+static int track_to_path_segment(SpaceClip *sc,
+ MovieTrackingTrack *track,
+ int direction,
+ TrackPathPoint *path)
+{
+ const int count = sc->path_length;
+ int current_frame = ED_space_clip_get_clip_frame_number(sc);
+ const MovieTrackingMarker *marker = BKE_tracking_marker_get_exact(track, current_frame);
+ /* Check whether there is marker at exact current frame.
+ * If not, we don't have anything to be put to path. */
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ return 0;
+ }
+ /* Index inside of path array where we write data to. */
+ int point_index = count;
+ int path_length = 0;
+ for (int i = 0; i < count; ++i) {
+ marker_to_path_point(sc, track, marker, &path[point_index]);
+ /* Move to the next marker along the path segment. */
+ path_length++;
+ point_index += direction;
+ current_frame += direction;
+ marker = BKE_tracking_marker_get_exact(track, current_frame);
+ if (marker == NULL || (marker->flag & MARKER_DISABLED)) {
+ /* Reached end of tracked segment. */
break;
}
+ }
+ return path_length;
+}
- if (marker->framenr == i) {
- add_v2_v2v2(path[--a], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[a], path[a]);
+static void draw_track_path_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points == 0) {
+ return;
+ }
+ immBegin(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
+ }
+ immEnd();
+}
- if (marker->framenr == start_frame) {
- curindex = a;
- }
- }
- else {
- break;
+static void draw_track_path_keyframe_points(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ immBeginAtMost(GPU_PRIM_POINTS, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ if (point->flag & PATH_POINT_FLAG_KEYFRAME) {
+ immVertex2fv(position_attribute, point->co);
}
+ }
+ immEnd();
+}
- i--;
+static void draw_track_path_lines(const TrackPathPoint *path,
+ uint position_attribute,
+ const int start_point,
+ const int num_points)
+{
+ if (num_points < 2) {
+ return;
+ }
+ immBegin(GPU_PRIM_LINE_STRIP, num_points);
+ for (int i = 0; i < num_points; i++) {
+ const TrackPathPoint *point = &path[i + start_point];
+ immVertex2fv(position_attribute, point->co);
}
+ immEnd();
+}
- b = count;
- i = framenr;
- while (i <= framenr + count) {
- marker = BKE_tracking_marker_get(track, i);
+static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
+{
+#define MAX_STATIC_PATH 64
- if (!marker || marker->flag & MARKER_DISABLED) {
- break;
- }
+ const int count = sc->path_length;
+ TrackPathPoint path_static[(MAX_STATIC_PATH + 1) * 2];
+ TrackPathPoint *path;
+ const bool tiny = (sc->flag & SC_SHOW_TINY_MARKER) != 0;
- if (marker->framenr == i) {
- if (marker->framenr == start_frame) {
- curindex = b;
- }
+ if (count == 0) {
+ /* Early output, nothing to bother about here. */
+ return;
+ }
- add_v2_v2v2(path[b++], marker->pos, track->offset);
- ED_clip_point_undistorted_pos(sc, path[b - 1], path[b - 1]);
- }
- else {
- break;
- }
+ /* Try to use stack allocated memory when possibly, only use heap allocation
+ * for really long paths. */
+ path = (count < MAX_STATIC_PATH) ? path_static :
+ MEM_mallocN(sizeof(*path) * (count + 1) * 2, "path");
+ /* Collect path information. */
+ const int num_points_before = track_to_path_segment(sc, track, -1, path);
+ const int num_points_after = track_to_path_segment(sc, track, 1, path);
+ if (num_points_before == 0 && num_points_after == 0) {
+ return;
+ }
- i++;
+ int num_all_points = num_points_before + num_points_after;
+ /* If both leading and trailing parts of the path are there the center point is counted twice. */
+ if (num_points_before != 0 && num_points_after != 0) {
+ num_all_points -= 1;
}
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ const int path_start_index = count - num_points_before + 1;
+ const int path_center_index = count;
+ const uint position_attribute = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ /* Draw path outline. */
if (!tiny) {
immUniformThemeColor(TH_MARKER_OUTLINE);
-
if (TRACK_VIEW_SELECTED(sc, track)) {
- if ((b - a - 1) >= 1) {
- GPU_point_size(5.0f);
-
- immBegin(GPU_PRIM_POINTS, b - a - 1);
-
- for (i = a; i < b; i++) {
- if (i != curindex) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
- }
-
- immEnd();
- }
- }
-
- if ((b - a) >= 2) {
- GPU_line_width(3.0f);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - a);
-
- for (i = a; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ GPU_point_size(5.0f);
+ draw_track_path_points(path, position_attribute, path_start_index, num_all_points);
+ GPU_point_size(7.0f);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_all_points);
}
+ /* Draw darker outline for actual path, all line segments at once. */
+ GPU_line_width(3.0f);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_all_points);
}
- if (TRACK_VIEW_SELECTED(sc, track)) {
- GPU_point_size(3.0f);
-
- if ((curindex - a) >= 1) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_POINTS, curindex - a);
-
- for (i = a; i < curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex - 1) >= 1) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_POINTS, b - curindex - 1);
-
- for (i = curindex + 1; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
- }
+ /* Draw all points. */
+ GPU_point_size(3.0f);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_points(path, position_attribute, path_center_index, num_points_after);
+ /* Connect points with color coded segments. */
GPU_line_width(1);
+ immUniformThemeColor(TH_PATH_BEFORE);
+ draw_track_path_lines(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_AFTER);
+ draw_track_path_lines(path, position_attribute, path_center_index, num_points_after);
+
+ /* Draw all bigger points corresponding to keyframes. */
+ GPU_point_size(5.0f);
+ immUniformThemeColor(TH_PATH_KEYFRAME_BEFORE);
+ draw_track_path_keyframe_points(path, position_attribute, path_start_index, num_points_before);
+ immUniformThemeColor(TH_PATH_KEYFRAME_AFTER);
+ draw_track_path_keyframe_points(path, position_attribute, path_center_index, num_points_after);
- if ((curindex - a + 1) >= 2) {
- immUniformThemeColor(TH_PATH_BEFORE);
-
- immBegin(GPU_PRIM_LINE_STRIP, curindex - a + 1);
-
- for (i = a; i <= curindex; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
- }
-
- if ((b - curindex) >= 2) {
- immUniformThemeColor(TH_PATH_AFTER);
-
- immBegin(GPU_PRIM_LINE_STRIP, b - curindex);
-
- for (i = curindex; i < b; i++) {
- immVertex2f(pos, path[i][0], path[i][1]);
- }
-
- immEnd();
+ if (path != path_static) {
+ MEM_freeN(path);
}
immUnbindProgram();
- if (path != path_static) {
- MEM_freeN(path);
- }
#undef MAX_STATIC_PATH
}
diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h
index 1fae4c91a48..bd54d4f0016 100644
--- a/source/blender/editors/space_clip/clip_intern.h
+++ b/source/blender/editors/space_clip/clip_intern.h
@@ -94,6 +94,7 @@ void CLIP_OT_view_zoom_out(struct wmOperatorType *ot);
void CLIP_OT_view_zoom_ratio(struct wmOperatorType *ot);
void CLIP_OT_view_all(struct wmOperatorType *ot);
void CLIP_OT_view_selected(struct wmOperatorType *ot);
+void CLIP_OT_view_center_cursor(struct wmOperatorType *ot);
void CLIP_OT_change_frame(wmOperatorType *ot);
void CLIP_OT_rebuild_proxy(struct wmOperatorType *ot);
void CLIP_OT_mode_set(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index da534cf9b40..192449a219d 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -78,7 +78,9 @@
#include "clip_intern.h" // own include
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sclip_zoom_set(const bContext *C,
float zoom,
@@ -162,7 +164,11 @@ static void sclip_zoom_set_factor_exec(bContext *C, const wmEvent *event, float
ED_region_tag_redraw(ar);
}
-/******************** open clip operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Clip Operator
+ * \{ */
static void clip_filesel(bContext *C, wmOperator *op, const char *path)
{
@@ -326,7 +332,11 @@ void CLIP_OT_open(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************* reload clip operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Clip Operator
+ * \{ */
static int reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -355,7 +365,11 @@ void CLIP_OT_reload(wmOperatorType *ot)
ot->exec = reload_exec;
}
-/********************** view pan operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -376,7 +390,7 @@ static void view_pan_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -525,7 +539,11 @@ void CLIP_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float x, y;
@@ -549,7 +567,7 @@ static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
if (U.viewzoom == USER_ZOOM_CONT) {
@@ -729,7 +747,11 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
WM_operator_properties_use_cursor_init(ot);
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -845,7 +867,11 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -887,8 +913,11 @@ void CLIP_OT_view_zoom_ratio(wmOperatorType *ot)
-FLT_MAX,
FLT_MAX);
}
+/** \} */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
static int view_all_exec(bContext *C, wmOperator *op)
{
@@ -961,8 +990,41 @@ void CLIP_OT_view_all(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "fit_view", 0, "Fit View", "Fit frame to the viewport");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ clip_view_center_to_point(sc, sc->cursor[0], sc->cursor[1]);
-/********************** view selected operator *********************/
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "CLIP_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_clip_maskedit_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -992,8 +1054,11 @@ void CLIP_OT_view_selected(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+/** \} */
-/********************** change frame operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -1109,8 +1174,11 @@ void CLIP_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+/** \} */
-/********************** rebuild proxies operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Rebuild Proxies Operator
+ * \{ */
typedef struct ProxyBuildJob {
Scene *scene;
@@ -1521,8 +1589,11 @@ void CLIP_OT_rebuild_proxy(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER;
}
+/** \} */
-/********************** mode set operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Mode Set Operator
+ * \{ */
static int mode_set_exec(bContext *C, wmOperator *op)
{
@@ -1558,7 +1629,12 @@ void CLIP_OT_mode_set(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -1608,9 +1684,14 @@ void CLIP_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** Prefetch operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name Prefetch Operator
+ * \{ */
static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -1650,8 +1731,11 @@ void CLIP_OT_prefetch(wmOperatorType *ot)
ot->invoke = clip_prefetch_invoke;
ot->modal = clip_prefetch_modal;
}
+/** \} */
-/********************** Set scene frames *********************/
+/* -------------------------------------------------------------------- */
+/** \name Set Scene Frames Operator
+ * \{ */
static int clip_set_scene_frames_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1686,8 +1770,11 @@ void CLIP_OT_set_scene_frames(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
ot->exec = clip_set_scene_frames_exec;
}
+/** \} */
-/******************** set 3d cursor operator ********************/
+/* -------------------------------------------------------------------- */
+/** \name Set 3d Cursor Operator
+ * \{ */
static int clip_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
@@ -1748,7 +1835,11 @@ void CLIP_OT_cursor_set(wmOperatorType *ot)
10.0f);
}
-/********************** Toggle lock to selection operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Toggle Lock To Selection Operator
+ * \{ */
static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -1773,7 +1864,11 @@ void CLIP_OT_lock_selection_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_LOCK_BYPASS;
}
-/********************** macros *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Macros
+ * \{ */
void ED_operatormacros_clip(void)
{
@@ -1797,3 +1892,5 @@ void ED_operatormacros_clip(void)
otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_boolean_set(otmacro->ptr, "release_confirm", true);
}
+
+/** \} */
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index 2964a95648a..16305a9b17b 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -443,6 +443,7 @@ static void clip_operatortypes(void)
WM_operatortype_append(CLIP_OT_view_zoom_ratio);
WM_operatortype_append(CLIP_OT_view_all);
WM_operatortype_append(CLIP_OT_view_selected);
+ WM_operatortype_append(CLIP_OT_view_center_cursor);
WM_operatortype_append(CLIP_OT_change_frame);
WM_operatortype_append(CLIP_OT_rebuild_proxy);
WM_operatortype_append(CLIP_OT_mode_set);
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index 68198acfe52..f1bce00ea0b 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2090,7 +2090,7 @@ static int keyframe_insert_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_insert(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Insert keyframe";
+ ot->name = "Insert Keyframe";
ot->description = "Insert a keyframe to selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_insert";
@@ -2113,7 +2113,7 @@ static int keyframe_delete_exec(bContext *C, wmOperator *UNUSED(op))
void CLIP_OT_keyframe_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete keyframe";
+ ot->name = "Delete Keyframe";
ot->description = "Delete a keyframe from selected tracks at current frame";
ot->idname = "CLIP_OT_keyframe_delete";
diff --git a/source/blender/editors/space_clip/tracking_ops_solve.c b/source/blender/editors/space_clip/tracking_ops_solve.c
index 1d2fc239a89..7e2671382b9 100644
--- a/source/blender/editors/space_clip/tracking_ops_solve.c
+++ b/source/blender/editors/space_clip/tracking_ops_solve.c
@@ -118,7 +118,11 @@ static void solve_camera_freejob(void *scv)
MovieClip *clip = scj->clip;
int solved;
- WM_set_locked_interface(scj->wm, false);
+ /* WindowManager is missing in the job when initialization is incomplete.
+ * In this case the interface is not locked either. */
+ if (scj->wm != NULL) {
+ WM_set_locked_interface(scj->wm, false);
+ }
if (!scj->context) {
/* job weren't fully initialized due to some error */
diff --git a/source/blender/editors/space_clip/tracking_ops_utils.c b/source/blender/editors/space_clip/tracking_ops_utils.c
index 3970f1381bf..7579c9a49c6 100644
--- a/source/blender/editors/space_clip/tracking_ops_utils.c
+++ b/source/blender/editors/space_clip/tracking_ops_utils.c
@@ -57,11 +57,11 @@ void clip_tracking_clear_invisible_track_selection(SpaceClip *sc, MovieClip *cli
void clip_tracking_hide_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_NONE);
+ WM_cursor_set(win, WM_CURSOR_NONE);
}
void clip_tracking_show_cursor(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index f5c02dbd724..5cc2f00413a 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -149,11 +149,11 @@ static void console_main_region_init(wmWindowManager *wm, ARegion *ar)
static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index 4b86f38f8e4..b0ff67844d8 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -32,10 +32,6 @@ struct FileSelectParams;
struct SpaceFile;
struct View2D;
-/* file_ops.c */
-struct ARegion *file_tools_region(struct ScrArea *sa);
-struct ARegion *file_tool_props_region(struct ScrArea *sa);
-
/* file_draw.c */
#define TILE_BORDER_X (UI_UNIT_X / 4)
#define TILE_BORDER_Y (UI_UNIT_Y / 4)
@@ -86,7 +82,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot);
void FILE_OT_previous(struct wmOperatorType *ot);
void FILE_OT_next(struct wmOperatorType *ot);
void FILE_OT_refresh(struct wmOperatorType *ot);
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot);
void FILE_OT_filenum(struct wmOperatorType *ot);
void FILE_OT_delete(struct wmOperatorType *ot);
void FILE_OT_rename(struct wmOperatorType *ot);
@@ -112,6 +107,7 @@ void file_sfile_to_operator_ex(bContext *C,
struct SpaceFile *sfile,
char *filepath);
void file_sfile_to_operator(bContext *C, struct wmOperator *op, struct SpaceFile *sfile);
+
void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOperator *op);
/* filesel.c */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 127196cca74..3cdcc07f081 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1506,14 +1506,11 @@ void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
bool file_draw_check_exists(SpaceFile *sfile)
{
if (sfile->op) { /* fails on reload */
- PropertyRNA *prop;
- if ((prop = RNA_struct_find_property(sfile->op->ptr, "check_existing"))) {
- if (RNA_property_boolean_get(sfile->op->ptr, prop)) {
- char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
- if (BLI_is_file(filepath)) {
- return true;
- }
+ if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
+ char filepath[FILE_MAX];
+ BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
+ if (BLI_is_file(filepath)) {
+ return true;
}
}
}
@@ -2152,6 +2149,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile->params) {
+ char old_dir[sizeof(sfile->params->dir)];
+
+ BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
+
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
@@ -2185,8 +2186,10 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
- /* if directory exists, enter it immediately */
- ED_file_change_dir(C);
+ if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
+ /* if directory exists, enter it immediately */
+ ED_file_change_dir(C);
+ }
/* don't do for now because it selects entire text instead of
* placing cursor at the end */
@@ -2318,78 +2321,6 @@ void FILE_OT_hidedot(struct wmOperatorType *ot)
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
}
-ARegion *file_tools_region(ScrArea *sa)
-{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOLS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after header */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tools for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOLS;
- arnew->alignment = RGN_ALIGN_LEFT;
-
- return arnew;
-}
-
-ARegion *file_tool_props_region(ScrArea *sa)
-{
- ARegion *ar, *arnew;
-
- if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
- return ar;
- }
-
- /* add subdiv level; after execute region */
- ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE);
-
- /* is error! */
- if (ar == NULL) {
- return NULL;
- }
-
- arnew = MEM_callocN(sizeof(ARegion), "tool props for file");
- BLI_insertlinkafter(&sa->regionbase, ar, arnew);
- arnew->regiontype = RGN_TYPE_TOOL_PROPS;
- arnew->alignment = RGN_ALIGN_RIGHT;
-
- return arnew;
-}
-
-static int file_bookmark_toggle_exec(bContext *C, wmOperator *UNUSED(unused))
-{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = file_tools_region(sa);
-
- if (ar) {
- ED_region_toggle_hidden(C, ar);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void FILE_OT_bookmark_toggle(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Toggle Bookmarks";
- ot->description = "Toggle bookmarks display";
- ot->idname = "FILE_OT_bookmark_toggle";
-
- /* api callbacks */
- ot->exec = file_bookmark_toggle_exec;
- ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
-}
-
static bool file_filenum_poll(bContext *C)
{
SpaceFile *sfile = CTX_wm_space_file(C);
@@ -2398,7 +2329,7 @@ static bool file_filenum_poll(bContext *C)
return false;
}
- return sfile->params && (sfile->params->action_type == FILE_SAVE);
+ return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
}
/**
@@ -2464,60 +2395,49 @@ void FILE_OT_filenum(struct wmOperatorType *ot)
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
}
-static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
+static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
{
- ScrArea *sa = CTX_wm_area(C);
- SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
+ const int numfiles = filelist_files_ensure(sfile->files);
- if (sfile->params) {
- int idx = sfile->params->highlight_file;
- int numfiles = filelist_files_ensure(sfile->files);
- if ((0 <= idx) && (idx < numfiles)) {
- FileDirEntry *file = filelist_file(sfile->files, idx);
+ if ((file_idx >= 0) && (file_idx < numfiles)) {
+ FileDirEntry *file = filelist_file(sfile->files, file_idx);
+
+ if ((require_selected == false) ||
+ (filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) {
filelist_entry_select_index_set(
- sfile->files, idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
+ sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE);
/* We can skip the pending state,
* as we can directly set FILE_SEL_EDITING on the expected entry here. */
sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
}
+ }
+}
+
+static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+ ScrArea *sa = 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);
}
return OPERATOR_FINISHED;
}
-static bool file_rename_poll(bContext *C)
+static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
{
- bool poll = ED_operator_file_active(C);
- SpaceFile *sfile = CTX_wm_space_file(C);
-
- if (sfile && sfile->params) {
- int idx = sfile->params->highlight_file;
- int numfiles = filelist_files_ensure(sfile->files);
-
- if ((0 <= idx) && (idx < numfiles)) {
- FileDirEntry *file = filelist_file(sfile->files, idx);
- if (FILENAME_IS_CURRPAR(file->relpath)) {
- poll = false;
- }
- }
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
- if (sfile->params->highlight_file < 0) {
- poll = false;
- }
- else {
- char dir[FILE_MAX_LIBEXTRA];
- if (filelist_islibrary(sfile->files, dir, NULL)) {
- poll = false;
- }
- }
- }
- else {
- poll = false;
+ if (sfile->params) {
+ file_rename_state_activate(sfile, sfile->params->highlight_file, false);
+ ED_area_tag_redraw(sa);
}
- return poll;
+ return OPERATOR_FINISHED;
}
void FILE_OT_rename(struct wmOperatorType *ot)
@@ -2528,8 +2448,9 @@ void FILE_OT_rename(struct wmOperatorType *ot)
ot->idname = "FILE_OT_rename";
/* api callbacks */
+ ot->invoke = file_rename_invoke;
ot->exec = file_rename_exec;
- ot->poll = file_rename_poll;
+ ot->poll = ED_operator_file_active;
}
static bool file_delete_poll(bContext *C)
@@ -2573,23 +2494,29 @@ int file_delete_exec(bContext *C, wmOperator *op)
int numfiles = filelist_files_ensure(sfile->files);
int i;
+ const char *error_message = NULL;
bool report_error = false;
errno = 0;
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
file = filelist_file(sfile->files, i);
BLI_make_file_string(BKE_main_blendfile_path(bmain), str, sfile->params->dir, file->relpath);
- if (BLI_delete(str, false, false) != 0 || BLI_exists(str)) {
+ if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) {
report_error = true;
}
}
}
if (report_error) {
- BKE_reportf(op->reports,
- RPT_ERROR,
- "Could not delete file: %s",
- errno ? strerror(errno) : "unknown error");
+ if (error_message != NULL) {
+ BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message);
+ }
+ else {
+ BKE_reportf(op->reports,
+ RPT_ERROR,
+ "Could not delete file or directory: %s",
+ errno ? strerror(errno) : "unknown error");
+ }
}
ED_fileselect_clear(wm, sa, sfile);
@@ -2602,7 +2529,7 @@ void FILE_OT_delete(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Delete Selected Files";
- ot->description = "Delete selected files";
+ ot->description = "Move selected files to the trash or recycle bin";
ot->idname = "FILE_OT_delete";
/* api callbacks */
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index b0fed1fafd4..9ba098fcf45 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -110,18 +110,22 @@ void file_tool_props_region_panels_register(ARegionType *art)
BLI_addtail(&art->paneltypes, pt);
}
-static void file_panel_execution_cancel_button(uiBlock *block)
+static void file_panel_execution_cancel_button(uiLayout *layout)
{
- uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_cancel",
- WM_OP_EXEC_REGION_WIN,
- IFACE_("Cancel"),
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- "");
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ uiItemO(row, IFACE_("Cancel"), ICON_NONE, "FILE_OT_cancel");
+}
+
+static void file_panel_execution_execute_button(uiLayout *layout, const char *title)
+{
+ uiLayout *row = uiLayoutRow(layout, false);
+ uiLayoutSetScaleX(row, 0.8f);
+ uiLayoutSetFixedSize(row, true);
+ /* Just a display hint. */
+ uiLayoutSetActiveDefault(row, true);
+ uiItemO(row, title, ICON_NONE, "FILE_OT_execute");
}
static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
@@ -145,7 +149,6 @@ 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);
- uiLayoutSetScaleX(row, 1.3f);
uiLayoutSetScaleY(row, 1.3f);
/* callbacks for operator check functions */
@@ -176,7 +179,7 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
* immediate ui_apply_but_func but only after button deactivates */
UI_but_funcN_set(but, file_filename_enter_handle, NULL, but);
- if (params->action_type == FILE_SAVE) {
+ if (params->flag & FILE_CHECK_EXISTING) {
but_extra_rna_ptr = UI_but_extra_operator_icon_add(
but, "FILE_OT_filenum", WM_OP_EXEC_REGION_WIN, ICON_ADD);
RNA_int_set(but_extra_rna_ptr, "increment", 1);
@@ -192,23 +195,16 @@ static void file_panel_execution_buttons_draw(const bContext *C, Panel *pa)
UI_block_func_set(block, NULL, NULL, NULL);
{
- if (windows_layout == false) {
- file_panel_execution_cancel_button(block);
- }
- but = uiDefButO(block,
- UI_BTYPE_BUT,
- "FILE_OT_execute",
- WM_OP_EXEC_REGION_WIN,
- params->title,
- 0,
- 0,
- UI_UNIT_X,
- UI_UNIT_Y,
- "");
- /* Just a display hint. */
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
+ uiLayout *sub = uiLayoutRow(row, false);
+ uiLayoutSetOperatorContext(sub, WM_OP_EXEC_REGION_WIN);
+
if (windows_layout) {
- file_panel_execution_cancel_button(block);
+ file_panel_execution_execute_button(sub, params->title);
+ file_panel_execution_cancel_button(sub);
+ }
+ else {
+ file_panel_execution_cancel_button(sub);
+ file_panel_execution_execute_button(sub, params->title);
}
}
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index 27cccf6bab1..d29233618de 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -831,7 +831,7 @@ void filelist_setfilter_options(FileList *filelist,
}
if ((filelist->filter_data.filter != filter) || (filelist->filter_data.filter_id != filter_id)) {
filelist->filter_data.filter = filter;
- filelist->filter_data.filter_id = filter_id;
+ filelist->filter_data.filter_id = (filter & FILE_TYPE_BLENDERLIB) ? filter_id : FILTER_ID_ALL;
update = true;
}
if (!STREQ(filelist->filter_data.filter_glob, filter_glob)) {
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e54f13e9356..bb3906a961b 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -49,6 +49,8 @@
#include "BLI_utildefines.h"
#include "BLI_fnmatch.h"
+#include "BLO_readfile.h"
+
#include "BLT_translation.h"
#include "BKE_appdir.h"
@@ -101,10 +103,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
sizeof(sfile->params->dir),
sizeof(sfile->params->file));
sfile->params->filter_glob[0] = '\0';
- /* set the default thumbnails size */
- sfile->params->thumbnail_size = 128;
- /* Show size column by default. */
- sfile->params->details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME;
+ sfile->params->thumbnail_size = U_default.file_space_data.thumbnail_size;
+ sfile->params->details_flags = U_default.file_space_data.details_flags;
+ sfile->params->filter_id = U_default.file_space_data.filter_id;
}
params = sfile->params;
@@ -167,6 +168,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->flag &= ~FILE_DIRSEL_ONLY;
}
+ if ((prop = RNA_struct_find_property(op->ptr, "check_existing"))) {
+ params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_CHECK_EXISTING : 0;
+ }
if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) {
params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0;
}
@@ -241,15 +245,6 @@ short ED_fileselect_set_params(SpaceFile *sfile)
}
}
- /* For now, always init filterid to 'all true' */
- params->filter_id = FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU |
- FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS |
- FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME |
- FILTER_ID_MSK | FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA |
- FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK |
- FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO |
- FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP;
-
if (U.uiflag & USER_HIDE_DOT) {
params->flag |= FILE_HIDE_DOT;
}
@@ -271,30 +266,11 @@ short ED_fileselect_set_params(SpaceFile *sfile)
params->sort = RNA_property_enum_get(op->ptr, prop);
}
else {
- params->sort = FILE_SORT_ALPHA;
- }
-
- if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) {
- params->action_type = RNA_property_enum_get(op->ptr, prop);
+ params->sort = U_default.file_space_data.sort_type;
}
if (params->display == FILE_DEFAULTDISPLAY) {
- if (params->display_previous == FILE_DEFAULTDISPLAY) {
- if (U.uiflag & USER_SHOW_THUMBNAILS) {
- if (params->filter & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT)) {
- params->display = FILE_IMGDISPLAY;
- }
- else {
- params->display = FILE_VERTICALDISPLAY;
- }
- }
- else {
- params->display = FILE_VERTICALDISPLAY;
- }
- }
- else {
- params->display = params->display_previous;
- }
+ params->display = U_default.file_space_data.display_type;
}
if (is_relative_path) {
@@ -308,10 +284,9 @@ short ED_fileselect_set_params(SpaceFile *sfile)
else {
/* default values, if no operator */
params->type = FILE_UNIX;
- params->flag |= FILE_HIDE_DOT;
+ params->flag |= U_default.file_space_data.flag;
params->flag &= ~FILE_DIRSEL_ONLY;
params->display = FILE_VERTICALDISPLAY;
- params->display_previous = FILE_DEFAULTDISPLAY;
params->sort = FILE_SORT_ALPHA;
params->filter = 0;
params->filter_glob[0] = '\0';
@@ -347,6 +322,65 @@ short ED_fileselect_set_params(SpaceFile *sfile)
return 1;
}
+/* The subset of FileSelectParams.flag items we store into preferences. */
+#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT | FILE_SORT_INVERT)
+
+void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
+{
+ wmOperator *op = sfile->op;
+ UserDef_FileSpaceData *sfile_udata = &U.file_space_data;
+
+ ED_fileselect_set_params(sfile);
+
+ if (!op) {
+ return;
+ }
+
+ if (!RNA_struct_property_is_set(op->ptr, "display_type")) {
+ sfile->params->display = sfile_udata->display_type;
+ }
+ if (!RNA_struct_property_is_set(op->ptr, "sort_method")) {
+ sfile->params->sort = sfile_udata->sort_type;
+ }
+ sfile->params->thumbnail_size = sfile_udata->thumbnail_size;
+ sfile->params->details_flags = sfile_udata->details_flags;
+ sfile->params->filter_id = sfile_udata->filter_id;
+
+ /* Combine flags we take from params with the flags we take from userdef. */
+ sfile->params->flag = (sfile->params->flag & ~PARAMS_FLAGS_REMEMBERED) |
+ (sfile_udata->flag & PARAMS_FLAGS_REMEMBERED);
+}
+
+/**
+ * Update the user-preference data for the file space. In fact, this also contains some
+ * non-FileSelectParams data, but we can safely ignore this.
+ *
+ * \param temp_win_size: If the browser was opened in a temporary window,
+ * pass its size here so we can store that in the preferences. Otherwise NULL.
+ */
+void ED_fileselect_params_to_userdef(SpaceFile *sfile, int temp_win_size[2])
+{
+ UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
+ UserDef_FileSpaceData sfile_udata_old = U.file_space_data;
+
+ sfile_udata_new->display_type = sfile->params->display;
+ sfile_udata_new->thumbnail_size = sfile->params->thumbnail_size;
+ sfile_udata_new->sort_type = sfile->params->sort;
+ sfile_udata_new->details_flags = sfile->params->details_flags;
+ sfile_udata_new->flag = sfile->params->flag & PARAMS_FLAGS_REMEMBERED;
+ sfile_udata_new->filter_id = sfile->params->filter_id;
+
+ if (temp_win_size) {
+ sfile_udata_new->temp_win_sizex = temp_win_size[0];
+ sfile_udata_new->temp_win_sizey = temp_win_size[1];
+ }
+
+ /* Tag prefs as dirty if something has changed. */
+ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
+ U.runtime.is_dirty = true;
+ }
+}
+
void ED_fileselect_reset_params(SpaceFile *sfile)
{
sfile->params->type = FILE_UNIX;
@@ -767,7 +801,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar)
layout->tile_border_x * 2;
layout->flag = FILE_LAYOUT_HOR;
}
- params->display_previous = params->display;
layout->dirty = false;
}
@@ -924,6 +957,17 @@ void ED_fileselect_exit(wmWindowManager *wm, ScrArea *sa, SpaceFile *sfile)
return;
}
if (sfile->op) {
+ wmWindow *temp_win = WM_window_is_temp_screen(wm->winactive) ? wm->winactive : NULL;
+ int win_size[2];
+
+ if (temp_win) {
+ /* Get DPI/pixelsize independent size to be stored in preferences. */
+ WM_window_set_dpi(temp_win); /* Ensure the DPI is taken from the right window. */
+ win_size[0] = WM_window_pixels_x(temp_win) / UI_DPI_FAC;
+ win_size[1] = WM_window_pixels_y(temp_win) / UI_DPI_FAC;
+ }
+ ED_fileselect_params_to_userdef(sfile, temp_win ? win_size : NULL);
+
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = NULL;
}
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index d6a4eafc658..d63fcf402de 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -55,6 +55,40 @@
#include "filelist.h"
#include "GPU_framebuffer.h"
+static ARegion *file_execute_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE)) != NULL) {
+ return ar;
+ }
+
+ ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_EXECUTE;
+ ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->flag = RGN_FLAG_DYNAMIC_SIZE;
+
+ return ar;
+}
+
+static ARegion *file_tool_props_region_ensure(ScrArea *sa, ARegion *ar_prev)
+{
+ ARegion *ar;
+
+ if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) {
+ return ar;
+ }
+
+ /* add subdiv level; after execute region */
+ ar = MEM_callocN(sizeof(ARegion), "tool props for file");
+ BLI_insertlinkafter(&sa->regionbase, ar_prev, ar);
+ ar->regiontype = RGN_TYPE_TOOL_PROPS;
+ ar->alignment = RGN_ALIGN_RIGHT;
+
+ return ar;
+}
+
/* ******************** default callbacks for file space ***************** */
static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
@@ -72,40 +106,20 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
/* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */
ar->alignment = RGN_ALIGN_TOP;
- /* ui list region */
- ar = MEM_callocN(sizeof(ARegion), "ui region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_UI;
- ar->alignment = RGN_ALIGN_TOP;
- ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
-
/* Tools region */
ar = MEM_callocN(sizeof(ARegion), "tools region for file");
BLI_addtail(&sfile->regionbase, ar);
ar->regiontype = RGN_TYPE_TOOLS;
ar->alignment = RGN_ALIGN_LEFT;
- /* Tools region (lower split region) */
- ar = MEM_callocN(sizeof(ARegion), "lower tools region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOLS;
- ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV;
- ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
- /* Execute region */
- ar = MEM_callocN(sizeof(ARegion), "execute region for file");
+ /* ui list region */
+ ar = MEM_callocN(sizeof(ARegion), "ui region for file");
BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_EXECUTE;
- ar->alignment = RGN_ALIGN_BOTTOM;
+ ar->regiontype = RGN_TYPE_UI;
+ ar->alignment = RGN_ALIGN_TOP;
ar->flag |= RGN_FLAG_DYNAMIC_SIZE;
- /* Tool props region is added as needed. */
-#if 0
- /* Tool props (aka operator) region */
- ar = MEM_callocN(sizeof(ARegion), "tool props region for file");
- BLI_addtail(&sfile->regionbase, ar);
- ar->regiontype = RGN_TYPE_TOOL_PROPS;
- ar->alignment = RGN_ALIGN_RIGHT;
-#endif
+ /* Tool props and execute region are added as needed, see file_refresh(). */
/* main region */
ar = MEM_callocN(sizeof(ARegion), "main region for file");
@@ -218,6 +232,46 @@ static SpaceLink *file_duplicate(SpaceLink *sl)
return (SpaceLink *)sfilen;
}
+static void file_ensure_valid_region_state(bContext *C,
+ wmWindowManager *wm,
+ wmWindow *win,
+ ScrArea *sa,
+ 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);
+ 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 (params->flag & FILE_HIDE_TOOL_PROPS) {
+ ar_props->flag |= RGN_FLAG_HIDDEN;
+ }
+ else {
+ ar_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);
+
+ ED_region_remove(C, sa, ar_props);
+ ED_region_remove(C, sa, ar_execute);
+ needs_init = true;
+ }
+
+ if (needs_init) {
+ ED_area_initialize(wm, win, sa);
+ }
+}
+
static void file_refresh(const bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
@@ -287,21 +341,8 @@ static void file_refresh(const bContext *C, ScrArea *sa)
}
/* Might be called with NULL sa, see file_main_region_draw() below. */
- if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) {
- /* Create TOOLS region. */
- file_tools_region(sa);
-
- ED_area_initialize(wm, win, sa);
- }
- if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) {
- /* Create TOOL_PROPS region. */
- ARegion *region_props = file_tool_props_region(sa);
-
- if (params->flag & FILE_HIDE_TOOL_PROPS) {
- region_props->flag |= RGN_FLAG_HIDDEN;
- }
-
- ED_area_initialize(wm, win, sa);
+ if (sa) {
+ file_ensure_valid_region_state((bContext *)C, wm, win, sa, sfile, params);
}
ED_area_tag_redraw(sa);
@@ -495,7 +536,6 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_previous);
WM_operatortype_append(FILE_OT_next);
WM_operatortype_append(FILE_OT_refresh);
- WM_operatortype_append(FILE_OT_bookmark_toggle);
WM_operatortype_append(FILE_OT_bookmark_add);
WM_operatortype_append(FILE_OT_bookmark_delete);
WM_operatortype_append(FILE_OT_bookmark_cleanup);
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 708d91a82bb..33cb1cb0075 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -862,7 +862,11 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
sub = uiLayoutColumn(layout, true);
uiItemR(sub, &dtar_ptr, "transform_type", 0, NULL, ICON_NONE);
- if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) {
+ if (ELEM(dtar->transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW)) {
uiItemR(sub, &dtar_ptr, "rotation_mode", 0, IFACE_("Mode"), ICON_NONE);
}
@@ -1152,8 +1156,12 @@ static void graph_draw_driver_settings_panel(uiLayout *layout,
if ((dvar->type == DVAR_TYPE_ROT_DIFF) ||
(dvar->type == DVAR_TYPE_TRANSFORM_CHAN &&
- dvar->targets[0].transChan >= DTAR_TRANSCHAN_ROTX &&
- dvar->targets[0].transChan < DTAR_TRANSCHAN_SCALEX)) {
+ ELEM(dvar->targets[0].transChan,
+ DTAR_TRANSCHAN_ROTX,
+ DTAR_TRANSCHAN_ROTY,
+ DTAR_TRANSCHAN_ROTZ,
+ DTAR_TRANSCHAN_ROTW) &&
+ dvar->targets[0].rotation_mode != DTAR_ROTMODE_QUATERNION)) {
BLI_snprintf(
valBuf, sizeof(valBuf), "%.3f (%4.1f°)", dvar->curval, RAD2DEGF(dvar->curval));
}
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index c94f1f1d79f..42a1566629a 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -879,10 +879,6 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
float offset;
float unitfac = ANIM_unit_mapping_get_factor(ac->scene, id, fcu, mapping_flag, &offset);
- /* for now, only show when debugging driver... */
- // if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0)
- // return;
-
const uint shdr_pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 329067de545..59cf5f63de3 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -2506,28 +2506,28 @@ static const EnumPropertyItem prop_graphkeys_mirror_types[] = {
{GRAPHKEYS_MIRROR_CFRA,
"CFRA",
0,
- "By Times over Current Frame",
+ "By Times Over Current Frame",
"Flip times of selected keyframes using the current frame as the mirror line"},
{GRAPHKEYS_MIRROR_VALUE,
"VALUE",
0,
- "By Values over Cursor Value",
+ "By Values Over Cursor Value",
"Flip values of selected keyframes using the cursor value (Y/Horizontal component) as the "
"mirror line"},
{GRAPHKEYS_MIRROR_YAXIS,
"YAXIS",
0,
- "By Times over Time=0",
+ "By Times Over Time=0",
"Flip times of selected keyframes, effectively reversing the order they appear in"},
{GRAPHKEYS_MIRROR_XAXIS,
"XAXIS",
0,
- "By Values over Value=0",
+ "By Values Over Value=0",
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
{GRAPHKEYS_MIRROR_MARKER,
"MARKER",
0,
- "By Times over First Selected Marker",
+ "By Times Over First Selected Marker",
"Flip times of selected keyframes using the first selected marker as the reference point"},
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 61e6b065cba..5abcff436f1 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
)
@@ -42,6 +43,7 @@ set(SRC
image_draw.c
image_edit.c
image_ops.c
+ image_undo.c
space_image.c
image_intern.h
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index ccd0a2bfd79..ec2b1cc7fbe 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -301,6 +301,18 @@ void ED_image_mouse_pos(SpaceImage *sima, ARegion *ar, const int mval[2], float
co[1] = ((mval[1] - sy) / zoomy) / height;
}
+void ED_image_view_center_to_point(SpaceImage *sima, float x, float y)
+{
+ int width, height;
+ float aspx, aspy;
+
+ ED_space_image_get_size(sima, &width, &height);
+ ED_space_image_get_aspect(sima, &aspx, &aspy);
+
+ sima->xof = (x - 0.5f) * width * aspx;
+ sima->yof = (y - 0.5f) * height * aspy;
+}
+
void ED_image_point_pos(SpaceImage *sima, ARegion *ar, float x, float y, float *xr, float *yr)
{
int sx, sy, width, height;
@@ -476,3 +488,9 @@ bool ED_space_image_maskedit_mask_poll(bContext *C)
return false;
}
+
+bool ED_space_image_cursor_poll(bContext *C)
+{
+ return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
+}
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 1abb6715fdb..f8ce065d46c 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -44,10 +44,12 @@ void draw_image_sample_line(struct SpaceImage *sima);
/* image_ops.c */
bool space_image_main_region_poll(struct bContext *C);
+bool space_image_view_center_cursor_poll(struct bContext *C);
void IMAGE_OT_view_all(struct wmOperatorType *ot);
void IMAGE_OT_view_pan(struct wmOperatorType *ot);
void IMAGE_OT_view_selected(struct wmOperatorType *ot);
+void IMAGE_OT_view_center_cursor(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
@@ -70,6 +72,7 @@ void IMAGE_OT_pack(struct wmOperatorType *ot);
void IMAGE_OT_unpack(struct wmOperatorType *ot);
void IMAGE_OT_invert(struct wmOperatorType *ot);
+void IMAGE_OT_resize(struct wmOperatorType *ot);
void IMAGE_OT_cycle_render_slot(struct wmOperatorType *ot);
void IMAGE_OT_clear_render_slot(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index e338a450db6..a8dfad85232 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -103,7 +103,9 @@
#include "image_intern.h"
-/******************** view navigation utilities *********************/
+/* -------------------------------------------------------------------- */
+/** \name View Navigation Utilities
+ * \{ */
static void sima_zoom_set(
SpaceImage *sima, ARegion *ar, float zoom, const float location[2], const bool zoom_to_pos)
@@ -211,7 +213,7 @@ static ImageUser *image_user_from_context(const bContext *C)
}
}
-static bool image_buffer_exists_from_context(bContext *C)
+static bool image_from_context_has_data_poll(bContext *C)
{
Image *ima = image_from_context(C);
ImageUser *iuser = image_user_from_context(C);
@@ -227,6 +229,16 @@ static bool image_buffer_exists_from_context(bContext *C)
return has_buffer;
}
+/**
+ * Use this when the image buffer is accessed without the image user.
+ */
+static bool image_from_contect_has_data_poll_no_image_user(bContext *C)
+{
+ Image *ima = image_from_context(C);
+
+ return BKE_image_has_ibuf(ima, NULL);
+}
+
static bool image_not_packed_poll(bContext *C)
{
/* Do not run 'replace' on packed images, it does not give user expected results at all. */
@@ -280,7 +292,12 @@ static bool image_sample_poll(bContext *C)
return true;
}
-/********************** view pan operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Pan Operator
+ * \{ */
typedef struct ViewPanData {
float x, y;
@@ -300,7 +317,7 @@ static void image_view_pan_init(bContext *C, wmOperator *op, const wmEvent *even
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->x = event->x;
@@ -423,7 +440,11 @@ void IMAGE_OT_view_pan(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Operator
+ * \{ */
typedef struct ViewZoomData {
float origx, origy;
@@ -453,7 +474,7 @@ static void image_view_zoom_init(bContext *C, wmOperator *op, const wmEvent *eve
/* Grab will be set when running from gizmo. */
vpd->own_cursor = (win->grabcursor == 0);
if (vpd->own_cursor) {
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
vpd->origx = event->x;
@@ -671,7 +692,12 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
}
#ifdef WITH_INPUT_NDOF
-/********************** NDOF operator *********************/
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name NDOF Operator
+ * \{ */
/* Combined pan/zoom from a 3D mouse device.
* Z zooms, XY pans
@@ -721,9 +747,14 @@ void IMAGE_OT_view_ndof(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_LOCK_BYPASS;
}
+
+/** \} */
+
#endif /* WITH_INPUT_NDOF */
-/********************** view all operator *********************/
+/* -------------------------------------------------------------------- */
+/** \name View All Operator
+ * \{ */
/* Updates the fields of the View2D member of the SpaceImage struct.
* Default behavior is to reset the position of the image and set the zoom to 1
@@ -800,7 +831,41 @@ void IMAGE_OT_view_all(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************** view selected operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Center View To Cursor Operator
+ * \{ */
+
+static int view_center_cursor_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ ED_image_view_center_to_point(sima, sima->cursor[0], sima->cursor[1]);
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_view_center_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Center View to Cursor";
+ ot->description = "Center the view so that the cursor is in the middle of the view";
+ ot->idname = "IMAGE_OT_view_center_cursor";
+
+ /* api callbacks */
+ ot->exec = view_center_cursor_exec;
+ ot->poll = ED_space_image_cursor_poll;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Selected Operator
+ * \{ */
static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -866,7 +931,11 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
ot->poll = image_view_selected_poll;
}
-/********************** view zoom in/out operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom In/Out Operator
+ * \{ */
static int image_view_zoom_in_exec(bContext *C, wmOperator *op)
{
@@ -984,7 +1053,11 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN);
}
-/********************** view zoom ratio operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Zoom Ratio Operator
+ * \{ */
static int image_view_zoom_ratio_exec(bContext *C, wmOperator *op)
{
@@ -1028,7 +1101,11 @@ void IMAGE_OT_view_zoom_ratio(wmOperatorType *ot)
FLT_MAX);
}
-/********************** view border-zoom operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name View Border-Zoom Operator
+ * \{ */
static int image_view_zoom_border_exec(bContext *C, wmOperator *op)
{
@@ -1084,14 +1161,18 @@ void IMAGE_OT_view_zoom_border(wmOperatorType *ot)
WM_operator_properties_gesture_box_zoom(ot);
}
-/**************** load/replace/save callbacks ******************/
+/* load/replace/save callbacks */
static void image_filesel(bContext *C, wmOperator *op, const char *path)
{
RNA_string_set(op->ptr, "filepath", path);
WM_event_add_fileselect(C, op);
}
-/******************** open image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Open Image Operator
+ * \{ */
typedef struct ImageOpenData {
PropertyPointerRNA pprop;
@@ -1525,7 +1606,12 @@ void IMAGE_OT_open(wmOperatorType *ot)
"Automatically detect animated sequences in selected images (based on file names)");
}
-/******************** Match movie length operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Match Movie Length Operator
+ * \{ */
+
static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
@@ -1571,7 +1657,11 @@ void IMAGE_OT_match_movie_length(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_INTERNAL /* | OPTYPE_UNDO */;
}
-/******************** replace image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Replace Image Operator
+ * \{ */
static int image_replace_exec(bContext *C, wmOperator *op)
{
@@ -1656,7 +1746,11 @@ void IMAGE_OT_replace(wmOperatorType *ot)
FILE_SORT_ALPHA);
}
-/******************** save image as operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image As Operator
+ * \{ */
static char imtype_best_depth(ImBuf *ibuf, const char imtype)
{
@@ -1970,7 +2064,7 @@ static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
static bool image_save_as_poll(bContext *C)
{
- if (!image_buffer_exists_from_context(C)) {
+ if (!image_from_context_has_data_poll(C)) {
return false;
}
@@ -2021,12 +2115,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE,
FILE_SPECIAL,
FILE_SAVE,
- WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH,
+ WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
-/******************** save image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Image Operator
+ * \{ */
static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
{
@@ -2067,7 +2165,7 @@ static bool image_file_path_saveable(bContext *C, Image *ima, ImageUser *iuser)
static bool image_save_poll(bContext *C)
{
/* Can't save if there are no pixels. */
- if (image_buffer_exists_from_context(C) == false) {
+ if (image_from_context_has_data_poll(C) == false) {
return false;
}
@@ -2147,7 +2245,11 @@ void IMAGE_OT_save(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************* save sequence operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save Sequence Operator
+ * \{ */
static int image_save_sequence_exec(bContext *C, wmOperator *op)
{
@@ -2233,13 +2335,17 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_save_sequence_exec;
- ot->poll = image_buffer_exists_from_context;
+ ot->poll = image_from_context_has_data_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************** save all operator **********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Save All Operator
+ * \{ */
static bool image_should_be_saved_when_modified(Image *ima)
{
@@ -2389,7 +2495,11 @@ void IMAGE_OT_save_all_modified(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/******************** reload image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Reload Image Operator
+ * \{ */
static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -2426,7 +2536,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER; /* no undo, image buffer is not handled by undo */
}
-/********************** new image operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name New Image Operator
+ * \{ */
+
#define IMA_DEF_NAME N_("Untitled")
enum {
@@ -2642,22 +2757,18 @@ void IMAGE_OT_new(wmOperatorType *ot)
#undef IMA_DEF_NAME
-/********************* invert operators *********************/
-
-static bool image_invert_poll(bContext *C)
-{
- Image *ima = image_from_context(C);
+/** \} */
- return BKE_image_has_ibuf(ima, NULL);
-}
+/* -------------------------------------------------------------------- */
+/** \name Invert Operators
+ * \{ */
static int image_invert_exec(bContext *C, wmOperator *op)
{
Image *ima = image_from_context(C);
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
SpaceImage *sima = CTX_wm_space_image(C);
- /* undo is supported only on image paint mode currently */
- bool support_undo = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
/* flags indicate if this channel should be inverted */
const bool r = RNA_boolean_get(op->ptr, "invert_r");
@@ -2672,14 +2783,12 @@ static int image_invert_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (support_undo) {
- ED_image_undo_push_begin(op->type->name, PAINT_MODE_TEXTURE_2D);
- /* not strictly needed, because we only imapaint_dirty_region to invalidate all tiles
- * but better do this right in case someone copies this for a tool that uses partial
- * redraw better */
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ if (is_paint) {
ED_imapaint_clear_partial_redraw();
- ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y, false);
}
+
/* TODO: make this into an IMB_invert_channels(ibuf,r,g,b,a) method!? */
if (ibuf->rect_float) {
@@ -2733,9 +2842,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
ibuf->userflags |= IB_MIPMAP_INVALID;
}
- if (support_undo) {
- ED_image_undo_push_end();
- }
+ ED_image_undo_push_end();
/* force GPU reupload, all image is invalid */
GPU_free_image(ima);
@@ -2758,7 +2865,7 @@ void IMAGE_OT_invert(wmOperatorType *ot)
/* api callbacks */
ot->exec = image_invert_exec;
- ot->poll = image_invert_poll;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
/* properties */
prop = RNA_def_boolean(ot->srna, "invert_r", 0, "Red", "Invert Red Channel");
@@ -2771,10 +2878,96 @@ void IMAGE_OT_invert(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
/* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Scale Operator
+ * \{ */
+
+static int image_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ Image *ima = image_from_context(C);
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ const int size[2] = {ibuf->x, ibuf->y};
+ RNA_property_int_set_array(op->ptr, prop, size);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+ return WM_operator_props_dialog_popup(C, op, 200, 200);
+}
+
+static int image_scale_exec(bContext *C, wmOperator *op)
+{
+ Image *ima = image_from_context(C);
+ ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ const bool is_paint = ((sima != NULL) && (sima->mode == SI_MODE_PAINT));
+
+ if (ibuf == NULL) {
+ /* TODO: this should actually never happen, but does for render-results -> cleanup */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (is_paint) {
+ ED_imapaint_clear_partial_redraw();
+ }
+
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "size");
+ int size[2];
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_int_get_array(op->ptr, prop, size);
+ }
+ else {
+ size[0] = ibuf->x;
+ size[1] = ibuf->y;
+ RNA_property_int_set_array(op->ptr, prop, size);
+ }
+
+ ED_image_undo_push_begin_with_image(op->type->name, ima, ibuf);
+
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ IMB_scaleImBuf(ibuf, size[0], size[1]);
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ ED_image_undo_push_end();
+
+ /* force GPU reupload, all image is invalid */
+ GPU_free_image(ima);
+
+ DEG_id_tag_update(&ima->id, 0);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+
+ return OPERATOR_FINISHED;
}
-/********************* pack operator *********************/
+void IMAGE_OT_resize(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Resize Image";
+ ot->idname = "IMAGE_OT_resize";
+ ot->description = "Resize the image";
+
+ /* api callbacks */
+ ot->invoke = image_scale_invoke;
+ ot->exec = image_scale_exec;
+ ot->poll = image_from_contect_has_data_poll_no_image_user;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "size", 2, NULL, 1, INT_MAX, "Size", "", 1, SHRT_MAX);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pack Operator
+ * \{ */
static bool image_pack_test(bContext *C, wmOperator *op)
{
@@ -2827,7 +3020,11 @@ void IMAGE_OT_pack(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/********************* unpack operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Unpack Operator
+ * \{ */
static int image_unpack_exec(bContext *C, wmOperator *op)
{
@@ -2926,7 +3123,11 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
ot->srna, "id", NULL, MAX_ID_NAME - 2, "Image Name", "Image data-block name to unpack");
}
-/******************** sample image operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Image Operator
+ * \{ */
typedef struct ImageSampleInfo {
ARegionType *art;
@@ -3339,7 +3540,12 @@ void IMAGE_OT_sample(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/******************** sample line operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Line Operator
+ * \{ */
+
static int image_sample_line_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -3421,10 +3627,14 @@ void IMAGE_OT_sample_line(wmOperatorType *ot)
/* flags */
ot->flag = 0; /* no undo/register since this operates on the space */
- WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+ WM_operator_properties_gesture_straightline(ot, WM_CURSOR_EDIT);
}
-/******************** set curve point operator ********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Set Curve Point Operator
+ * \{ */
void IMAGE_OT_curves_point_set(wmOperatorType *ot)
{
@@ -3458,7 +3668,11 @@ void IMAGE_OT_curves_point_set(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
-/********************* cycle render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Cycle Render Slot Operator
+ * \{ */
static bool image_cycle_render_slot_poll(bContext *C)
{
@@ -3504,7 +3718,11 @@ void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "reverse", 0, "Cycle in Reverse", "");
}
-/********************* clear render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Slot Operator
+ * \{ */
static int image_clear_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3535,7 +3753,11 @@ void IMAGE_OT_clear_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* add render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Add Render Slot Operator
+ * \{ */
static int image_add_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3564,7 +3786,11 @@ void IMAGE_OT_add_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************* remove render slot operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Remove Render Slot Operator
+ * \{ */
static int image_remove_render_slot_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3595,7 +3821,11 @@ void IMAGE_OT_remove_render_slot(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
-/********************** change frame operator *********************/
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Change Frame Operator
+ * \{ */
static bool change_frame_poll(bContext *C)
{
@@ -3746,7 +3976,11 @@ void IMAGE_OT_read_viewlayers(wmOperatorType *ot)
ot->flag = 0;
}
-/* ********************* Render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Render Border Operator
+ * \{ */
static int render_border_exec(bContext *C, wmOperator *op)
{
@@ -3815,7 +4049,11 @@ void IMAGE_OT_render_border(wmOperatorType *ot)
WM_operator_properties_border(ot);
}
-/* ********************* Clear render border operator ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Clear Render Border Operator
+ * \{ */
static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -3840,3 +4078,5 @@ void IMAGE_OT_clear_render_border(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+/** \} */
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
new file mode 100644
index 00000000000..577c4e24b11
--- /dev/null
+++ b/source/blender/editors/space_image/image_undo.c
@@ -0,0 +1,1058 @@
+/*
+ * 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.
+ *
+ * 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 spimage
+ *
+ * Overview
+ * ========
+ *
+ * - Each undo step is a #ImageUndoStep
+ * - Each #ImageUndoStep stores a list of #UndoImageHandle
+ * - Each #UndoImageHandle stores a list of #UndoImageBuf
+ * (this is the undo systems equivalent of an #ImBuf).
+ * - Each #UndoImageBuf stores an array of #UndoImageTile
+ * The tiles are shared between #UndoImageBuf's to avoid duplication.
+ *
+ * When the undo system manages an image, there will always be a full copy (as a #UndoImageBuf)
+ * each new undo step only stores modified tiles.
+ */
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_threads.h"
+
+#include "DNA_image_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_context.h"
+#include "BKE_image.h"
+#include "BKE_paint.h"
+#include "BKE_undo_system.h"
+
+#include "DEG_depsgraph.h"
+
+#include "ED_paint.h"
+#include "ED_undo.h"
+#include "ED_util.h"
+#include "ED_object.h"
+
+#include "GPU_draw.h"
+
+#include "WM_api.h"
+
+static CLG_LogRef LOG = {"ed.image.undo"};
+
+/* -------------------------------------------------------------------- */
+/** \name Thread Locking
+ * \{ */
+
+/* This is a non-global static resource,
+ * Maybe it should be exposed as part of the
+ * paint operation, but for now just give a public interface */
+static SpinLock paint_tiles_lock;
+
+void ED_image_paint_tile_lock_init(void)
+{
+ BLI_spin_init(&paint_tiles_lock);
+}
+
+void ED_image_paint_tile_lock_end(void)
+{
+ BLI_spin_end(&paint_tiles_lock);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Paint Tiles
+ *
+ * Created on demand while painting,
+ * use to access the previous state for some paint operations.
+ *
+ * These buffers are also used for undo when available.
+ *
+ * \{ */
+
+static ImBuf *imbuf_alloc_temp_tile(void)
+{
+ return IMB_allocImBuf(
+ ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE, 32, IB_rectfloat | IB_rect);
+}
+
+typedef struct PaintTile {
+ struct PaintTile *next, *prev;
+ Image *image;
+ ImBuf *ibuf;
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ ushort *mask;
+ bool valid;
+ bool use_float;
+ int x, y;
+} PaintTile;
+
+static void ptile_free(PaintTile *ptile)
+{
+ if (ptile->rect.pt) {
+ MEM_freeN(ptile->rect.pt);
+ }
+ if (ptile->mask) {
+ MEM_freeN(ptile->mask);
+ }
+ MEM_freeN(ptile);
+}
+
+static void ptile_free_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first, *ptile_next; ptile; ptile = ptile_next) {
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ BLI_listbase_clear(paint_tiles);
+}
+
+static void ptile_invalidate_list(ListBase *paint_tiles)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ ptile->valid = false;
+ }
+}
+
+void *ED_image_paint_tile_find(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool validate)
+{
+ for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
+ if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->image == image && ptile->ibuf == ibuf) {
+ if (r_mask) {
+ /* allocate mask if requested. */
+ if (!ptile->mask) {
+ ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "UndoImageTile.mask");
+ }
+ *r_mask = ptile->mask;
+ }
+ if (validate) {
+ ptile->valid = true;
+ }
+ return ptile->rect.pt;
+ }
+ }
+ }
+ return NULL;
+}
+
+void *ED_image_paint_tile_push(ListBase *paint_tiles,
+ Image *image,
+ ImBuf *ibuf,
+ ImBuf **tmpibuf,
+ int x_tile,
+ int y_tile,
+ ushort **r_mask,
+ bool **r_valid,
+ bool use_thread_lock,
+ bool find_prev)
+{
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ /* check if tile is already pushed */
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (find_prev) {
+ void *data = ED_image_paint_tile_find(paint_tiles, image, ibuf, x_tile, y_tile, r_mask, true);
+ if (data) {
+ return data;
+ }
+ }
+
+ if (*tmpibuf == NULL) {
+ *tmpibuf = imbuf_alloc_temp_tile();
+ }
+
+ PaintTile *ptile = MEM_callocN(sizeof(PaintTile), "PaintTile");
+
+ ptile->image = image;
+ ptile->ibuf = ibuf;
+
+ ptile->x = x_tile;
+ ptile->y = y_tile;
+
+ /* add mask explicitly here */
+ if (r_mask) {
+ *r_mask = ptile->mask = MEM_callocN(sizeof(ushort) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.mask");
+ }
+
+ ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) *
+ SQUARE(ED_IMAGE_UNDO_TILE_SIZE),
+ "PaintTile.rect");
+
+ ptile->use_float = has_float;
+ ptile->valid = true;
+
+ if (r_valid) {
+ *r_valid = &ptile->valid;
+ }
+
+ IMB_rectcpy(*tmpibuf,
+ ibuf,
+ 0,
+ 0,
+ x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, (*tmpibuf)->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, (*tmpibuf)->rect);
+ }
+
+ if (use_thread_lock) {
+ BLI_spin_lock(&paint_tiles_lock);
+ }
+ BLI_addtail(paint_tiles, ptile);
+
+ if (use_thread_lock) {
+ BLI_spin_unlock(&paint_tiles_lock);
+ }
+ return ptile->rect.pt;
+}
+
+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) {
+ Image *image = ptile->image;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ const bool has_float = (ibuf->rect_float != NULL);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(
+ ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
+ }
+
+ GPU_free_image(image); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Tile
+ * \{ */
+
+static uint index_from_xy(uint tile_x, uint tile_y, const uint tiles_dims[2])
+{
+ BLI_assert(tile_x < tiles_dims[0] && tile_y < tiles_dims[1]);
+ return (tile_y * tiles_dims[0]) + tile_x;
+}
+
+typedef struct UndoImageTile {
+ union {
+ float *fp;
+ uint *uint;
+ void *pt;
+ } rect;
+ int users;
+} UndoImageTile;
+
+static UndoImageTile *utile_alloc(bool has_float)
+{
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "ImageUndoTile");
+ if (has_float) {
+ utile->rect.fp = MEM_mallocN(sizeof(float[4]) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ else {
+ utile->rect.uint = MEM_mallocN(sizeof(uint) * SQUARE(ED_IMAGE_UNDO_TILE_SIZE), __func__);
+ }
+ return utile;
+}
+
+static void utile_init_from_imbuf(
+ UndoImageTile *utile, const uint x, const uint y, const ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, x, y, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ if (has_float) {
+ SWAP(float *, utile->rect.fp, tmpibuf->rect_float);
+ }
+ else {
+ SWAP(uint *, utile->rect.uint, tmpibuf->rect);
+ }
+}
+
+static void utile_restore(
+ const UndoImageTile *utile, const uint x, const uint y, ImBuf *ibuf, ImBuf *tmpibuf)
+{
+ const bool has_float = ibuf->rect_float;
+ float *prev_rect_float = tmpibuf->rect_float;
+ uint *prev_rect = tmpibuf->rect;
+
+ if (has_float) {
+ tmpibuf->rect_float = utile->rect.fp;
+ }
+ else {
+ tmpibuf->rect = utile->rect.uint;
+ }
+
+ IMB_rectcpy(ibuf, tmpibuf, x, y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+
+ tmpibuf->rect_float = prev_rect_float;
+ tmpibuf->rect = prev_rect;
+}
+
+static void utile_decref(UndoImageTile *utile)
+{
+ utile->users -= 1;
+ BLI_assert(utile->users >= 0);
+ if (utile->users == 0) {
+ MEM_freeN(utile->rect.pt);
+ MEM_freeN(utile);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Buffer
+ * \{ */
+
+typedef struct UndoImageBuf {
+ struct UndoImageBuf *next, *prev;
+
+ /**
+ * The buffer after the undo step has executed.
+ */
+ struct UndoImageBuf *post;
+
+ char ibuf_name[IMB_FILENAME_SIZE];
+
+ UndoImageTile **tiles;
+
+ /** Can calculate these from dims, just for convenience. */
+ uint tiles_len;
+ uint tiles_dims[2];
+
+ uint image_dims[2];
+
+ /** Store variables from the image. */
+ struct {
+ short source;
+ bool use_float;
+ char gen_type;
+ } image_state;
+
+} UndoImageBuf;
+
+static UndoImageBuf *ubuf_from_image_no_tiles(Image *image, const ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = MEM_callocN(sizeof(*ubuf), __func__);
+
+ ubuf->image_dims[0] = ibuf->x;
+ ubuf->image_dims[1] = ibuf->y;
+
+ ubuf->tiles_dims[0] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[0]);
+ ubuf->tiles_dims[1] = ED_IMAGE_UNDO_TILE_NUMBER(ubuf->image_dims[1]);
+
+ ubuf->tiles_len = ubuf->tiles_dims[0] * ubuf->tiles_dims[1];
+ ubuf->tiles = MEM_callocN(sizeof(*ubuf->tiles) * ubuf->tiles_len, __func__);
+
+ BLI_strncpy(ubuf->ibuf_name, ibuf->name, sizeof(ubuf->ibuf_name));
+ ubuf->image_state.gen_type = image->gen_type;
+ ubuf->image_state.source = image->source;
+ ubuf->image_state.use_float = ibuf->rect_float != NULL;
+
+ return ubuf;
+}
+
+static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf)
+{
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ const bool has_float = ibuf->rect_float;
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ BLI_assert(ubuf->tiles[i] == NULL);
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile->users = 1;
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+ ubuf->tiles[i] = utile;
+
+ i += 1;
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+/** Ensure we can copy the ubuf into the ibuf. */
+static void ubuf_ensure_compat_ibuf(const UndoImageBuf *ubuf, ImBuf *ibuf)
+{
+ /* We could have both float and rect buffers,
+ * in this case free the float buffer if it's unused. */
+ if ((ibuf->rect_float != NULL) && (ubuf->image_state.use_float == false)) {
+ imb_freerectfloatImBuf(ibuf);
+ }
+
+ if (ibuf->x == ubuf->image_dims[0] && ibuf->y == ubuf->image_dims[1] &&
+ (ubuf->image_state.use_float ? (void *)ibuf->rect_float : (void *)ibuf->rect)) {
+ return;
+ }
+
+ imb_freerectImbuf_all(ibuf);
+ IMB_rect_size_set(ibuf, ubuf->image_dims);
+
+ if (ubuf->image_state.use_float) {
+ imb_addrectfloatImBuf(ibuf);
+ }
+ else {
+ imb_addrectImBuf(ibuf);
+ }
+}
+
+static void ubuf_free(UndoImageBuf *ubuf)
+{
+ UndoImageBuf *ubuf_post = ubuf->post;
+ for (uint i = 0; i < ubuf->tiles_len; i++) {
+ UndoImageTile *utile = ubuf->tiles[i];
+ utile_decref(utile);
+ }
+ MEM_freeN(ubuf->tiles);
+ MEM_freeN(ubuf);
+ if (ubuf_post) {
+ ubuf_free(ubuf_post);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Handle
+ * \{ */
+
+typedef struct UndoImageHandle {
+ struct UndoImageHandle *next, *prev;
+
+ /** Each undo handle refers to a single image which may have multiple buffers. */
+ UndoRefID_Image image_ref;
+
+ /**
+ * List of #UndoImageBuf's to support multiple buffers per image.
+ *
+ * \note To properly support multiple buffers per image
+ * we would need to store an #ImageUser for each #UndoImageBuf.
+ * since when restoring the image we use:
+ * `BKE_image_acquire_ibuf(image, NULL, NULL)`.
+ */
+ ListBase buffers;
+
+} UndoImageHandle;
+
+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) {
+ /* Tiles only added to second set of tiles. */
+ Image *image = uh->image_ref.ptr;
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (UNLIKELY(ibuf == NULL)) {
+ CLOG_ERROR(&LOG, "Unable to get buffer for image '%s'", image->id.name + 2);
+ continue;
+ }
+ bool changed = false;
+ for (UndoImageBuf *ubuf_iter = uh->buffers.first; ubuf_iter; ubuf_iter = ubuf_iter->next) {
+ UndoImageBuf *ubuf = use_init ? ubuf_iter : ubuf_iter->post;
+ ubuf_ensure_compat_ibuf(ubuf, ibuf);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+ utile_restore(ubuf->tiles[i], x, y, ibuf, tmpibuf);
+ changed = true;
+ i += 1;
+ }
+ }
+ }
+
+ if (changed) {
+ BKE_image_mark_dirty(image, ibuf);
+ GPU_free_image(image); /* force OpenGL reload */
+
+ if (ibuf->rect_float) {
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ }
+ if (ibuf->mipmap[0]) {
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mip-map recreation. */
+ }
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ DEG_id_tag_update(&image->id, 0);
+ }
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
+static void uhandle_free_list(ListBase *undo_handles)
+{
+ LISTBASE_FOREACH_MUTABLE (UndoImageHandle *, uh, undo_handles) {
+ LISTBASE_FOREACH_MUTABLE (UndoImageBuf *, ubuf, &uh->buffers) {
+ ubuf_free(ubuf);
+ }
+ MEM_freeN(uh);
+ }
+ BLI_listbase_clear(undo_handles);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Image Undo Internal Utilities
+ * \{ */
+
+/** #UndoImageHandle utilities */
+
+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) {
+ if (STREQ(ubuf->ibuf_name, ibuf_name)) {
+ return ubuf;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageBuf *uhandle_add_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ BLI_assert(uhandle_lookup_ubuf(uh, image, ibuf->name) == NULL);
+ UndoImageBuf *ubuf = ubuf_from_image_no_tiles(image, ibuf);
+ BLI_addtail(&uh->buffers, ubuf);
+
+ ubuf->post = NULL;
+
+ return ubuf;
+}
+
+static UndoImageBuf *uhandle_ensure_ubuf(UndoImageHandle *uh, Image *image, ImBuf *ibuf)
+{
+ UndoImageBuf *ubuf = uhandle_lookup_ubuf(uh, image, ibuf->name);
+ if (ubuf == NULL) {
+ ubuf = uhandle_add_ubuf(uh, image, ibuf);
+ }
+ return ubuf;
+}
+
+static UndoImageHandle *uhandle_lookup_by_name(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (STREQ(image->id.name + 2, uh->image_ref.name + 2)) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_lookup(ListBase *undo_handles, const Image *image)
+{
+ for (UndoImageHandle *uh = undo_handles->first; uh; uh = uh->next) {
+ if (image == uh->image_ref.ptr) {
+ return uh;
+ }
+ }
+ return NULL;
+}
+
+static UndoImageHandle *uhandle_add(ListBase *undo_handles, Image *image)
+{
+ BLI_assert(uhandle_lookup(undo_handles, image) == NULL);
+ UndoImageHandle *uh = MEM_callocN(sizeof(*uh), __func__);
+ uh->image_ref.ptr = image;
+ BLI_addtail(undo_handles, uh);
+ return uh;
+}
+
+static UndoImageHandle *uhandle_ensure(ListBase *undo_handles, Image *image)
+{
+ UndoImageHandle *uh = uhandle_lookup(undo_handles, image);
+ if (uh == NULL) {
+ uh = uhandle_add(undo_handles, image);
+ }
+ return uh;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Implements ED Undo System
+ * \{ */
+
+typedef struct ImageUndoStep {
+ UndoStep step;
+
+ /** #UndoImageHandle */
+ ListBase handles;
+
+ /**
+ * #PaintTile
+ * Run-time only data (active during a paint stroke).
+ */
+ ListBase paint_tiles;
+
+ bool is_encode_init;
+ ePaintMode paint_mode;
+
+} ImageUndoStep;
+
+/**
+ * Find the previous undo buffer from this one.
+ * \note We could look into undo steps even further back.
+ */
+static UndoImageBuf *ubuf_lookup_from_reference(ImageUndoStep *us_prev,
+ const Image *image,
+ const UndoImageBuf *ubuf)
+{
+ /* Use name lookup because because the pointer is cleared for previous steps. */
+ UndoImageHandle *uh_prev = uhandle_lookup_by_name(&us_prev->handles, image);
+ if (uh_prev != NULL) {
+ UndoImageBuf *ubuf_reference = uhandle_lookup_ubuf(uh_prev, image, ubuf->ibuf_name);
+ if (ubuf_reference) {
+ ubuf_reference = ubuf_reference->post;
+ if ((ubuf_reference->image_dims[0] == ubuf->image_dims[0]) &&
+ (ubuf_reference->image_dims[1] == ubuf->image_dims[1])) {
+ return ubuf_reference;
+ }
+ }
+ }
+ return NULL;
+}
+
+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;
+ if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+ return true;
+ }
+ }
+ else {
+ if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* dummy, memory is cleared anyway. */
+ us->is_encode_init = true;
+ BLI_listbase_clear(&us->handles);
+ BLI_listbase_clear(&us->paint_tiles);
+}
+
+static bool image_undosys_step_encode(struct bContext *C,
+ struct Main *UNUSED(bmain),
+ UndoStep *us_p)
+{
+ /* Encoding is done along the way by adding tiles
+ * to the current 'ImageUndoStep' added by encode_init.
+ *
+ * This function ensures there are previous and current states of the image in the undo buffer.
+ */
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+
+ BLI_assert(us->step.data_size == 0);
+
+ if (us->is_encode_init) {
+
+ ImBuf *tmpibuf = imbuf_alloc_temp_tile();
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+
+ /* Initialize undo tiles from ptiles (if they exist). */
+ for (PaintTile *ptile = us->paint_tiles.first, *ptile_next; ptile; ptile = ptile_next) {
+ if (ptile->valid) {
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, ptile->image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, ptile->image, ptile->ibuf);
+
+ UndoImageTile *utile = MEM_callocN(sizeof(*utile), "UndoImageTile");
+ utile->users = 1;
+ utile->rect.pt = ptile->rect.pt;
+ ptile->rect.pt = NULL;
+ const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+
+ BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
+ ubuf_pre->tiles[tile_index] = utile;
+ }
+ ptile_next = ptile->next;
+ ptile_free(ptile);
+ }
+ 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) {
+
+ ImBuf *ibuf = BKE_image_acquire_ibuf(uh->image_ref.ptr, NULL, NULL);
+
+ const bool has_float = ibuf->rect_float;
+
+ BLI_assert(ubuf_pre->post == NULL);
+ ubuf_pre->post = ubuf_from_image_no_tiles(uh->image_ref.ptr, ibuf);
+ UndoImageBuf *ubuf_post = ubuf_pre->post;
+
+ if (ubuf_pre->image_dims[0] != ubuf_post->image_dims[0] ||
+ ubuf_pre->image_dims[1] != ubuf_post->image_dims[1]) {
+ ubuf_from_image_all_tiles(ubuf_post, ibuf);
+ }
+ else {
+ /* Search for the previous buffer. */
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(
+ us_reference, uh->image_ref.ptr, ubuf_post) :
+ NULL);
+
+ int i = 0;
+ for (uint y_tile = 0; y_tile < ubuf_pre->tiles_dims[1]; y_tile += 1) {
+ uint y = y_tile << ED_IMAGE_UNDO_TILE_BITS;
+ for (uint x_tile = 0; x_tile < ubuf_pre->tiles_dims[0]; x_tile += 1) {
+ uint x = x_tile << ED_IMAGE_UNDO_TILE_BITS;
+
+ if ((ubuf_reference != NULL) && ((ubuf_pre->tiles[i] == NULL) ||
+ /* In this case the paint stroke as has added a tile
+ * which we have a duplicate reference available. */
+ (ubuf_pre->tiles[i]->users == 1))) {
+ if (ubuf_pre->tiles[i] != NULL) {
+ /* If we have a reference, re-use this single use tile for the post state. */
+ BLI_assert(ubuf_pre->tiles[i]->users == 1);
+ ubuf_post->tiles[i] = ubuf_pre->tiles[i];
+ ubuf_pre->tiles[i] = NULL;
+ utile_init_from_imbuf(ubuf_post->tiles[i], x, y, ibuf, tmpibuf);
+ }
+ else {
+ BLI_assert(ubuf_post->tiles[i] == NULL);
+ ubuf_post->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_post->tiles[i]->users += 1;
+ }
+ BLI_assert(ubuf_pre->tiles[i] == NULL);
+ ubuf_pre->tiles[i] = ubuf_reference->tiles[i];
+ ubuf_pre->tiles[i]->users += 1;
+
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ }
+ else {
+ UndoImageTile *utile = utile_alloc(has_float);
+ utile_init_from_imbuf(utile, x, y, ibuf, tmpibuf);
+
+ if (ubuf_pre->tiles[i] != NULL) {
+ ubuf_post->tiles[i] = utile;
+ utile->users = 1;
+ }
+ else {
+ ubuf_pre->tiles[i] = utile;
+ ubuf_post->tiles[i] = utile;
+ utile->users = 2;
+ }
+ }
+ BLI_assert(ubuf_pre->tiles[i] != NULL);
+ BLI_assert(ubuf_post->tiles[i] != NULL);
+ i += 1;
+ }
+ }
+ }
+ BKE_image_release_ibuf(uh->image_ref.ptr, ibuf, NULL);
+ }
+ }
+
+ IMB_freeImBuf(tmpibuf);
+
+ /* Useful to debug tiles are stored correctly. */
+ if (false) {
+ uhandle_restore_list(&us->handles, false);
+ }
+ }
+ else {
+ /* Happens when switching modes. */
+ ePaintMode paint_mode = BKE_paintmode_get_active_from_context(C);
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ }
+
+ us_p->is_applied = true;
+
+ return true;
+}
+
+static void image_undosys_step_decode_undo_impl(ImageUndoStep *us, bool is_final)
+{
+ BLI_assert(us->step.is_applied == true);
+ uhandle_restore_list(&us->handles, !is_final);
+ us->step.is_applied = false;
+}
+
+static void image_undosys_step_decode_redo_impl(ImageUndoStep *us)
+{
+ BLI_assert(us->step.is_applied == false);
+ uhandle_restore_list(&us->handles, false);
+ us->step.is_applied = true;
+}
+
+static void image_undosys_step_decode_undo(ImageUndoStep *us, bool is_final)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) {
+ if (us_iter->step.next->is_applied == false) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+ while (us_iter != us || (!is_final && us_iter == us)) {
+
+ image_undosys_step_decode_undo_impl(us_iter, is_final);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+}
+
+static void image_undosys_step_decode_redo(ImageUndoStep *us)
+{
+ ImageUndoStep *us_iter = us;
+ while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) {
+ if (us_iter->step.prev->is_applied == true) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.prev;
+ }
+ while (us_iter && (us_iter->step.is_applied == false)) {
+ image_undosys_step_decode_redo_impl(us_iter);
+ if (us_iter == us) {
+ break;
+ }
+ us_iter = (ImageUndoStep *)us_iter->step.next;
+ }
+}
+
+static void image_undosys_step_decode(
+ struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool is_final)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ if (dir < 0) {
+ image_undosys_step_decode_undo(us, is_final);
+ }
+ else {
+ image_undosys_step_decode_redo(us);
+ }
+
+ if (us->paint_mode == PAINT_MODE_TEXTURE_3D) {
+ ED_object_mode_set(C, OB_MODE_TEXTURE_PAINT);
+ }
+
+ /* Refresh texture slots. */
+ ED_editors_init_for_undo(bmain);
+}
+
+static void image_undosys_step_free(UndoStep *us_p)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ uhandle_free_list(&us->handles);
+
+ /* Typically this list will have been cleared. */
+ ptile_free_list(&us->paint_tiles);
+}
+
+static void image_undosys_foreach_ID_ref(UndoStep *us_p,
+ UndoTypeForEachIDRefFn foreach_ID_ref_fn,
+ void *user_data)
+{
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ for (UndoImageHandle *uh = us->handles.first; uh; uh = uh->next) {
+ foreach_ID_ref_fn(user_data, ((UndoRefID *)&uh->image_ref));
+ }
+}
+
+/* Export for ED_undo_sys. */
+void ED_image_undosys_type(UndoType *ut)
+{
+ ut->name = "Image";
+ ut->poll = image_undosys_poll;
+ ut->step_encode_init = image_undosys_step_encode_init;
+ ut->step_encode = image_undosys_step_encode;
+ ut->step_decode = image_undosys_step_decode;
+ ut->step_free = image_undosys_step_free;
+
+ ut->step_foreach_ID_ref = image_undosys_foreach_ID_ref;
+
+ ut->use_context = true;
+
+ ut->step_size = sizeof(ImageUndoStep);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utilities
+ * \{ */
+
+ListBase *ED_image_paint_tile_list_get(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ UndoStep *us_prev = ustack->step_init;
+ UndoStep *us_p = BKE_undosys_stack_init_or_active_with_type(ustack, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ /* We should always have an undo push started when accessing tiles,
+ * not doing this means we won't have paint_mode correctly set. */
+ BLI_assert(us_p == us_prev);
+ if (us_p != us_prev) {
+ /* Fallback value until we can be sure this never happens. */
+ us->paint_mode = PAINT_MODE_TEXTURE_2D;
+ }
+ return &us->paint_tiles;
+}
+
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+void ED_image_undo_restore(UndoStep *us)
+{
+ ListBase *paint_tiles = &((ImageUndoStep *)us)->paint_tiles;
+ ptile_restore_runtime_list(paint_tiles);
+ ptile_invalidate_list(paint_tiles);
+}
+
+static ImageUndoStep *image_undo_push_begin(const char *name, int paint_mode)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ bContext *C = NULL; /* special case, we never read from this. */
+ UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, name, BKE_UNDOSYS_TYPE_IMAGE);
+ ImageUndoStep *us = (ImageUndoStep *)us_p;
+ BLI_assert(ELEM(paint_mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D));
+ us->paint_mode = paint_mode;
+ return us;
+}
+
+void ED_image_undo_push_begin(const char *name, int paint_mode)
+{
+ image_undo_push_begin(name, paint_mode);
+}
+
+void ED_image_undo_push_begin_with_image(const char *name, Image *image, ImBuf *ibuf)
+{
+ ImageUndoStep *us = image_undo_push_begin(name, PAINT_MODE_TEXTURE_2D);
+
+ UndoImageHandle *uh = uhandle_ensure(&us->handles, image);
+ UndoImageBuf *ubuf_pre = uhandle_ensure_ubuf(uh, image, ibuf);
+ BLI_assert(ubuf_pre->post == NULL);
+
+ ImageUndoStep *us_reference = (ImageUndoStep *)ED_undo_stack_get()->step_active;
+ while (us_reference && us_reference->step.type != BKE_UNDOSYS_TYPE_IMAGE) {
+ us_reference = (ImageUndoStep *)us_reference->step.prev;
+ }
+ UndoImageBuf *ubuf_reference = (us_reference ?
+ ubuf_lookup_from_reference(us_reference, image, ubuf_pre) :
+ NULL);
+
+ if (ubuf_reference) {
+ memcpy(ubuf_pre->tiles, ubuf_reference->tiles, sizeof(*ubuf_pre->tiles) * ubuf_pre->tiles_len);
+ for (uint i = 0; i < ubuf_pre->tiles_len; i++) {
+ UndoImageTile *utile = ubuf_pre->tiles[i];
+ utile->users += 1;
+ }
+ }
+ else {
+ ubuf_from_image_all_tiles(ubuf_pre, ibuf);
+ }
+}
+
+void ED_image_undo_push_end(void)
+{
+ UndoStack *ustack = ED_undo_stack_get();
+ BKE_undosys_step_push(ustack, NULL, NULL);
+ 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 5fa4fe3e077..a88ecc91868 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -207,6 +207,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_view_all);
WM_operatortype_append(IMAGE_OT_view_pan);
WM_operatortype_append(IMAGE_OT_view_selected);
+ WM_operatortype_append(IMAGE_OT_view_center_cursor);
WM_operatortype_append(IMAGE_OT_view_zoom);
WM_operatortype_append(IMAGE_OT_view_zoom_in);
WM_operatortype_append(IMAGE_OT_view_zoom_out);
@@ -229,6 +230,7 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_unpack);
WM_operatortype_append(IMAGE_OT_invert);
+ WM_operatortype_append(IMAGE_OT_resize);
WM_operatortype_append(IMAGE_OT_cycle_render_slot);
WM_operatortype_append(IMAGE_OT_clear_render_slot);
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 1abf1a64263..938e7f09881 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -597,13 +597,19 @@ void NLA_OT_select_leftright(wmOperatorType *ot)
/* ******************** Mouse-Click Select Operator *********************** */
/* select strip directly under mouse */
-static void mouse_nla_strips(
- bContext *C, bAnimContext *ac, const int mval[2], short select_mode, const bool deselect_all)
+static int mouse_nla_strips(bContext *C,
+ bAnimContext *ac,
+ const int mval[2],
+ short select_mode,
+ const bool deselect_all,
+ bool wait_to_deselect_others)
{
Scene *scene = ac->scene;
bAnimListElem *ale = NULL;
NlaStrip *strip = NULL;
+ int ret_value = OPERATOR_FINISHED;
+
nlaedit_strip_at_region_position(ac, mval[0], mval[1], &ale, &strip);
/* if currently in tweakmode, exit tweakmode before changing selection states
@@ -613,6 +619,10 @@ static void mouse_nla_strips(
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
}
+ if (select_mode != SELECT_REPLACE) {
+ wait_to_deselect_others = false;
+ }
+
/* For replacing selection, if we have something to select, we have to clear existing selection.
* The same goes if we found nothing to select, and deselect_all is true
* (deselect on nothing behavior). */
@@ -620,11 +630,16 @@ static void mouse_nla_strips(
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
- /* deselect all strips */
- deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
+ if (strip && wait_to_deselect_others && (strip->flag & DESELECT_STRIPS_CLEARACTIVE)) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ /* deselect all strips */
+ deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
- /* deselect all other channels first */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ /* deselect all other channels first */
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ }
}
/* only select strip if we clicked on a valid channel and hit something */
@@ -658,14 +673,17 @@ static void mouse_nla_strips(
/* free this channel */
MEM_freeN(ale);
}
+
+ return ret_value;
}
/* ------------------- */
/* handle clicking */
-static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int nlaedit_clickselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
+ int ret_value;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -675,15 +693,19 @@ static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent
/* select mode is either replace (deselect all, then add) or add/extend */
const short selectmode = RNA_boolean_get(op->ptr, "extend") ? SELECT_INVERT : SELECT_REPLACE;
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
/* select strips based upon mouse position */
- mouse_nla_strips(C, &ac, event->mval, selectmode, deselect_all);
+ ret_value = mouse_nla_strips(C, &ac, mval, selectmode, deselect_all, wait_to_deselect_others);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_SELECTED, NULL);
/* for tweak grab to work */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value | OPERATOR_PASS_THROUGH;
}
void NLA_OT_click_select(wmOperatorType *ot)
@@ -695,14 +717,17 @@ void NLA_OT_click_select(wmOperatorType *ot)
ot->idname = "NLA_OT_click_select";
ot->description = "Handle clicks to select NLA Strips";
- /* api callbacks - absolutely no exec() this yet... */
- ot->invoke = nlaedit_clickselect_invoke;
+ /* callbacks */
ot->poll = ED_operator_nla_active;
+ ot->exec = nlaedit_clickselect_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
/* flags */
ot->flag = OPTYPE_UNDO;
/* properties */
+ WM_operator_properties_generic_select(ot);
prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 93121a6bef9..a5b18ff7589 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -47,6 +47,7 @@
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
+#include "GPU_platform.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
@@ -815,51 +816,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- PointerRNA imaptr = RNA_pointer_get(ptr, "image");
PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
- Image *ima = imaptr.data;
-
- uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
- uiTemplateID(layout,
- C,
- ptr,
- "image",
- "IMAGE_OT_new",
- "IMAGE_OT_open",
- NULL,
- UI_TEMPLATE_ID_FILTER_ALL,
- false);
-
- if (!ima) {
- return;
- }
-
- uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE);
-
- if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
- uiLayout *row = uiLayoutRow(layout, true);
- const bool is_packed = BKE_image_has_packedfile(ima);
-
- if (is_packed) {
- uiItemO(row, "", ICON_PACKAGE, "image.unpack");
- }
- else {
- uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
- }
-
- row = uiLayoutRow(row, true);
- uiLayoutSetEnabled(row, !is_packed);
- uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
- uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
- }
-
- /* multilayer? */
- if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
- uiTemplateImageLayers(layout, C, ima, iuserptr.data);
- }
- else if (ima->source != IMA_SRC_GENERATED) {
- uiTemplateImageInfo(layout, C, ima, iuserptr.data);
- }
+ 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);
diff --git a/source/blender/editors/space_node/node_add.c b/source/blender/editors/space_node/node_add.c
index 01a30f677a3..664349b3c3b 100644
--- a/source/blender/editors/space_node/node_add.c
+++ b/source/blender/editors/space_node/node_add.c
@@ -309,7 +309,7 @@ void NODE_OT_add_reroute(wmOperatorType *ot)
prop = RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_CROSSCURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_CROSS, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ****************** Add File Node Operator ******************* */
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 770e6dd2a9e..2081c69a1a4 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1456,16 +1456,16 @@ static void node_draw_hidden(const bContext *C,
int node_get_resize_cursor(int directions)
{
if (directions == 0) {
- return CURSOR_STD;
+ return WM_CURSOR_DEFAULT;
}
else if ((directions & ~(NODE_RESIZE_TOP | NODE_RESIZE_BOTTOM)) == 0) {
- return CURSOR_Y_MOVE;
+ return WM_CURSOR_Y_MOVE;
}
else if ((directions & ~(NODE_RESIZE_RIGHT | NODE_RESIZE_LEFT)) == 0) {
- return CURSOR_X_MOVE;
+ return WM_CURSOR_X_MOVE;
}
else {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
}
@@ -1474,7 +1474,7 @@ void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2])
bNodeTree *ntree = snode->edittree;
bNode *node;
bNodeSocket *sock;
- int wmcursor = CURSOR_STD;
+ int wmcursor = WM_CURSOR_DEFAULT;
if (ntree) {
if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN | SOCK_OUT)) {
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 588fc4d4307..5d020ff5ab4 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -241,6 +241,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
node->flag |= NODE_SELECT;
}
+ bNodeLink *glinks_first = ntree->links.last;
+
/* Add internal links to the ntree */
for (link = wgroup->links.first; link; link = linkn) {
linkn = link->next;
@@ -248,6 +250,8 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
BLI_addtail(&ntree->links, link);
}
+ bNodeLink *glinks_last = ntree->links.last;
+
/* and copy across the animation,
* note that the animation data's action can be NULL here */
if (wgroup->adt) {
@@ -280,70 +284,64 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode)
BKE_id_free(bmain, wgroup);
/* restore external links to and from the gnode */
- /* note: the nodes have been copied to intermediate wgroup first (so need to use new_node),
- * then transferred to ntree (new_node pointers remain valid).
- */
/* input links */
- for (link = ngroup->links.first; link; link = link->next) {
- if (link->fromnode->type == NODE_GROUP_INPUT) {
- const char *identifier = link->fromsock->identifier;
- int num_external_links = 0;
-
- /* find external links to this input */
- for (tlink = ntree->links.first; tlink; tlink = tlink->next) {
- if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
- nodeAddLink(ntree,
- tlink->fromnode,
- tlink->fromsock,
- link->tonode->new_node,
- link->tosock->new_sock);
- num_external_links++;
+ if (glinks_first != NULL) {
+ for (link = glinks_first->next; link != glinks_last->next; link = link->next) {
+ if (link->fromnode->type == NODE_GROUP_INPUT) {
+ const char *identifier = link->fromsock->identifier;
+ int num_external_links = 0;
+
+ /* find external links to this input */
+ for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) {
+ if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ num_external_links++;
+ }
}
- }
- /* if group output is not externally linked,
- * convert the constant input value to ensure somewhat consistent behavior */
- if (num_external_links == 0) {
- /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
- BLI_assert(sock);*/
+ /* if group output is not externally linked,
+ * convert the constant input value to ensure somewhat consistent behavior */
+ if (num_external_links == 0) {
+ /* XXX TODO bNodeSocket *sock = node_group_find_input_socket(gnode, identifier);
+ BLI_assert(sock);*/
- /* XXX TODO
- * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node,
- * ntree, sock, gnode);*/
+ /* XXX TODO
+ * nodeSocketCopy(ntree, link->tosock->new_sock, link->tonode->new_node,
+ * ntree, sock, gnode);*/
+ }
}
}
- }
- /* output links */
- for (link = ntree->links.first; link; link = link->next) {
- if (link->fromnode == gnode) {
- const char *identifier = link->fromsock->identifier;
- int num_internal_links = 0;
-
- /* find internal links to this output */
- for (tlink = ngroup->links.first; tlink; tlink = tlink->next) {
- /* only use active output node */
- if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
- if (STREQ(tlink->tosock->identifier, identifier)) {
- nodeAddLink(ntree,
- tlink->fromnode->new_node,
- tlink->fromsock->new_sock,
- link->tonode,
- link->tosock);
- num_internal_links++;
+ /* Also iterate over new links to cover passthrough links. */
+ glinks_last = ntree->links.last;
+
+ /* output links */
+ for (link = ntree->links.first; link != glinks_first->next; link = link->next) {
+ if (link->fromnode == gnode) {
+ const char *identifier = link->fromsock->identifier;
+ int num_internal_links = 0;
+
+ /* find internal links to this output */
+ for (tlink = glinks_first->next; tlink != glinks_last->next; tlink = tlink->next) {
+ /* only use active output node */
+ if (tlink->tonode->type == NODE_GROUP_OUTPUT && (tlink->tonode->flag & NODE_DO_OUTPUT)) {
+ if (STREQ(tlink->tosock->identifier, identifier)) {
+ nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock);
+ num_internal_links++;
+ }
}
}
- }
- /* if group output is not internally linked,
- * convert the constant output value to ensure somewhat consistent behavior */
- if (num_internal_links == 0) {
- /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
- BLI_assert(sock);*/
+ /* if group output is not internally linked,
+ * convert the constant output value to ensure somewhat consistent behavior */
+ if (num_internal_links == 0) {
+ /* XXX TODO bNodeSocket *sock = node_group_find_output_socket(gnode, identifier);
+ BLI_assert(sock);*/
- /* XXX TODO
- * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
+ /* XXX TODO
+ * nodeSocketCopy(ntree, link->tosock, link->tonode, ntree, sock, gnode); */
+ }
}
}
}
@@ -717,7 +715,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
ListBase anim_basepaths = {NULL, NULL};
float min[2], max[2], center[2];
int totselect;
- bool expose_all = false;
+ bool expose_visible = false;
bNode *input_node, *output_node;
/* XXX rough guess, not nice but we don't have access to UI constants here ... */
@@ -735,7 +733,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
/* auto-add interface for "solo" nodes */
if (totselect == 1) {
- expose_all = true;
+ expose_visible = true;
}
/* move nodes over */
@@ -879,8 +877,8 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
}
}
- /* expose all unlinked sockets too */
- if (expose_all) {
+ /* expose all unlinked sockets too but only the visible ones*/
+ if (expose_visible) {
for (node = ngroup->nodes.first; node; node = node->next) {
if (node_group_make_use_node(node, gnode)) {
for (sock = node->inputs.first; sock; sock = sock->next) {
@@ -892,6 +890,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
break;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
@@ -913,6 +914,9 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree,
skip = true;
}
}
+ if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) {
+ skip = true;
+ }
if (skip) {
continue;
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index eef3f85319c..357ef31c51f 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -1103,7 +1103,7 @@ void NODE_OT_links_cut(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
/* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+ RNA_def_int(ot->srna, "cursor", WM_CURSOR_KNIFE, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
}
/* ********************** Detach links operator ***************** */
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 450cf28cce1..e22ef389516 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -430,11 +430,9 @@ void node_select_single(bContext *C, bNode *node)
}
static int node_mouse_select(bContext *C,
+ wmOperator *op,
const int mval[2],
- const bool extend,
- const bool socket_select,
- const bool deselect_all,
- const bool wait_to_deselect_others)
+ bool wait_to_deselect_others)
{
Main *bmain = CTX_data_main(C);
SpaceNode *snode = CTX_wm_space_node(C);
@@ -445,8 +443,15 @@ static int node_mouse_select(bContext *C,
float cursor[2];
int ret_value = OPERATOR_CANCELLED;
- /* Waiting to deselect others is only allowed for basic selection. */
- BLI_assert(!(extend || socket_select) || !wait_to_deselect_others);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ /* always do socket_select when extending selection. */
+ const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
+ const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+
+ /* These cases are never modal. */
+ if (extend || socket_select) {
+ wait_to_deselect_others = false;
+ }
/* get mouse coordinates in view2d space */
UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &cursor[0], &cursor[1]);
@@ -552,115 +557,40 @@ static int node_mouse_select(bContext *C,
static int node_select_exec(bContext *C, wmOperator *op)
{
- int mval[2];
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
/* get settings from RNA properties for operator */
+ int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
/* perform the select */
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
+ const int ret_value = node_mouse_select(C, op, mval, wait_to_deselect_others);
/* allow tweak event to work too */
return ret_value | OPERATOR_PASS_THROUGH;
}
-static int node_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
-{
- const short init_event_type = (short)POINTER_AS_INT(op->customdata);
-
- /* get settings from RNA properties for operator */
- int mval[2];
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
-
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* always do socket_select when extending selection. */
- const bool socket_select = extend || RNA_boolean_get(op->ptr, "socket_select");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
-
- /* These cases are never modal. */
- if (extend || socket_select) {
- return node_select_exec(C, op);
- }
-
- if (init_event_type == 0) {
- if (event->val == KM_PRESS) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, true);
-
- op->customdata = POINTER_FROM_INT((int)event->type);
- if (ret_value & OPERATOR_RUNNING_MODAL) {
- WM_event_add_modal_handler(C, op);
- }
- return ret_value | OPERATOR_PASS_THROUGH;
- }
- else {
- /* If we are in init phase, and cannot validate init of modal operations,
- * just fall back to basic exec.
- */
- return node_select_exec(C, op);
- }
- }
- else if (event->type == init_event_type && event->val == KM_RELEASE) {
- const int ret_value = node_mouse_select(C, mval, extend, socket_select, deselect_all, false);
- return ret_value | OPERATOR_PASS_THROUGH;
- }
- else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
- const int drag_delta[2] = {
- mval[0] - event->mval[0],
- mval[1] - event->mval[1],
- };
- /* If user moves mouse more than defined threshold, we consider select operator as
- * finished. Otherwise, it is still running until we get an 'release' event. In any
- * case, we pass through event, but select op is not finished yet. */
- if (WM_event_drag_test_with_delta(event, drag_delta)) {
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
- }
- else {
- /* Important not to return anything other than PASS_THROUGH here,
- * otherwise it prevents underlying tweak detection code to work properly. */
- return OPERATOR_PASS_THROUGH;
- }
- }
-
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
-}
-
-static int node_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
- RNA_int_set(op->ptr, "mouse_x", event->mval[0]);
- RNA_int_set(op->ptr, "mouse_y", event->mval[1]);
-
- op->customdata = POINTER_FROM_INT(0);
-
- return node_select_modal(C, op, event);
-}
-
void NODE_OT_select(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Select";
ot->idname = "NODE_OT_select";
ot->description = "Select the node under the cursor";
/* api callbacks */
- ot->invoke = node_select_invoke;
ot->exec = node_select_exec;
- ot->modal = node_select_modal;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_node_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- PropertyRNA *prop;
- RNA_def_int(ot->srna, "mouse_x", 0, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "mouse_y", 0, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
+ WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", false, "Extend", "");
RNA_def_boolean(ot->srna, "socket_select", false, "Socket Select", "");
prop = RNA_def_boolean(ot->srna,
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 309446db83b..03606282fcd 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -965,7 +965,7 @@ static int collection_isolate_exec(bContext *C, wmOperator *op)
LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter);
if (extend) {
- BKE_layer_collection_isolate(scene, view_layer, layer_collection, true);
+ BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true);
}
else {
PointerRNA ptr;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index a2ca3254b30..3b86e04308e 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -2419,7 +2419,6 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case OB_GPENCIL:
data.icon = ICON_OUTLINER_OB_GREASEPENCIL;
break;
- break;
}
}
else {
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 943993cb810..c55140db46f 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -674,7 +674,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot)
PropertyRNA *prop;
/* identifiers */
- ot->name = "Outliner ID data Remap";
+ ot->name = "Outliner ID Data Remap";
ot->idname = "OUTLINER_OT_id_remap";
/* callbacks */
@@ -770,7 +770,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids);
+ BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids);
return OPERATOR_FINISHED;
}
@@ -804,7 +804,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-blocks pasted", num_pasted);
+ BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted);
return OPERATOR_FINISHED;
}
@@ -2257,7 +2257,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op)
BKE_id_multi_tagged_delete(bmain);
- BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]);
+ BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-block(s)", num_tagged[INDEX_ID_NULL]);
/* XXX: tree management normally happens from draw_outliner(), but when
* you're clicking to fast on Delete object from context menu in
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 44e67fa1508..f1e884adc3d 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -263,7 +263,8 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer,
for (base = FIRSTBASE(view_layer); base; base = base->next) {
Object *ob = base->object;
- if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) {
+ if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) &&
+ BKE_object_is_child_recursive(ob_parent, ob))) {
ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT);
}
}
@@ -1198,7 +1199,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if ((ob != NULL) && (ob->data == tselem->id)) {
Base *base = BKE_view_layer_base_find(view_layer, ob);
- if ((base != NULL) && (base->flag & BASE_VISIBLE)) {
+ if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
do_outliner_activate_obdata(C, scene, view_layer, base, extend);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index fd6a052b84d..7f7cfff12ef 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -1365,7 +1365,7 @@ static void outliner_add_layer_collection_objects(
TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0);
te_object->directdata = base;
- if (!(base->flag & BASE_VISIBLE)) {
+ if (!(base->flag & BASE_VISIBLE_DEPSGRAPH)) {
te_object->flag |= TE_DISABLED;
}
}
@@ -1398,7 +1398,7 @@ static void outliner_add_layer_collections_recursive(SpaceOutliner *soops,
tselem->flag &= ~TSE_CLOSED;
}
- if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0) {
+ if (exclude || (lc->runtime_flag & LAYER_COLLECTION_VISIBLE_VIEW_LAYER) == 0) {
ten->flag |= TE_DISABLED;
}
}
@@ -2085,12 +2085,12 @@ static bool outliner_element_visible_get(ViewLayer *view_layer,
}
if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) {
- if ((base->flag & BASE_VISIBLE) == 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
return false;
}
}
else if (exclude_filter & SO_FILTER_OB_STATE_HIDDEN) {
- if ((base->flag & BASE_VISIBLE) != 0) {
+ if ((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) {
return false;
}
}
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 79880c68120..68eea4f278b 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -229,6 +229,11 @@ static void outliner_main_region_listener(wmWindow *UNUSED(win),
ED_region_tag_redraw(ar);
}
break;
+ case NC_TEXT:
+ if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) {
+ ED_region_tag_redraw(ar);
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_script/script_edit.c b/source/blender/editors/space_script/script_edit.c
index 48248fe1dd2..2be05785d2b 100644
--- a/source/blender/editors/space_script/script_edit.c
+++ b/source/blender/editors/space_script/script_edit.c
@@ -106,6 +106,7 @@ static bool script_test_modal_operators(bContext *C)
static int script_reload_exec(bContext *C, wmOperator *op)
{
+
#ifdef WITH_PYTHON
/* clear running operators */
@@ -114,6 +115,8 @@ static int script_reload_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
+ WM_script_tag_reload();
+
/* TODO, this crashes on netrender and keying sets, need to look into why
* disable for now unless running in debug mode */
WM_cursor_wait(1);
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index b24f8e8d00f..8a15c05dd4a 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -336,7 +336,7 @@ 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_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */
seq->scene = sce_seq;
@@ -420,7 +420,7 @@ 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_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->clip = clip;
id_us_ensure_real(&seq->clip->id);
@@ -504,7 +504,7 @@ 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_ALPHAOVER;
+ seq->blend_mode = SEQ_TYPE_CROSS;
seq->mask = mask;
id_us_ensure_real(&seq->mask->id);
@@ -1091,8 +1091,14 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
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 */
+ }
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) {
+ seq->blend_mode = SEQ_TYPE_CROSS;
+ }
+ else if (seq->type == SEQ_TYPE_TEXT) {
+ seq->blend_mode = SEQ_TYPE_ALPHAOVER;
}
- seq->blend_mode = SEQ_TYPE_ALPHAOVER;
/* an unset channel is a special case where we automatically go above
* the other strips. */
@@ -1169,7 +1175,7 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot)
RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
RNA_def_float_vector(ot->srna,
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 6740c2baad2..7bec913900d 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -117,5 +117,6 @@ void sequencer_buttons_register(ARegionType *art)
pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw;
pt->flag |= PNL_DEFAULT_CLOSED;
+ pt->order = 10;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index bf555e8fe09..1a788237e6e 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -334,7 +334,7 @@ static void drawseqwave(View2D *v2d,
value2 = (1.0f - f) * value2 + f * waveform->data[p * 3 + 4];
}
- if (fcu) {
+ if (fcu && !BKE_fcurve_is_empty(fcu)) {
float evaltime = x1_offset + (i * stepsize);
volume = evaluate_fcurve(fcu, evaltime);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 22b73c32bfe..865dfb45278 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1600,6 +1600,7 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
if (success) {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
return OPERATOR_FINISHED;
}
else {
@@ -1693,6 +1694,7 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
if (sa) {
ED_area_status_text(sa, NULL);
}
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
@@ -3894,7 +3896,7 @@ void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna,
"type",
sequencer_prop_effect_types,
- SEQ_TYPE_ALPHAOVER,
+ SEQ_TYPE_CROSS,
"Type",
"Sequencer effect type");
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index affb6d3fd88..4c20fc1707a 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -319,7 +319,7 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static int sequencer_select_exec(bContext *C, wmOperator *op)
{
View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = CTX_data_scene(C);
@@ -328,7 +328,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
+ bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
int left_right = RNA_enum_get(op->ptr, "left_right");
+ int mval[2];
+ int ret_value = OPERATOR_CANCELLED;
+
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
Sequence *seq, *neighbor, *act_orig;
int hand, sel_side;
@@ -338,9 +344,13 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
return OPERATOR_CANCELLED;
}
+ if (extend) {
+ wait_to_deselect_others = false;
+ }
+
marker = find_nearest_marker(SCE_MARKERS, 1); // XXX - dummy function for now
- seq = find_nearest_seq(scene, v2d, &hand, event->mval);
+ seq = find_nearest_seq(scene, v2d, &hand, mval);
// 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)) {
@@ -364,6 +374,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
/* deselect_markers(0, 0); */
marker->flag |= SELECT;
}
+
+ ret_value = OPERATOR_FINISHED;
}
else if (left_right != SEQ_SELECT_LR_NONE) {
/* use different logic for this */
@@ -374,7 +386,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
switch (left_right) {
case SEQ_SELECT_LR_MOUSE:
- x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
+ x = UI_view2d_region_to_view_x(v2d, mval[0]);
break;
case SEQ_SELECT_LR_LEFT:
x = CFRA - 1.0f;
@@ -409,13 +421,27 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
}
+
+ ret_value = OPERATOR_FINISHED;
}
else {
act_orig = ed->act_seq;
if (seq) {
- if (!extend && !linked_handle) {
+ /* Are we trying to select a handle that's already selected? */
+ const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
+ ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
+
+ if (wait_to_deselect_others && (seq->flag & SELECT) &&
+ (hand == SEQ_SIDE_NONE || handle_selected)) {
+ ret_value = OPERATOR_RUNNING_MODAL;
+ }
+ else if (!extend && !linked_handle) {
ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
+ }
+ else {
+ ret_value = OPERATOR_FINISHED;
}
BKE_sequencer_active_set(scene, seq);
@@ -509,6 +535,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
}
}
+
+ ret_value = OPERATOR_FINISHED;
}
else {
if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
@@ -525,6 +553,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
seq->flag ^= SEQ_RIGHTSEL;
break;
}
+ ret_value = OPERATOR_FINISHED;
}
else {
seq->flag |= SELECT;
@@ -542,9 +571,12 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
if (linked_time) {
select_linked_time(ed->seqbasep, seq);
}
+
+ BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
}
else if (deselect_all) {
ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
}
}
@@ -552,8 +584,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
- /* allowing tweaks */
- return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
+ return ret_value;
}
void SEQUENCER_OT_select(wmOperatorType *ot)
@@ -565,6 +596,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
{SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
{0, NULL, 0, NULL, NULL},
};
+ PropertyRNA *prop;
/* identifiers */
ot->name = "Select";
@@ -572,14 +604,16 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
ot->description = "Select a strip (last selected becomes the \"active strip\")";
/* api callbacks */
- ot->invoke = sequencer_select_invoke;
+ ot->exec = sequencer_select_exec;
+ ot->invoke = WM_generic_select_invoke;
+ ot->modal = WM_generic_select_modal;
ot->poll = ED_operator_sequencer_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- PropertyRNA *prop;
+ WM_operator_properties_generic_select(ot);
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
prop = RNA_def_boolean(ot->srna,
"deselect_all",
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 9f39313b9ab..088f06e9da8 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -311,11 +311,11 @@ static void text_main_region_draw(const bContext *C, ARegion *ar)
static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
{
SpaceText *st = sa->spacedata.first;
- int wmcursor = BC_TEXTEDITCURSOR;
+ int wmcursor = WM_CURSOR_TEXT_EDIT;
if (st->text &&
BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
- wmcursor = CURSOR_STD;
+ wmcursor = WM_CURSOR_DEFAULT;
}
WM_cursor_set(win, wmcursor);
diff --git a/source/blender/editors/space_text/text_format_lua.c b/source/blender/editors/space_text/text_format_lua.c
index 347d46a4234..935e288c7be 100644
--- a/source/blender/editors/space_text/text_format_lua.c
+++ b/source/blender/editors/space_text/text_format_lua.c
@@ -48,7 +48,7 @@ static int txtfmt_lua_find_keyword(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "do", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "else", len)) { i = len;
@@ -66,8 +66,7 @@ static int txtfmt_lua_find_keyword(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "then", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "until", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "while", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0; }
/* clang-format on */
@@ -96,7 +95,7 @@ static int txtfmt_lua_find_specialvar(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "collectgarbage", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "dofile", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "error", len)) { i = len;
@@ -124,8 +123,7 @@ static int txtfmt_lua_find_specialvar(const char *string)
} else if (STR_LITERAL_STARTSWITH(string, "unpack", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "_VERSION", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "xpcall", len)) { i = len;
- } else { i = 0;
-}
+ } else { i = 0; }
/* clang-format on */
@@ -140,18 +138,13 @@ static int txtfmt_lua_find_bool(const char *string)
{
int i, len;
- if (STR_LITERAL_STARTSWITH(string, "nil", len)) {
- i = len;
- }
- else if (STR_LITERAL_STARTSWITH(string, "true", len)) {
- i = len;
- }
- else if (STR_LITERAL_STARTSWITH(string, "false", len)) {
- i = len;
- }
- else {
- i = 0;
- }
+ /* Keep aligned args for readability. */
+ /* clang-format off */
+
+ if (STR_LITERAL_STARTSWITH(string, "nil", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
+ } else { i = 0; }
/* clang-format on */
@@ -169,10 +162,9 @@ static char txtfmt_lua_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_lua_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_lua_find_keyword(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
- } else { fmt = FMT_TYPE_DEFAULT;
-}
+ } else { fmt = FMT_TYPE_DEFAULT; }
/* clang-format on */
diff --git a/source/blender/editors/space_text/text_format_osl.c b/source/blender/editors/space_text/text_format_osl.c
index fb9ddcb09cb..2da4488e901 100644
--- a/source/blender/editors/space_text/text_format_osl.c
+++ b/source/blender/editors/space_text/text_format_osl.c
@@ -40,7 +40,7 @@ static int txtfmt_osl_find_builtinfunc(const char *string)
/* list is from
* https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
*/
- if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "closure", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "color", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
@@ -86,7 +86,7 @@ static int txtfmt_osl_find_reserved(const char *string)
/* list is from...
* https://github.com/imageworks/OpenShadingLanguage/raw/master/src/doc/osl-languagespec.pdf
*/
- if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "bool", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "case", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "catch", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "char", len)) { i = len;
@@ -149,7 +149,7 @@ static int txtfmt_osl_find_specialvar(const char *string)
/* clang-format off */
/* OSL shader types */
- if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "shader", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "surface", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "volume", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "displacement", len)) { i = len;
@@ -189,7 +189,7 @@ static char txtfmt_osl_format_identifier(const char *str)
/* Keep aligned args for readability. */
/* clang-format off */
- if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
+ if ((txtfmt_osl_find_specialvar(str)) != -1) { fmt = FMT_TYPE_SPECIAL;
} else if ((txtfmt_osl_find_builtinfunc(str)) != -1) { fmt = FMT_TYPE_KEYWORD;
} else if ((txtfmt_osl_find_reserved(str)) != -1) { fmt = FMT_TYPE_RESERVED;
} else if ((txtfmt_osl_find_preprocessor(str)) != -1) { fmt = FMT_TYPE_DIRECTIVE;
@@ -323,7 +323,7 @@ static void txtfmt_osl_format_line(SpaceText *st, TextLine *line, const bool do_
/* Special vars(v) or built-in keywords(b) */
/* keep in sync with 'txtfmt_osl_format_identifier()' */
- if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
+ if ((i = txtfmt_osl_find_specialvar(str)) != -1) { prev = FMT_TYPE_SPECIAL;
} else if ((i = txtfmt_osl_find_builtinfunc(str)) != -1) { prev = FMT_TYPE_KEYWORD;
} else if ((i = txtfmt_osl_find_reserved(str)) != -1) { prev = FMT_TYPE_RESERVED;
} else if ((i = txtfmt_osl_find_preprocessor(str)) != -1) { prev = FMT_TYPE_DIRECTIVE;
diff --git a/source/blender/editors/space_text/text_format_pov.c b/source/blender/editors/space_text/text_format_pov.c
index a5e1a3845cf..21df7b5b76a 100644
--- a/source/blender/editors/space_text/text_format_pov.c
+++ b/source/blender/editors/space_text/text_format_pov.c
@@ -48,7 +48,7 @@ static int txtfmt_pov_find_keyword(const char *string)
int i, len;
/* Language Directives */
- if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "persistent", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "version", len)) { i = len;
@@ -101,7 +101,7 @@ static int txtfmt_pov_find_reserved_keywords(const char *string)
/* clang-format off */
/* Float Functions */
- if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "conserve_energy", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "max_intersections", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "dimension_size", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "bitwise_and", len)) { i = len;
@@ -261,7 +261,7 @@ static int txtfmt_pov_find_reserved_builtins(const char *string)
/* clang-format off */
/* Language Keywords */
- if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "reflection_exponent", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "area_illumination", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "all_intersections", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "cutaway_textures", len)) { i = len;
@@ -500,7 +500,7 @@ static int txtfmt_pov_find_specialvar(const char *string)
{
int i, len;
/* Modifiers */
- if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "dispersion_samples", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "projected_through", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "double_illuminate", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "expand_thresholds", len)) { i = len;
@@ -710,7 +710,7 @@ static int txtfmt_pov_find_bool(const char *string)
/* clang-format off */
/* Built-in Constants */
- if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "unofficial", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len;
diff --git a/source/blender/editors/space_text/text_format_pov_ini.c b/source/blender/editors/space_text/text_format_pov_ini.c
index 04f4b992cc6..b349b38e551 100644
--- a/source/blender/editors/space_text/text_format_pov_ini.c
+++ b/source/blender/editors/space_text/text_format_pov_ini.c
@@ -49,7 +49,7 @@ static int txtfmt_ini_find_keyword(const char *string)
/* clang-format off */
/* Language Directives */
- if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "deprecated", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "statistics", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "declare", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "default", len)) { i = len;
@@ -111,7 +111,7 @@ static int txtfmt_ini_find_reserved(const char *string)
* list is from...
* http://www.povray.org/documentation/view/3.7.0/212/
*/
- if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "RenderCompleteSoundEnabled", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "Create_Continue_Trace_Log", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "ParseErrorSoundEnabled", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "RenderErrorSoundEnabled", len)) { i = len;
@@ -321,7 +321,7 @@ static int txtfmt_ini_find_bool(const char *string)
/* clang-format off */
/* Built-in Constants */
- if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "false", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "no", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "off", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "true", len)) { i = len;
diff --git a/source/blender/editors/space_text/text_format_py.c b/source/blender/editors/space_text/text_format_py.c
index 98eeee61c3a..d84beb79be6 100644
--- a/source/blender/editors/space_text/text_format_py.c
+++ b/source/blender/editors/space_text/text_format_py.c
@@ -58,11 +58,11 @@ static int txtfmt_py_find_builtinfunc(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
- } else if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "assert", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "async", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "await", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "and", len)) { i = len;
+ } else if (STR_LITERAL_STARTSWITH(string, "as", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "break", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "continue", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "del", len)) { i = len;
@@ -114,7 +114,7 @@ static int txtfmt_py_find_specialvar(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "def", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "class", len)) { i = len;
} else { i = 0;
}
@@ -155,7 +155,7 @@ static int txtfmt_py_find_bool(const char *string)
/* Keep aligned args for readability. */
/* clang-format off */
- if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
+ if (STR_LITERAL_STARTSWITH(string, "None", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "True", len)) { i = len;
} else if (STR_LITERAL_STARTSWITH(string, "False", len)) { i = len;
} else { i = 0;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index caefb5070fb..f9557225b6b 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -443,6 +443,8 @@ static int text_reload_exec(bContext *C, wmOperator *op)
text_drawcache_tag_update(CTX_wm_space_text(C), 1);
WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text);
+ text->flags &= ~TXT_ISDIRTY;
+
/* return to scroll position */
st->top = orig_top;
txt_screen_clamp(st, ar);
@@ -3482,7 +3484,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
}
else {
if (!found) {
- BKE_reportf(op->reports, RPT_ERROR, "Text not found: %s", st->findstr);
+ BKE_reportf(op->reports, RPT_WARNING, "Text not found: %s", st->findstr);
}
}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index b32bb0baec9..c7f13ce0e51 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -311,13 +311,6 @@ static void view3d_free(SpaceLink *sl)
MEM_freeN(vd->runtime.properties_storage);
}
- if (vd->fx_settings.ssao) {
- MEM_freeN(vd->fx_settings.ssao);
- }
- if (vd->fx_settings.dof) {
- MEM_freeN(vd->fx_settings.dof);
- }
-
if (vd->shading.prop) {
IDP_FreeProperty(vd->shading.prop);
vd->shading.prop = NULL;
@@ -341,19 +334,20 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
v3dn->runtime.properties_storage = NULL;
}
+ v3dn->local_collections_uuid = 0;
+ v3dn->flag &= ~V3D_LOCAL_COLLECTIONS;
+
if (v3dn->shading.type == OB_RENDER) {
v3dn->shading.type = OB_SOLID;
}
+ if (v3dn->shading.prop) {
+ v3dn->shading.prop = IDP_CopyProperty(v3do->shading.prop);
+ }
+
/* copy or clear inside new stuff */
v3dn->runtime.properties_storage = NULL;
- if (v3dn->fx_settings.dof) {
- v3dn->fx_settings.dof = MEM_dupallocN(v3do->fx_settings.dof);
- }
- if (v3dn->fx_settings.ssao) {
- v3dn->fx_settings.ssao = MEM_dupallocN(v3do->fx_settings.ssao);
- }
return (SpaceLink *)v3dn;
}
@@ -577,7 +571,7 @@ static void view3d_lightcache_update(bContext *C)
Scene *scene = CTX_data_scene(C);
- if (strcmp(scene->r.engine, RE_engine_id_BLENDER_EEVEE) != 0) {
+ if (!BKE_scene_uses_blender_eevee(scene)) {
/* Only do auto bake if eevee is the active engine */
return;
}
@@ -1039,10 +1033,10 @@ static void view3d_main_region_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
if (obedit) {
- WM_cursor_set(win, CURSOR_EDIT);
+ WM_cursor_set(win, WM_CURSOR_EDIT);
}
else {
- WM_cursor_set(win, CURSOR_STD);
+ WM_cursor_set(win, WM_CURSOR_DEFAULT);
}
}
@@ -1093,6 +1087,9 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win),
if (wmn->data & ND_GPENCIL_EDITMODE) {
ED_region_tag_redraw(ar);
}
+ else if (wmn->action == NA_EDITED) {
+ ED_region_tag_redraw(ar);
+ }
break;
case NC_BRUSH:
ED_region_tag_redraw(ar);
@@ -1457,7 +1454,7 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (view_layer->basact) {
Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
- if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT)) {
+ if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 || (ob->mode & OB_MODE_EDIT)) {
CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact);
}
}
@@ -1469,7 +1466,8 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes
if (view_layer->basact) {
Object *ob = view_layer->basact->object;
/* if hidden but in edit mode, we still display, can happen with animation */
- if ((view_layer->basact->flag & BASE_VISIBLE) != 0 || (ob->mode & OB_MODE_EDIT) != 0) {
+ if ((view_layer->basact->flag & BASE_VISIBLE_DEPSGRAPH) != 0 ||
+ (ob->mode & OB_MODE_EDIT) != 0) {
CTX_data_id_pointer_set(result, &ob->id);
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index aafd36a5bb8..3ee9755cb06 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1422,18 +1422,24 @@ static void draw_grid_unit_name(
{
if (!rv3d->is_persp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
const char *grid_unit = NULL;
+ int font_id = BLF_default();
ED_view3d_grid_view_scale(scene, v3d, rv3d, &grid_unit);
if (grid_unit) {
char numstr[32] = "";
- UI_FontThemeColor(BLF_default(), TH_TEXT_HI);
+ UI_FontThemeColor(font_id, TH_TEXT_HI);
if (v3d->grid != 1.0f) {
BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid);
}
*yoffset -= U.widget_unit;
+ 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);
BLF_draw_default_ascii(
xoffset, *yoffset, 0.0f, numstr[0] ? numstr : grid_unit, sizeof(numstr));
+
+ BLF_disable(font_id, BLF_SHADOW);
}
}
}
diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c
index f77a42fb1c1..17b575cedae 100644
--- a/source/blender/editors/space_view3d/view3d_draw_legacy.c
+++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c
@@ -179,7 +179,7 @@ static void validate_object_select_id(
return;
}
- if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
+ if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
Base *base = BKE_view_layer_base_find(view_layer, obact);
DRW_select_buffer_context_create(&base, 1, -1);
}
@@ -226,7 +226,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc)
ARegion *ar = vc->ar;
Object *obact_eval = DEG_get_evaluated_object(vc->depsgraph, vc->obact);
- if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE) != 0)) {
+ if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) {
GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
DRW_draw_depth_object(vc->ar, viewport, obact_eval);
}
@@ -383,6 +383,14 @@ void ED_view3d_datamask(const bContext *C,
r_cddata_masks->lmask |= CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL;
r_cddata_masks->vmask |= CD_MASK_ORCO;
}
+ else if (v3d->shading.type == OB_SOLID) {
+ if (v3d->shading.color_type == V3D_SHADING_TEXTURE_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPUV;
+ }
+ if (v3d->shading.color_type == V3D_SHADING_VERTEX_COLOR) {
+ r_cddata_masks->lmask |= CD_MASK_MLOOPCOL;
+ }
+ }
if ((CTX_data_mode_enum(C) == CTX_MODE_EDIT_MESH) &&
(v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_WEIGHT)) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 4bc74ab8fba..3ad194a5d2b 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -2997,7 +2997,7 @@ static int viewselected_exec(bContext *C, wmOperator *op)
ok = paintface_minmax(ob_eval, min, max);
}
else if (ob_eval && (ob_eval->mode & OB_MODE_PARTICLE_EDIT)) {
- ok = PE_minmax(scene, CTX_data_view_layer(C), min, max);
+ ok = PE_minmax(depsgraph, scene, CTX_data_view_layer(C), min, max);
}
else if (ob_eval && (ob_eval->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT |
OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
index 615589347da..dbad06da5ec 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c
@@ -25,6 +25,7 @@
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DNA_object_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_camera.c b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
index 42931d5abb5..ba5ca5fbd15 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_camera.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_camera.c
@@ -24,6 +24,7 @@
#include "BKE_camera.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "DNA_object_types.h"
#include "DNA_camera_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_empty.c b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
index b37f1e41294..793aec42dcd 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_empty.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_empty.c
@@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_image.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
index 44ad1d14dba..90b1539c8a7 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_forcefield.c
@@ -21,6 +21,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DNA_object_types.h"
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_light.c b/source/blender/editors/space_view3d/view3d_gizmo_light.c
index 35677b2e4c2..890de0ae611 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_light.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_light.c
@@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_layer.h"
#include "BKE_object.h"
#include "DEG_depsgraph.h"
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 b5b924c7f4a..d6d3a3dc563 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c
@@ -518,9 +518,9 @@ static int gizmo_axis_test_select(bContext *UNUSED(C), wmGizmo *gz, const int mv
static int gizmo_axis_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part > 0) {
- return CURSOR_EDIT;
+ return WM_CURSOR_EDIT;
}
- return BC_NSEW_SCROLLCURSOR;
+ 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 2189191ad53..a5b7fac624d 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -407,6 +407,17 @@ static bool view3d_ruler_item_mousemove(RulerInfo *ruler_info,
/** \name Ruler/Grease Pencil Conversion
* \{ */
+/* Helper: Find the layer created as ruler. */
+static bGPDlayer *view3d_ruler_layer_get(bGPdata *gpd)
+{
+ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ if (gpl->flag & GP_LAYER_IS_RULER) {
+ return gpl;
+ }
+ }
+ return NULL;
+}
+
#define RULER_ID "RulerData3D"
static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
{
@@ -427,12 +438,12 @@ static bool view3d_ruler_to_gpencil(bContext *C, wmGizmoGroup *gzgroup)
}
gpd = scene->gpd;
- gpl = BLI_findstring(&gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = view3d_ruler_layer_get(gpd);
if (gpl == NULL) {
gpl = BKE_gpencil_layer_addnew(gpd, ruler_name, false);
copy_v4_v4(gpl->color, U.gpencil_new_layer_col);
gpl->thickness = 1;
- gpl->flag |= GP_LAYER_HIDE;
+ gpl->flag |= GP_LAYER_HIDE | GP_LAYER_IS_RULER;
}
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW);
@@ -485,8 +496,7 @@ static bool view3d_ruler_from_gpencil(const bContext *C, wmGizmoGroup *gzgroup)
if (scene->gpd) {
bGPDlayer *gpl;
- const char *ruler_name = RULER_ID;
- gpl = BLI_findstring(&scene->gpd->layers, ruler_name, offsetof(bGPDlayer, info));
+ gpl = view3d_ruler_layer_get(scene->gpd);
if (gpl) {
bGPDframe *gpf;
gpf = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_USE_PREV);
@@ -1013,9 +1023,9 @@ static void gizmo_ruler_exit(bContext *C, wmGizmo *gz, const bool cancel)
static int gizmo_ruler_cursor_get(wmGizmo *gz)
{
if (gz->highlight_part == PART_LINE) {
- return BC_CROSSCURSOR;
+ return WM_CURSOR_CROSS;
}
- return BC_NSEW_SCROLLCURSOR;
+ return WM_CURSOR_NSEW_SCROLL;
}
void VIEW3D_GT_ruler_item(wmGizmoType *gzt)
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index e5a145b0411..cfdd3dcbb6f 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -79,7 +79,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend");
BKE_copybuffer_save(bmain, str, op->reports);
- BKE_reportf(op->reports, RPT_INFO, "Copied %d selected objects", num_copied);
+ BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied);
return OPERATOR_FINISHED;
}
@@ -118,7 +118,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WINDOW, NULL);
- BKE_reportf(op->reports, RPT_INFO, "%d objects pasted", num_pasted);
+ BKE_reportf(op->reports, RPT_INFO, "%d object(s) pasted", num_pasted);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index bcffad454fe..3eee76277e8 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -120,13 +120,13 @@ float ED_view3d_select_dist_px(void)
}
/* TODO: should return whether there is valid context to continue */
-void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc)
+void ED_view3d_viewcontext_init(bContext *C, ViewContext *vc, Depsgraph *depsgraph)
{
memset(vc, 0, sizeof(ViewContext));
vc->C = C;
vc->ar = CTX_wm_region(C);
vc->bmain = CTX_data_main(C);
- vc->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ vc->depsgraph = depsgraph;
vc->scene = CTX_data_scene(C);
vc->view_layer = CTX_data_view_layer(C);
vc->v3d = CTX_wm_view3d(C);
@@ -1020,10 +1020,12 @@ static void do_lasso_select_armature__doSelectBone(void *userData,
is_ignore_flag |= BONESEL_TIP;
}
- 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)) {
- is_inside_flag |= BONESEL_BONE;
+ 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)) {
+ is_inside_flag |= BONESEL_BONE;
+ }
}
ebone->temp.i = is_inside_flag | (is_ignore_flag >> 16);
@@ -1344,11 +1346,12 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op)
const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ 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);
@@ -1889,6 +1892,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
/* mval comes from event->mval, only use within region handlers */
Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
Base *basact = NULL;
uint buffer[MAXPICKBUF];
@@ -1897,7 +1901,7 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
view3d_operator_needs_opengl(C);
BKE_object_update_select_id(CTX_data_main(C));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
const int hits = mixed_bones_object_selectbuffer(
@@ -1955,9 +1959,10 @@ static bool ed_object_select_pick(bContext *C,
bool enumerate,
bool object)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
@@ -3203,6 +3208,7 @@ static bool do_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const e
static int view3d_box_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
rcti rect;
bool changed_multi = false;
@@ -3214,7 +3220,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op)
BKE_object_update_select_id(CTX_data_main(C));
/* setup view context for argument to callbacks */
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
WM_operator_properties_border_to_rcti(op, &rect);
@@ -4004,6 +4010,7 @@ static bool object_circle_select(ViewContext *vc,
/* not a real operator, only for circle test */
static int view3d_circle_select_exec(bContext *C, wmOperator *op)
{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
const int radius = RNA_int_get(op->ptr, "radius");
const int mval[2] = {RNA_int_get(op->ptr, "x"), RNA_int_get(op->ptr, "y")};
@@ -4016,7 +4023,7 @@ static int view3d_circle_select_exec(bContext *C, wmOperator *op)
const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"),
WM_gesture_is_modal_first(gesture));
- ED_view3d_viewcontext_init(C, &vc);
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
Object *obact = vc.obact;
Object *obedit = vc.obedit;
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index e5e1b1297f6..d7af307bc53 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -196,8 +196,8 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for render engine draw */
- if (smooth_viewtx && v3d->shading.type != OB_RENDER) {
+ /* skip smooth viewing for external render engine draw */
+ if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
bool changed = false; /* zero means no difference */
if (sview->camera_old != sview->camera) {
@@ -508,7 +508,7 @@ static bool view3d_camera_to_view_poll(bContext *C)
void VIEW3D_OT_camera_to_view(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Align Camera To View";
+ ot->name = "Align Camera to View";
ot->description = "Set camera view to active view";
ot->idname = "VIEW3D_OT_camera_to_view";
@@ -1583,7 +1583,13 @@ static uint free_localcollection_bit(Main *bmain,
static void local_collections_reset_uuid(LayerCollection *layer_collection,
const unsigned short local_view_bit)
{
- layer_collection->local_collections_bits |= local_view_bit;
+ if (layer_collection->flag & LAYER_COLLECTION_HIDE) {
+ layer_collection->local_collections_bits &= ~local_view_bit;
+ }
+ else {
+ layer_collection->local_collections_bits |= local_view_bit;
+ }
+
LISTBASE_FOREACH (LayerCollection *, child, &layer_collection->layer_collections) {
local_collections_reset_uuid(child, local_view_bit);
}
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 91c05f5cac6..a7402a622d5 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -204,6 +204,8 @@ typedef struct WalkInfo {
* (this would need to un-key all previous frames).
*/
bool anim_playing;
+ bool need_rotation_keyframe;
+ bool need_translation_keyframe;
/** Previous 2D mouse values. */
int prev_mval[2];
@@ -538,6 +540,8 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
#endif
walk->anim_playing = ED_screen_animation_playing(wm);
+ walk->need_rotation_keyframe = false;
+ walk->need_translation_keyframe = false;
walk->time_lastdraw = PIL_check_seconds_timer();
@@ -577,7 +581,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->ar->winrct.ymin + walk->center_mval[1]);
/* remove the mouse cursor temporarily */
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
return 1;
}
@@ -930,9 +934,12 @@ static void walkMoveCamera(bContext *C,
/* we only consider autokeying on playback or if user confirmed walk on the same frame
* otherwise we get a keyframe even if the user cancels. */
const bool use_autokey = is_confirm || walk->anim_playing;
-
ED_view3d_cameracontrol_update(
walk->v3d_camera_control, use_autokey, C, do_rotate, do_translate);
+ if (use_autokey) {
+ walk->need_rotation_keyframe = false;
+ walk->need_translation_keyframe = false;
+ }
}
static float getFreeFallDistance(const float gravity, const float time)
@@ -1280,9 +1287,10 @@ static int walkApply(bContext *C, WalkInfo *walk, bool is_confirm)
add_v3_v3(rv3d->ofs, dvec_tmp);
if (rv3d->persp == RV3D_CAMOB) {
- const bool do_rotate = (moffset[0] || moffset[1]);
- const bool do_translate = (walk->speed != 0.0f);
- walkMoveCamera(C, walk, do_rotate, do_translate, is_confirm);
+ walk->need_rotation_keyframe |= (moffset[0] || moffset[1]);
+ walk->need_translation_keyframe |= (len_squared_v3(dvec_tmp) > FLT_EPSILON);
+ walkMoveCamera(
+ C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
}
}
else {
@@ -1322,7 +1330,10 @@ static void walkApply_ndof(bContext *C, WalkInfo *walk, bool is_confirm)
walk->redraw = true;
if (walk->rv3d->persp == RV3D_CAMOB) {
- walkMoveCamera(C, walk, has_rotate, has_translate, is_confirm);
+ walk->need_rotation_keyframe |= has_rotate;
+ walk->need_translation_keyframe |= has_translate;
+ walkMoveCamera(
+ C, walk, walk->need_rotation_keyframe, walk->need_translation_keyframe, is_confirm);
}
}
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index a95c7cf7456..b98c14150d5 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -2299,7 +2299,7 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if (t->options & CTX_SCULPT) {
+ if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
ED_sculpt_end_transform(C);
}
@@ -2346,9 +2346,11 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
- Object *ob = CTX_data_active_object(C);
- if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
- options |= CTX_SCULPT;
+ if (CTX_wm_view3d(C) != NULL) {
+ Object *ob = CTX_data_active_object(C);
+ if (ob && ob->mode == OB_MODE_SCULPT && ob->sculpt) {
+ options |= CTX_SCULPT;
+ }
}
t->options = options;
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index b90fff29a84..ff2afbc0cd7 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -267,7 +267,6 @@ typedef struct TransDataNla {
int handle;
} TransDataNla;
-struct GHash;
struct LinkNode;
/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 1e783e0e7b8..64ad8b2091e 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -429,7 +429,7 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
bone->flag |= BONE_TRANSFORM_CHILD;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
bone_children_clear_transflag(mode, around, &bone->childbase);
@@ -455,14 +455,14 @@ int count_set_pose_transflags(Object *ob,
bone->flag |= BONE_TRANSFORM;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
else {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
}
}
@@ -1542,8 +1542,8 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
}
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & (BONE_TRANSFORM | BONE_TRANSFORM_MIRROR)) {
-
+ 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 */
@@ -2237,9 +2237,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* Update motion paths once for all transformed bones in an object. */
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
- bool current_frame_only = canceled;
+ const ePosePathCalcRange range = canceled ? POSE_PATH_CALC_RANGE_CURRENT_FRAME :
+ POSE_PATH_CALC_RANGE_CHANGED;
ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(C, t->scene, ob, current_frame_only);
+ ED_pose_recalculate_paths(C, t->scene, ob, range);
}
BLI_gset_free(motionpath_updates, NULL);
}
@@ -2250,7 +2251,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* pass */
}
else if ((t->view_layer->basact) && (ob = t->view_layer->basact->object) &&
- (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, ob)) {
+ (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->depsgraph, t->scene, ob)) {
/* do nothing */
}
else if (t->flag & T_CURSOR) {
@@ -2320,8 +2321,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- bool current_frame_only = canceled;
- ED_objects_recalculate_paths(C, t->scene, current_frame_only);
+ const eObjectPathCalcRange range = canceled ? OBJECT_PATH_CALC_RANGE_CURRENT_FRAME :
+ OBJECT_PATH_CALC_RANGE_CHANGED;
+ ED_objects_recalculate_paths(C, t->scene, range);
}
}
@@ -2399,7 +2401,7 @@ void createTransData(bContext *C, TransInfo *t)
}
countAndCleanTransDataContainer(t);
}
- else if (t->options & CTX_SCULPT) {
+ else if ((t->options & CTX_SCULPT) && !(t->options & CTX_PAINT_CURVE)) {
createTransSculpt(t);
countAndCleanTransDataContainer(t);
}
@@ -2666,7 +2668,8 @@ void createTransData(bContext *C, TransInfo *t)
}
}
}
- else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
+ else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) &&
+ PE_start_edit(PE_get_current(t->depsgraph, scene, ob))) {
createTransParticleVerts(C, t);
countAndCleanTransDataContainer(t);
t->flag |= T_POINTS;
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index 3eb4d220cb0..f3d7592127c 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -621,10 +621,10 @@ void flushTransGraphData(TransInfo *t)
float inv_unit_scale = 1.0f / tdg->unit_scale;
- /* handle snapping for time values
- * - we should still be in NLA-mapping timespace
- * - only apply to keyframes (but never to handles)
- * - don't do this when canceling, or else these changes won't go away
+ /* Handle snapping for time values:
+ * - We should still be in NLA-mapping time-space.
+ * - Only apply to keyframes (but never to handles).
+ * - Don't do this when canceling, or else these changes won't go away.
*/
if ((t->state != TRANS_CANCEL) && (td->flag & TD_NOTIMESNAP) == 0) {
switch (sipo->autosnap) {
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 9c46094ee83..f1928433491 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -1044,7 +1044,6 @@ void trans_mesh_customdata_correction_init(TransInfo *t)
* accidentally break uv maps or vertex colors then */
(bm->shapenr <= 1) && (has_layer_math || (cd_loop_mdisp_offset != -1))) {
use_origfaces = true;
- cd_loop_mdisp_offset = cd_loop_mdisp_offset;
}
else {
use_origfaces = false;
@@ -1452,7 +1451,7 @@ void createTransUVs(bContext *C, TransInfo *t)
const bool use_facesel = (ts->uv_flag & UV_SYNC_SELECTION) == 0;
elementmap = BM_uv_element_map_create(em->bm, use_facesel, false, true);
if (elementmap == NULL) {
- return;
+ continue;
}
if (is_prop_connected) {
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 6142e9628a4..6e85f6b9bf0 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -501,8 +501,12 @@ static void set_trans_object_base_deps_flag_cb(ID *id,
static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object)
{
object->id.tag |= LIB_TAG_DOIT;
- DEG_foreach_dependent_ID_component(
- depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL);
+ DEG_foreach_dependent_ID_component(depsgraph,
+ &object->id,
+ DEG_OB_COMP_TRANSFORM,
+ DEG_FOREACH_COMPONENT_IGNORE_TRANSFORM_SOLVERS,
+ set_trans_object_base_deps_flag_cb,
+ NULL);
}
static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *view_layer)
@@ -930,11 +934,13 @@ void createTransTexspace(TransInfo *t)
normalize_m3(td->axismtx);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
- if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) {
+ if (BKE_object_obdata_texspace_get(ob, &texflag, &td->loc, &td->ext->size)) {
ob->dtx |= OB_TEXSPACE;
*texflag &= ~ME_AUTOSPACE;
}
+ zero_v3(td->ext->rot);
+
copy_v3_v3(td->iloc, td->loc);
copy_v3_v3(td->ext->irot, td->ext->rot);
copy_v3_v3(td->ext->isize, td->ext->size);
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index 3b11e604cab..2a961da018b 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -51,7 +51,7 @@ void createTransParticleVerts(bContext *C, TransInfo *t)
TransDataExtension *tx;
Object *ob = CTX_data_active_object(C);
ParticleEditSettings *pset = PE_settings(t->scene);
- PTCacheEdit *edit = PE_get_current(t->scene, ob);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, t->scene, ob);
ParticleSystem *psys = NULL;
PTCacheEditPoint *point;
PTCacheEditKey *key;
@@ -200,7 +200,7 @@ void flushTransParticles(TransInfo *t)
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(t->depsgraph, scene, ob);
ParticleSystem *psys = edit->psys;
PTCacheEditPoint *point;
PTCacheEditKey *key;
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 76f699e3dc4..2e4f4344481 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -794,6 +794,12 @@ static void pose_transform_mirror_update(Object *ob, PoseInitData_Mirror *pid)
for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
pchan_orig = pchan_orig->next) {
+ /* Clear the MIRROR flag from previous runs */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
+ for (bPoseChannel *pchan_orig = ob->pose->chanbase.first; pchan_orig;
+ pchan_orig = pchan_orig->next) {
/* no layer check, correct mirror is more important */
if (pchan_orig->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
@@ -1088,12 +1094,12 @@ static void recalcData_objects(TransInfo *t)
GSetIterator gs_iter;
GSET_ITER (gs_iter, motionpath_updates) {
Object *ob = BLI_gsetIterator_getKey(&gs_iter);
- ED_pose_recalculate_paths(t->context, t->scene, ob, true);
+ ED_pose_recalculate_paths(t->context, t->scene, ob, POSE_PATH_CALC_RANGE_CURRENT_FRAME);
}
BLI_gset_free(motionpath_updates, NULL);
}
else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) &&
- PE_get_current(t->scene, base->object)) {
+ PE_get_current(t->depsgraph, t->scene, base->object)) {
if (t->state != TRANS_CANCEL) {
applyProject(t);
}
@@ -1146,7 +1152,7 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, true);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -1707,7 +1713,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else {
- if (ISMOUSE(t->launch_event) && (U.flag & USER_RELEASECONFIRM)) {
+ /* Release confirms preference should not affect node editor (T69288, T70504). */
+ if (ISMOUSE(t->launch_event) &&
+ ((U.flag & USER_RELEASECONFIRM) || (t->spacetype == SPACE_NODE))) {
/* Global "release confirm" on mouse bindings */
t->flag |= T_RELEASE_CONFIRM;
}
@@ -1832,7 +1840,7 @@ static void freeTransCustomData(TransInfo *t, TransDataContainer *tc, TransCusto
custom_data->data = NULL;
}
/* In case modes are switched in the same transform session. */
- custom_data->free_cb = false;
+ custom_data->free_cb = NULL;
custom_data->use_free = false;
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 25cf0fbbba2..157cf96a85e 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -516,9 +516,15 @@ static void protectflag_to_drawflags(short protectflag, short *drawflags)
}
/* for pose mode */
-static void protectflag_to_drawflags_pchan(RegionView3D *rv3d, const bPoseChannel *pchan)
+static void protectflag_to_drawflags_pchan(RegionView3D *rv3d,
+ const bPoseChannel *pchan,
+ short orientation_type)
{
- protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+ /* Protect-flags apply to local space in pose mode, so only let them influence axis
+ * visibility if we show the global orientation, otherwise it's confusing. */
+ if (orientation_type == V3D_ORIENT_LOCAL) {
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+ }
}
/* for editmode*/
@@ -742,7 +748,14 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
bGPdata *gpd = CTX_data_gpencil_data(C);
const bool is_gp_edit = GPENCIL_ANY_MODE(gpd);
int a, totsel = 0;
+
const int pivot_point = scene->toolsettings->transform_pivot_point;
+ const short orientation_type = params->orientation_type ?
+ (params->orientation_type - 1) :
+ scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
+ const short orientation_index_custom =
+ params->orientation_type ? params->orientation_index_custom :
+ scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
/* transform widget matrix */
unit_m4(rv3d->twmat);
@@ -756,12 +769,6 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* global, local or normal orientation?
* if we could check 'totsel' now, this should be skipped with no selection. */
if (ob) {
- const short orientation_type = params->orientation_type ?
- (params->orientation_type - 1) :
- scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
- const short orientation_index_custom =
- params->orientation_type ? params->orientation_index_custom :
- scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
float mat[3][3];
ED_transform_calc_orientation_from_type_ex(
C, mat, scene, rv3d, ob, obedit, orientation_type, orientation_index_custom, pivot_point);
@@ -888,7 +895,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
calc_tw_center_with_matrix(tbounds, ebo->head, use_mat_local, mat_local);
totsel++;
}
- if (ebo->flag & BONE_SELECTED) {
+ if (ebo->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL)) {
protectflag_to_drawflags_ebone(rv3d, ebo);
}
}
@@ -1038,7 +1045,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
Bone *bone = pchan->bone;
if (bone && (bone->flag & BONE_TRANSFORM)) {
calc_tw_center_with_matrix(tbounds, pchan->pose_head, use_mat_local, mat_local);
- protectflag_to_drawflags_pchan(rv3d, pchan);
+ protectflag_to_drawflags_pchan(rv3d, pchan, orientation_type);
}
}
totsel += totsel_iter;
@@ -1063,7 +1070,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
}
}
else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob);
PTCacheEditPoint *point;
PTCacheEditKey *ek;
int k;
@@ -1122,7 +1129,12 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
calc_tw_center(tbounds, co);
}
}
- protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+
+ /* Protect-flags apply to world space in object mode, so only let them influence axis
+ * visibility if we show the global orientation, otherwise it's confusing. */
+ if (orientation_type == V3D_ORIENT_GLOBAL) {
+ protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+ }
totsel++;
}
@@ -1168,16 +1180,20 @@ static void gizmo_prepare_mat(const bContext *C,
if (scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) {
bGPdata *gpd = CTX_data_gpencil_data(C);
- Object *ob = OBACT(view_layer);
if (gpd && (gpd->flag & GP_DATA_STROKE_EDITMODE)) {
/* pass */
}
- else if (ob->sculpt) {
- SculptSession *ss = ob->sculpt;
- copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
- }
- else if (ob != NULL) {
- ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ else {
+ Object *ob = OBACT(view_layer);
+ if (ob != NULL) {
+ if ((ob->mode & OB_MODE_ALL_SCULPT) && ob->sculpt) {
+ SculptSession *ss = ob->sculpt;
+ copy_v3_v3(rv3d->twmat[3], ss->pivot_pos);
+ }
+ else {
+ ED_object_calc_active_center(ob, false, rv3d->twmat[3]);
+ }
+ }
}
}
break;
@@ -1293,7 +1309,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
PointerRNA toolsettings_ptr;
RNA_pointer_create(&scene->id, &RNA_ToolSettings, scene->toolsettings, &toolsettings_ptr);
- if (type_fn == VIEW3D_GGT_xform_gizmo) {
+ if (ELEM(type_fn, VIEW3D_GGT_xform_gizmo, VIEW3D_GGT_xform_shear)) {
extern PropertyRNA rna_ToolSettings_transform_pivot_point;
const PropertyRNA *props[] = {
&rna_ToolSettings_transform_pivot_point,
@@ -1334,6 +1350,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_gz_tag_refresh);
+ WM_msg_subscribe_rna_anon_prop(mbus, EditBone, lock, &msg_sub_value_gz_tag_refresh);
}
void drawDial3d(const TransInfo *t)
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index e771fe43bd8..2821277ffa0 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -389,7 +389,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
/* INPUT_VECTOR, INPUT_CUSTOM_RATIO, INPUT_CUSTOM_RATIO_FLIP */
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, BC_NSEW_SCROLLCURSOR);
+ WM_cursor_modal_set(win, WM_CURSOR_NSEW_SCROLL);
}
break;
case HLP_SPRING:
@@ -400,7 +400,7 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
case HLP_CARROW:
if (t->flag & T_MODAL) {
t->flag |= T_MODAL_CURSOR_SET;
- WM_cursor_modal_set(win, CURSOR_NONE);
+ WM_cursor_modal_set(win, WM_CURSOR_NONE);
}
break;
default:
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 1c264ba48ae..b2d8671fbce 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -302,11 +302,11 @@ static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
WM_operatortype_props_advanced_begin(ot);
RNA_def_boolean(
- ot->srna, "use", false, "Use after creation", "Select orientation after its creation");
+ ot->srna, "use", false, "Use After Creation", "Select orientation after its creation");
RNA_def_boolean(ot->srna,
"overwrite",
false,
- "Overwrite previous",
+ "Overwrite Previous",
"Overwrite previously created orientation with same name");
}
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index cbe9505d3f2..3159464072e 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -44,6 +44,7 @@
#include "BKE_curve.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 9c2642a46c1..f35a2808f22 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -47,6 +47,7 @@
#include "BKE_object.h"
#include "BKE_anim.h" /* for duplis */
#include "BKE_editmesh.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_tracking.h"
#include "BKE_context.h"
@@ -1717,7 +1718,7 @@ static short snapCurve(SnapData *snapdata,
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_texspace_get(cu, NULL, NULL, NULL);
+ BoundBox *bb = BKE_curve_boundbox_get(ob);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -2367,6 +2368,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
+ BM_mesh_elem_index_ensure(em->bm, BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_vert->tree,
lpmat,
snapdata->win_size,
@@ -2382,6 +2384,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
int last_index = nearest.index;
nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
+ BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
BLI_bvhtree_find_nearest_projected(treedata_edge->tree,
lpmat,
snapdata->win_size,
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index c2566d111cf..f5548119e0a 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -245,7 +245,7 @@ bool ED_editors_flush_edits(Main *bmain, bool for_render)
* may cause a flush on saving: T53986. */
if ((ob->sculpt && ob->sculpt->cache) == 0) {
/* flush multires changes (for sculpt) */
- multires_force_update(ob);
+ multires_flush_sculpt_updates(ob);
has_edited = true;
if (for_render) {
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index bd941968418..fafd54804c0 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -177,6 +177,7 @@ static void uvedit_get_batches(Object *ob,
float *tot_area,
float *tot_area_uv)
{
+ float *tmp_tot_area, *tmp_tot_area_uv;
int drawfaces = draw_uvs_face_check(scene->toolsettings);
const bool draw_stretch = (sima->flag & SI_DRAW_STRETCH) != 0;
const bool draw_faces = (sima->flag & SI_NO_DRAWFACES) == 0;
@@ -193,7 +194,8 @@ static void uvedit_get_batches(Object *ob,
}
if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
- batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, NULL, NULL);
+ batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_area(
+ ob->data, &tmp_tot_area, &tmp_tot_area_uv);
}
else if (draw_stretch) {
batches->faces = DRW_mesh_batch_cache_get_edituv_faces_stretch_angle(ob->data);
@@ -207,11 +209,11 @@ static void uvedit_get_batches(Object *ob,
DRW_mesh_batch_cache_create_requested(ob, ob->data, scene, false, false);
- /* after create_requested we can load the actual areas */
- float tmp_tot_area, tmp_tot_area_uv;
- DRW_mesh_batch_cache_get_edituv_faces_stretch_area(ob->data, &tmp_tot_area, &tmp_tot_area_uv);
- *tot_area += tmp_tot_area;
- *tot_area_uv += tmp_tot_area_uv;
+ if (draw_stretch && (sima->dt_uvstretch == SI_UVDT_STRETCH_AREA)) {
+ /* after create_requested we can load the actual areas */
+ *tot_area += *tmp_tot_area;
+ *tot_area_uv += *tmp_tot_area_uv;
+ }
}
static void draw_uvs_shadow(SpaceImage *UNUSED(sima),
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 57e2a84d248..0d258ba542b 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -4872,12 +4872,6 @@ static void UV_OT_reveal(wmOperatorType *ot)
/** \name Set 2D Cursor Operator
* \{ */
-static bool uv_set_2d_cursor_poll(bContext *C)
-{
- return ED_operator_uvedit_space_image(C) || ED_space_image_maskedit_poll(C) ||
- ED_space_image_paint_curve(C);
-}
-
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima = CTX_wm_space_image(C);
@@ -4923,7 +4917,7 @@ static void UV_OT_cursor_set(wmOperatorType *ot)
/* api callbacks */
ot->exec = uv_set_2d_cursor_exec;
ot->invoke = uv_set_2d_cursor_invoke;
- ot->poll = uv_set_2d_cursor_poll;
+ ot->poll = ED_space_image_cursor_poll;
/* properties */
RNA_def_float_vector(ot->srna,