diff options
Diffstat (limited to 'source/blender/editors')
100 files changed, 1587 insertions, 1064 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_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 2a35acdefcb..36583ecf060 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -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/drivers.c b/source/blender/editors/animation/drivers.c index 61c8da08954..64f7fe034dc 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -111,7 +111,7 @@ struct FCurve *alloc_driver_fcurve(const char rna_path[], 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) { 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/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 616daf94e57..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 */ diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c index 3f6db956643..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 */ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 603b0967ace..e11807d818f 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1876,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; } @@ -1883,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; 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/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 7c3aac6c688..c3e61f5f2b2 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -246,7 +246,8 @@ ScrArea *ED_screen_temp_space_open(struct bContext *C, int sizex, int sizey, eSpace_Type space_type, - int display_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/UI_resources.h b/source/blender/editors/include/UI_resources.h index 76ab4a53eb8..89579b88d24 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -283,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 f05100e9065..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) { 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_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 e0442ebcca2..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); @@ -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; } @@ -7493,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 @@ -8005,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; } @@ -9816,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 4351b75eb86..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 */ /** diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 4e56a02997b..7ce4242c697 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -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_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_widgets.c b/source/blender/editors/interface/interface_widgets.c index 9f1b11d1354..b3e039292e1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -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,9 +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 ? - CLAMPIS(mval_origin[0], rect->xmin + unit_size, rect->xmax - unit_size) : - 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 8a570933a33..99594cf0803 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; @@ -841,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/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_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 d066e9ecddc..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,7 +178,6 @@ 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, @@ -182,7 +186,8 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) }), mesh); - BM_mesh_free(bm); + BKE_editmesh_free(em); + MEM_freeN(em); if (new_mesh->totvert == 0) { BKE_mesh_free(new_mesh); @@ -196,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); } @@ -212,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_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 4636d1ee71e..cf3170b5446 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -2044,11 +2044,7 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) } if (tot_failed_all != 0) { - BKE_reportf(op->reports, - RPT_WARNING, - tot_failed_all == 1 ? "Unable to rotate %d edge" : - "Unable to rotate %d edges", - tot_failed_all); + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed_all); } return OPERATOR_FINISHED; @@ -3165,11 +3161,7 @@ static int edbm_remove_doubles_exec(bContext *C, wmOperator *op) } MEM_freeN(objects); - BKE_reportf(op->reports, - RPT_INFO, - count_multi == 1 ? "Removed %d vertex" : - "Removed %d vertices", - count_multi); + BKE_reportf(op->reports, RPT_INFO, "Removed %d vertice(s)", count_multi); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index 569994bead1..a0d424e083c 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); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index d6816ddbe73..bdb23c5ce6f 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); @@ -1581,11 +1581,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) } CTX_DATA_END; - BKE_reportf(op->reports, - RPT_INFO, - changed_count == 1 ? "Deleted %u object" : - "Deleted %u objects", - changed_count); + BKE_reportf(op->reports, RPT_INFO, "Deleted %u object(s)", changed_count); if (changed_count == 0) { return OPERATOR_CANCELLED; @@ -2149,6 +2145,7 @@ static int convert_exec(bContext *C, wmOperator *op) const short target = RNA_enum_get(op->ptr, "target"); bool keep_original = RNA_boolean_get(op->ptr, "keep_original"); int a, mballConverted = 0; + bool gpencilConverted = false; /* don't forget multiple users! */ @@ -2389,20 +2386,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; } } } @@ -2502,6 +2499,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); @@ -2580,7 +2588,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_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_edit.c b/source/blender/editors/object/object_edit.c index 4759a3cb0db..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); @@ -1547,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_relations.c b/source/blender/editors/object/object_relations.c index d56791e5da0..c030c551374 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2051,7 +2051,7 @@ void ED_object_single_users(Main *bmain, 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 reguarding drivers and custom props, see T66641. + * 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. diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 2c05ae14f2e..35762c5861e 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -92,6 +92,12 @@ static bool object_remesh_poll(bContext *C) 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); } @@ -111,8 +117,13 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) ED_sculpt_undo_geometry_begin(ob); } + 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); + mesh, mesh->remesh_voxel_size, mesh->remesh_voxel_adaptivity, isovalue); if (!new_mesh) { return OPERATOR_CANCELLED; @@ -204,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; @@ -320,6 +382,12 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update 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); @@ -390,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; } } @@ -602,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"); @@ -628,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/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 2ea0e9dc018..3978f7ba3b5 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3076,11 +3076,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_reportf(op->reports, - RPT_INFO, - totremoved == 1 ? "Removed %d double particle" : - "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); 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 6873495e962..a54701f8725 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -156,8 +156,8 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } /* changes context! */ - if (WM_window_open_temp(C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE) == - 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; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index c068fbdf7cb..9957fe0515c 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -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/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 316604156de..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" diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c8008fe3cc7..bbdddfadc30 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1375,13 +1375,14 @@ ScrArea *ED_screen_temp_space_open(bContext *C, int sizex, int sizey, eSpace_Type space_type, - int display_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)) { + if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) { sa = CTX_wm_area(C); } break; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 0b374617cce..cc1f53eabde 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3946,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); @@ -4828,9 +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, IFACE_("Blender Preferences"), event->x, event->y, sizex, sizey, SPACE_USERPREF) != - 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); @@ -4879,9 +4884,14 @@ 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, IFACE_("Blender Drivers Editor"), event->x, event->y, sizex, sizey, SPACE_GRAPH) != - 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 */ @@ -4939,9 +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, IFACE_("Blender Info Log"), event->x, event->y + shift_y, sizex, sizey, SPACE_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/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 774d4ef09b1..c59ab6279cd 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -410,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; @@ -1359,13 +1359,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) 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 & BRUSH_AIRBRUSH)); + 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 ((mode == PAINT_MODE_SCULPT) && ss && !(brush->falloff_shape & BRUSH_AIRBRUSH)) { + if ((mode == PAINT_MODE_SCULPT) && ss && + (brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE)) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; if (!ups->stroke_active) { @@ -1393,7 +1394,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) } /* Draw pose brush origin */ - if (brush->sculpt_tool == SCULPT_TOOL_POSE && !is_multires) { + 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); @@ -1439,14 +1440,14 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) 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->modifiers_active) { + 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 && !is_multires) { + 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); @@ -1492,7 +1493,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) /* 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->modifiers_active) { + 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), diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 24c2dfb6c6b..b4388f6c324 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -540,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) { diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 4f1ae10aa62..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) { diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 69eed84fe2b..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; diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index a93e55685d2..d160fba4013 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -166,9 +166,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .value = value, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); @@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .clip_planes_final = clip_planes_final, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { MEM_freeN(nodes); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index d8be345cc84..36418045551 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -256,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; @@ -668,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); } } @@ -909,16 +910,21 @@ PaintStroke *paint_stroke_new(bContext *C, 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; - UnifiedPaintSettings *ups = stroke->ups; + if (stroke == NULL) { + return; + } + UnifiedPaintSettings *ups = stroke->ups; ups->draw_anchored = false; ups->stroke_active = false; - if (rv3d) { - rv3d->rflag &= ~RV3D_PAINTING; - } - if (stroke->timer) { WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer); } @@ -933,7 +939,6 @@ void paint_stroke_free(bContext *C, wmOperator *op) BLI_freelistN(&stroke->line); - BKE_paint_set_overlay_override(0); MEM_SAFE_FREE(op->customdata); } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 3554a6cc546..77c95c6acb3 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -2072,9 +2072,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data, struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); + 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; @@ -2120,22 +2120,22 @@ static void wpaint_paint_leaves(bContext *C, data.strength = BKE_brush_weight_get(scene, brush); /* NOTE: current mirroring code cannot be run in parallel */ - TaskParallelSettings settings; + 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; } } @@ -2587,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; @@ -3131,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; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); + 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}; @@ -3177,21 +3172,21 @@ static void vpaint_paint_leaves(bContext *C, .lcol = (uint *)me->mloopcol, .me = me, }; - TaskParallelSettings 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; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b9d621fc1fb..d2d424745da 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -64,6 +64,7 @@ #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" @@ -185,7 +186,6 @@ static float sculpt_vertex_mask_get(SculptSession *ss, int index) static int sculpt_active_vertex_get(SculptSession *ss) { - BLI_assert(BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS); switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: return ss->active_vertex_index; @@ -211,14 +211,19 @@ static void sculpt_active_vertex_normal_get(SculptSession *ss, float normal[3]) #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) @@ -254,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; @@ -276,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; @@ -293,20 +300,44 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, } } -static void sculpt_vertex_neighbors_get_grids(SculptSession *UNUSED(ss), - int UNUSED(index), +static void sculpt_vertex_neighbors_get_grids(SculptSession *ss, + const int index, + const bool include_duplicates, SculptVertexNeighborIter *iter) { - /* TODO: implement this for multires. It might also be worth changing this - * iterator to provide a coordinate and mask pointer directly for effiency, - * rather than converting back and forth between CCGElem and global index. */ + /* 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 +348,28 @@ static void sculpt_vertex_neighbors_get(SculptSession *ss, sculpt_vertex_neighbors_get_bmesh(ss, index, iter); return; case PBVH_GRIDS: - sculpt_vertex_neighbors_get_grids(ss, index, iter); + 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) { \ @@ -381,16 +423,19 @@ static void do_nearest_vertex_get_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void nearest_vertex_get_finalize(void *__restrict userdata, void *__restrict tls) +static void nearest_vertex_get_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - NearestVertexTLSData *nvtd = tls; - if (data->nearest_vertex_index == -1) { - data->nearest_vertex_index = nvtd->nearest_vertex_index; + 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 (nvtd->nearest_vertex_distance_squared < data->nearest_vertex_distance_squared) { - data->nearest_vertex_index = nvtd->nearest_vertex_index; - data->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; + else if (nvtd->nearest_vertex_distance_squared < join->nearest_vertex_distance_squared) { + join->nearest_vertex_index = nvtd->nearest_vertex_index; + join->nearest_vertex_distance_squared = nvtd->nearest_vertex_distance_squared; } } @@ -417,25 +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); - task_data.nearest_vertex_distance_squared = FLT_MAX; NearestVertexTLSData nvtd; nvtd.nearest_vertex_index = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = nearest_vertex_get_finalize; + settings.func_reduce = nearest_vertex_get_reduce; settings.userdata_chunk = &nvtd; settings.userdata_chunk_size = sizeof(NearestVertexTLSData); - BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); MEM_SAFE_FREE(nodes); - return task_data.nearest_vertex_index; + return nvtd.nearest_vertex_index; } static bool is_symmetry_iteration_valid(char i, char symm) @@ -470,28 +513,18 @@ typedef struct SculptFloodFill { char *visited_vertices; } SculptFloodFill; -typedef struct SculptFloodFillIterator { - int v; - int it; - float edge_factor; -} SculptFloodFillIterator; - 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(SculptFloodFillIterator)); + 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) { - SculptFloodFillIterator mevit; - mevit.v = index; - mevit.it = 0; - mevit.edge_factor = 1.0f; - BLI_gsqueue_push(flood->queue, &mevit); + BLI_gsqueue_push(flood->queue, &index); } static void sculpt_floodfill_add_active( @@ -518,32 +551,24 @@ static void sculpt_floodfill_add_active( } } -static void sculpt_floodfill_execute(SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, - const SculptFloodFillIterator *from, - SculptFloodFillIterator *to, - void *userdata), - void *userdata) +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) { - /* TODO: multires support, taking into account duplicate vertices and - * correctly handling them in the pose, automask and mask expand callbacks. */ while (!BLI_gsqueue_is_empty(flood->queue)) { - SculptFloodFillIterator from; - BLI_gsqueue_pop(flood->queue, &from); + int from_v; + BLI_gsqueue_pop(flood->queue, &from_v); SculptVertexNeighborIter ni; - sculpt_vertex_neighbors_iter_begin(ss, from.v, ni) + sculpt_vertex_duplicates_and_neighbors_iter_begin(ss, from_v, ni) { - if (flood->visited_vertices[ni.index] == 0) { - flood->visited_vertices[ni.index] = 1; + const int to_v = ni.index; + if (flood->visited_vertices[to_v] == 0) { + flood->visited_vertices[to_v] = 1; - SculptFloodFillIterator to; - to.v = ni.index; - to.it = from.it + 1; - to.edge_factor = 0.0f; - - if (func(ss, &from, &to, userdata)) { - BLI_gsqueue_push(flood->queue, &to); + if (func(ss, from_v, to_v, ni.is_duplicate, userdata)) { + BLI_gsqueue_push(flood->queue, &to_v); } } } @@ -912,9 +937,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); - BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); MEM_SAFE_FREE(nodes); } @@ -1097,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)); @@ -1194,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 (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return false; - } - if (sculpt_stroke_is_dynamic_topology(ss, br)) { return false; } @@ -1229,7 +1248,7 @@ 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 & BRUSH_AIRBRUSH) { + if (br->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { return false; } @@ -1247,17 +1266,15 @@ typedef struct AutomaskFloodFillData { char symm; } AutomaskFloodFillData; -static bool automask_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *UNUSED(from), - SculptFloodFillIterator *to, - void *userdata) +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; + 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)); + 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) @@ -1396,9 +1413,10 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * \{ */ typedef struct AreaNormalCenterTLSData { - float private_co[2][3]; - float private_no[2][3]; - int private_count[2]; + /* 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, @@ -1408,8 +1426,8 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, SculptThreadedTaskData *data = userdata; SculptSession *ss = data->ob->sculpt; AreaNormalCenterTLSData *anctd = tls->userdata_chunk; - float(*area_nos)[3] = data->area_nos; - float(*area_cos)[3] = data->area_cos; + const bool use_area_nos = data->use_area_nos; + const bool use_area_cos = data->use_area_cos; PBVHVertexIter vd; SculptUndoNode *unode = NULL; @@ -1428,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; } @@ -1459,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(anctd->private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(anctd->private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - anctd->private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } } @@ -1511,40 +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(anctd->private_co[flip_index], co); + if (use_area_cos) { + add_v3_v3(anctd->area_cos[flip_index], co); } - if (area_nos) { - add_v3_v3(anctd->private_no[flip_index], no); + if (use_area_nos) { + add_v3_v3(anctd->area_nos[flip_index], no); } - anctd->private_count[flip_index] += 1; + anctd->area_count[flip_index] += 1; } } BKE_pbvh_vertex_iter_end; } } -static void calc_area_normal_and_center_finalize(void *__restrict userdata, void *__restrict tls) +static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - AreaNormalCenterTLSData *anctd = tls; - float(*area_nos)[3] = data->area_nos; - float(*area_cos)[3] = data->area_cos; + AreaNormalCenterTLSData *join = chunk_join; + AreaNormalCenterTLSData *anctd = chunk; + /* for flatten center */ - if (area_cos) { - add_v3_v3(area_cos[0], anctd->private_co[0]); - add_v3_v3(area_cos[1], anctd->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], anctd->private_no[0]); - add_v3_v3(area_nos[1], anctd->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] += anctd->private_count[0]; - data->count[1] += anctd->private_count[1]; + join->area_count[0] += anctd->area_count[0]; + join->area_count[1] += anctd->area_count[1]; } static void calc_area_center( @@ -1555,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, @@ -1568,24 +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, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + 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; } } @@ -1613,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, @@ -1626,24 +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, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + 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; } } @@ -1661,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, @@ -1675,24 +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, }; AreaNormalCenterTLSData anctd = {{{0}}}; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = calc_area_normal_and_center_finalize; + settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + 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; } } @@ -1701,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; } } @@ -1736,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; @@ -2083,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); @@ -2796,7 +2801,7 @@ static void smooth(Sculpt *sd, .strength = strength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); switch (type) { @@ -2814,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; } @@ -2855,10 +2860,10 @@ static void bmesh_topology_rake( .nodes = nodes, .strength = factor, }; - TaskParallelSettings settings; + 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); } } @@ -2912,9 +2917,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); + 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) @@ -2999,9 +3004,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); + 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, @@ -3075,9 +3080,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } /** @@ -3191,9 +3196,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .flippedbstrength = flippedbstrength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); + 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, @@ -3253,9 +3258,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); + 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, @@ -3325,9 +3330,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } /* Regularized Kelvinlets: Sculpting Brushes based on Fundamental Solutions of Elasticity @@ -3566,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, @@ -3574,9 +3583,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); + 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, @@ -3628,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); @@ -3667,14 +3672,14 @@ static void do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .transform_trans_inv = transform_trans_inv, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } typedef struct PoseGrowFactorTLSData { float pos_avg[3]; - int tot_pos_avg; + int pos_count; } PoseGrowFactorTLSData; static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, @@ -3703,7 +3708,7 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, 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->tot_pos_avg++; + gftd->pos_count++; } } } @@ -3711,12 +3716,14 @@ static void pose_brush_grow_factor_task_cb_ex(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void pose_brush_grow_factor_finalize(void *__restrict userdata, void *__restrict tls) +static void pose_brush_grow_factor_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - PoseGrowFactorTLSData *gftd = tls; - add_v3_v3(data->tot_pos_avg, gftd->pos_avg); - data->tot_pos_count += gftd->tot_pos_avg; + 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 */ @@ -3735,12 +3742,12 @@ static void sculpt_pose_grow_pose_factor( .totnode = totnode, .pose_factor = pose_factor, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; PoseGrowFactorTLSData gftd; - gftd.tot_pos_avg = 0; + gftd.pos_count = 0; zero_v3(gftd.pos_avg); BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = pose_brush_grow_factor_finalize; + settings.func_reduce = pose_brush_grow_factor_reduce; settings.userdata_chunk = &gftd; settings.userdata_chunk_size = sizeof(PoseGrowFactorTLSData); @@ -3748,15 +3755,13 @@ static void sculpt_pose_grow_pose_factor( 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(data.tot_pos_avg); - data.tot_pos_count = 0; zero_v3(gftd.pos_avg); - gftd.tot_pos_avg = 0; + gftd.pos_count = 0; memcpy(data.prev_mask, pose_factor, sculpt_vertex_count_get(ss) * sizeof(float)); - BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); - if (data.tot_pos_count != 0) { - mul_v3_fl(data.tot_pos_avg, 1.0f / (float)data.tot_pos_count); - float len = len_v3v3(data.tot_pos_avg, pose_origin); + 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; @@ -3806,25 +3811,25 @@ typedef struct PoseFloodFillData { int tot_co; } PoseFloodFillData; -static bool pose_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *UNUSED(from), - SculptFloodFillIterator *to, - void *userdata) +static bool pose_floodfill_cb( + SculptSession *ss, int UNUSED(from_v), int to_v, bool is_duplicate, void *userdata) { PoseFloodFillData *data = userdata; if (data->pose_factor) { - data->pose_factor[to->v] = 1.0f; + data->pose_factor[to_v] = 1.0f; } - const float *co = sculpt_vertex_co_get(ss, to->v); + 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)) { - add_v3_v3(data->pose_origin, co); - data->tot_co++; + if (!is_duplicate) { + add_v3_v3(data->pose_origin, co); + data->tot_co++; + } } return false; @@ -3925,9 +3930,9 @@ static void sculpt_pose_brush_init( /* Smooth the pose brush factor for cleaner deformation */ for (int i = 0; i < 4; i++) { - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } MEM_SAFE_FREE(nodes); @@ -3995,9 +4000,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); + 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, @@ -4116,9 +4121,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .grab_delta = grab_delta, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); + 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, @@ -4188,9 +4193,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); + 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, @@ -4261,9 +4266,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); + 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, @@ -4358,9 +4363,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode }; BLI_mutex_init(&data.mutex); - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); BLI_mutex_end(&data.mutex); } @@ -4426,9 +4431,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } static void calc_sculpt_plane( @@ -4635,9 +4640,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); + 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, @@ -4733,9 +4738,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); + 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, @@ -4863,9 +4868,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .mat = mat, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); + 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, @@ -4956,9 +4961,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); + 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, @@ -5048,9 +5053,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_co = area_co, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } static void do_gravity_task_cb_ex(void *__restrict userdata, @@ -5117,9 +5122,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); + 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]) @@ -5271,7 +5276,12 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe 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); } @@ -5286,9 +5296,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); + 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); @@ -5306,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, ss->cache->location, ss->cache->radius); - } + sculpt_pose_brush_init(sd, ob, ss, brush, ss->cache->location, ss->cache->radius); } /* Apply one type of brush action */ @@ -5425,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); } } @@ -5481,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); } } @@ -5508,9 +5516,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .nodes = nodes, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } MEM_SAFE_FREE(nodes); @@ -5532,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); @@ -5578,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, @@ -5598,12 +5606,12 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use .vertCos = vertCos, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, sculpt_flush_stroke_deform_task_cb, &settings); + 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); } @@ -5614,7 +5622,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_use * 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); } } @@ -6378,7 +6386,8 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob, const B 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)) { + 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); } @@ -6559,13 +6568,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, /* Update the active vertex of the SculptSession */ ss->active_vertex_index = srd.active_vertex_index; - - if (!ss->multires) { - copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss)); - } - else { - zero_v3(out->active_vertex_co); - } + copy_v3_v3(out->active_vertex_co, sculpt_active_vertex_co_get(ss)); copy_v3_v3(out->location, ray_normal); mul_v3_fl(out->location, srd.depth); @@ -6877,7 +6880,7 @@ static void sculpt_flush_update_done(const bContext *C, Object *ob, SculptUpdate /* 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); } @@ -6970,10 +6973,10 @@ 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); } @@ -8146,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. @@ -8194,40 +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; - BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - 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; - - MEM_SAFE_FREE(nodes); - MEM_SAFE_FREE(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) @@ -8299,6 +8269,11 @@ 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: @@ -8417,12 +8392,12 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * .filter_strength = filter_strength, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); + 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); } @@ -8440,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; @@ -8654,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); @@ -8702,9 +8669,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) .prev_mask = prev_mask, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + 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); @@ -8813,13 +8780,14 @@ static void dirty_mask_compute_range_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } -static void dirty_mask_compute_range_finalize(void *__restrict userdata, void *__restrict tls) +static void dirty_mask_compute_range_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - SculptThreadedTaskData *data = userdata; - DirtyMaskRangeData *range = tls; - - data->dirty_mask_min = min_ff(range->min, data->dirty_mask_min); - data->dirty_mask_max = max_ff(range->max, data->dirty_mask_max); + 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, @@ -8871,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); @@ -8894,8 +8858,6 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .sd = sd, .ob = ob, .nodes = nodes, - .dirty_mask_min = FLT_MAX, - .dirty_mask_max = -FLT_MAX, .dirty_mask_dirty_only = RNA_boolean_get(op->ptr, "dirty_only"), }; DirtyMaskRangeData range = { @@ -8903,15 +8865,17 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .max = -FLT_MAX, }; - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - settings.func_finalize = dirty_mask_compute_range_finalize; + settings.func_reduce = dirty_mask_compute_range_reduce; settings.userdata_chunk = ⦥ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); - BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); + data.dirty_mask_min = range.min; + data.dirty_mask_max = range.max; + BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); MEM_SAFE_FREE(nodes); @@ -9070,10 +9034,10 @@ 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; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); + BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings); } /* Pivot position */ @@ -9139,10 +9103,10 @@ 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; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + 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; } @@ -9157,26 +9121,37 @@ typedef struct MaskExpandFloodFillData { bool use_normals; } MaskExpandFloodFillData; -static bool mask_expand_floodfill_cb(SculptSession *ss, - const SculptFloodFillIterator *from, - SculptFloodFillIterator *to, - void *userdata) +static bool mask_expand_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) { MaskExpandFloodFillData *data = userdata; - 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 (!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); - to->edge_factor = 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); + 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; @@ -9197,10 +9172,6 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent 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"); @@ -9228,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"); @@ -9266,6 +9242,8 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent ss->filter_cache->normal_factor[i] = avg / ni.size; } } + + MEM_SAFE_FREE(ss->filter_cache->edge_factor); } SculptThreadedTaskData data = { @@ -9277,10 +9255,10 @@ 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; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + 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: " @@ -9594,13 +9572,13 @@ void ED_sculpt_update_modal_transform(struct bContext *C) mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]); } - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BLI_task_parallel_range( + 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); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index e9af49a0b5a..93e4a777569 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -194,12 +194,9 @@ 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; @@ -209,13 +206,8 @@ typedef struct SculptThreadedTaskData { float *pose_factor; float (*transform_rot)[4], (*transform_trans)[4], (*transform_trans_inv)[4]; - float tot_pos_avg[3]; - int tot_pos_count; - float max_distance_squared; float nearest_vertex_search_co[3]; - int nearest_vertex_index; - float nearest_vertex_distance_squared; int mask_expand_update_it; bool mask_expand_invert_mask; @@ -418,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; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 788d07f6e78..5d95cc80280 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -86,6 +86,7 @@ static void update_cb(PBVHNode *node, void *rebuild) struct PartialUpdateData { PBVH *pbvh; bool rebuild; + char *modified_grids; }; /** @@ -94,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)); + } } } @@ -135,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); @@ -157,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]]); } @@ -180,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; } } } @@ -346,9 +360,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - TaskParallelSettings settings; + PBVHParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BLI_task_parallel_range( + BKE_pbvh_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); if (nodes) { @@ -485,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 */ @@ -527,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)) { @@ -546,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) { @@ -577,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)) { @@ -605,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); @@ -620,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) @@ -806,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"); } @@ -828,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]]); } } @@ -1057,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/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_select.c b/source/blender/editors/space_action/action_select.c index 4a4ff5f5605..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); @@ -1681,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 @@ -1703,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; + } } } } @@ -1787,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) { @@ -1805,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) @@ -1831,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/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_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index b4b51de302d..3cdcc07f081 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2395,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) @@ -2459,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) @@ -2504,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); @@ -2533,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/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 e2c9bb8d6e5..ba4ccb4fba9 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -247,13 +247,7 @@ 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; + params->filter_id = FILTER_ID_ALL; if (U.uiflag & USER_HIDE_DOT) { params->flag |= FILE_HIDE_DOT; @@ -362,10 +356,10 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) /** * Update the user-preference data for the file space. In fact, this also contains some - * non-FileSelectParams data, but it's neglectable. + * 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. + * \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]) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 39f7bf001f3..a8dfad85232 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -2298,12 +2298,7 @@ static int image_save_sequence_exec(bContext *C, wmOperator *op) /* get a filename for menu */ BLI_split_dir_part(first_ibuf->name, di, sizeof(di)); - BKE_reportf(op->reports, - RPT_INFO, - tot == 1 ? "%d image will be saved in %s" : - "%d images will be saved in %s", - tot, - di); + BKE_reportf(op->reports, RPT_INFO, "%d image(s) will be saved in %s", tot, di); iter = IMB_moviecacheIter_new(image->cache); while (!IMB_moviecacheIter_done(iter)) { diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index c450d5122eb..577c4e24b11 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -70,7 +70,7 @@ static CLG_LogRef LOG = {"ed.image.undo"}; /** \name Thread Locking * \{ */ -/* this is a static resource for non-globality, +/* 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; @@ -457,6 +457,31 @@ static void ubuf_from_image_all_tiles(UndoImageBuf *ubuf, const ImBuf *ibuf) 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; @@ -510,7 +535,8 @@ static void uhandle_restore_list(ListBase *undo_handles, bool use_init) 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; - IMB_rect_size_set(ibuf, ubuf->image_dims); + 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; 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 3beb12fbb2a..a5b18ff7589 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -47,7 +47,7 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" -#include "GPU_extensions.h" +#include "GPU_platform.h" #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_state.h" @@ -816,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); @@ -3890,9 +3847,7 @@ static void nodelink_batch_draw(SpaceNode *snode) void nodelink_batch_start(SpaceNode *UNUSED(snode)) { - /* TODO: partial workaround for NVIDIA driver bug on recent GTX/RTX cards, - * that breaks instancing when using indirect draw-call (see T70011). */ - g_batch_link.enabled = !GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY); + g_batch_link.enabled = true; } void nodelink_batch_end(SpaceNode *snode) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 08ac84cbb2f..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); */ + } } } } @@ -893,7 +891,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, } } if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { - skip = true; + skip = true; } if (skip) { continue; @@ -917,7 +915,7 @@ static void node_group_make_insert_selected(const bContext *C, bNodeTree *ntree, } } if (sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) { - skip = true; + skip = true; } if (skip) { continue; diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index b66cd0d3069..e22ef389516 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -557,100 +557,40 @@ static int node_mouse_select(bContext *C, static int node_select_exec(bContext *C, wmOperator *op) { + 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"); /* perform the select */ - const int ret_value = node_mouse_select(C, op, mval, 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"); - - if (init_event_type == 0) { - if (event->val == KM_PRESS) { - const int ret_value = node_mouse_select(C, op, mval, 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. - */ - const int ret_value = node_mouse_select(C, op, mval, false); - return ret_value | OPERATOR_PASS_THROUGH; - } - } - else if (event->type == init_event_type && event->val == KM_RELEASE) { - const int ret_value = node_mouse_select(C, op, mval, 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 c81d292a859..c55140db46f 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -770,11 +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, - num_ids == 1 ? "Copied %d selected data-block" : - "Copied %d selected data-blocks", - num_ids); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); return OPERATOR_FINISHED; } @@ -808,11 +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, - num_pasted == 1 ? "%d data-block pasted" : - "%d data-blocks pasted", - num_pasted); + BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted); return OPERATOR_FINISHED; } @@ -2265,11 +2257,7 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op) BKE_id_multi_tagged_delete(bmain); - BKE_reportf(op->reports, - RPT_INFO, - num_tagged[INDEX_ID_NULL] == 1 ? "Deleted %d data-block" : - "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_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 9d7163cd6d9..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; } 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/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_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fbb6dfb8f8f..8b02a52d7f9 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -341,6 +341,9 @@ 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; } @@ -1096,6 +1099,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); @@ -1460,7 +1466,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); } } @@ -1472,7 +1478,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 acc46935eb5..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); } 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_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 5625333d837..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); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 37eea6b03d7..cfdd3dcbb6f 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -79,11 +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, - num_copied == 1 ? "Copied %d selected object" : - "Copied %d selected objects", - num_copied); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); return OPERATOR_FINISHED; } @@ -122,11 +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, - num_pasted == 1 ? "%d object pasted" : - "%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 198b5d05540..3eee76277e8 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.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); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index dd8e2e07271..d7af307bc53 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -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 ac9ad30d719..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(); @@ -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 67ea0f255fc..b98c14150d5 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/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_convert.c b/source/blender/editors/transform/transform_convert.c index 5862faaf667..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 */ diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 7f9c4ee2fcc..f1928433491 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1451,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_generics.c b/source/blender/editors/transform/transform_generics.c index 53e36f86a64..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); @@ -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 65fd9c6f5e9..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; @@ -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++; } @@ -1338,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_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 1601acb1c8f..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" @@ -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, |