Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2019-07-01 04:49:08 +0300
committerYimingWu <xp8110@outlook.com>2019-07-01 04:49:08 +0300
commit27ca5cdfeee638226126822191b7e69cf5b90e79 (patch)
tree8bd4ebdc2dfcdaab35d93b05be67d4f2963ec21a /source/blender/editors
parent37c3aa8eabbb3ba5f5718070744c0c60b67f0f21 (diff)
parentbbb3500c97167c070a76373e023bdd8820d3ca41 (diff)
Merge branch 'master' into soc-2019-npr
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/keyframing.c6
-rw-r--r--source/blender/editors/animation/keyingsets.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c102
-rw-r--r--source/blender/editors/include/ED_gpencil.h1
-rw-r--r--source/blender/editors/interface/interface_widgets.c117
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c4
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c702
-rw-r--r--source/blender/editors/object/object_add.c20
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modes.c7
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/render/render_preview.c14
-rw-r--r--source/blender/editors/screen/screendump.c50
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c43
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/util/gizmo_utils.c7
18 files changed, 611 insertions, 481 deletions
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 89d85388981..31f7a337d57 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2034,7 +2034,7 @@ static int delete_key_exec(bContext *C, wmOperator *op)
int type = RNA_property_enum_get(op->ptr, op->type->prop);
ks = ANIM_keyingset_get_from_enum_type(scene, type);
if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
return OPERATOR_CANCELLED;
}
}
@@ -2044,7 +2044,7 @@ static int delete_key_exec(bContext *C, wmOperator *op)
ks = ANIM_keyingset_get_from_idname(scene, type_id);
if (ks == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id);
+ BKE_reportf(op->reports, RPT_ERROR, "Active Keying Set '%s' not found", type_id);
return OPERATOR_CANCELLED;
}
}
@@ -3000,7 +3000,7 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *
int type = RNA_property_enum_get(op->ptr, prop);
ks = ANIM_keyingset_get_from_enum_type(scene, type);
if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
}
}
else if (prop_type == PROP_STRING) {
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index ab5e3186c47..0cb83c79c85 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -154,7 +154,7 @@ static int remove_active_keyingset_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove");
return OPERATOR_CANCELLED;
}
else if (scene->active_keyingset < 0) {
@@ -203,7 +203,7 @@ static int add_empty_ks_path_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to add empty path to");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to add empty path to");
return OPERATOR_CANCELLED;
}
else {
@@ -253,12 +253,12 @@ static int remove_active_ks_path_exec(bContext *C, wmOperator *op)
ks->active_path--;
}
else {
- BKE_report(op->reports, RPT_ERROR, "No active keying set path to remove");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set path to remove");
return OPERATOR_CANCELLED;
}
}
else {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove a path from");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove a path from");
return OPERATOR_CANCELLED;
}
@@ -409,7 +409,7 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove property from");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove property from");
return OPERATOR_CANCELLED;
}
else if (scene->active_keyingset < 0) {
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 9588d4bb570..44f4728adcd 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -2804,6 +2804,9 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
const int type = RNA_enum_get(op->ptr, "type");
+ const bool geometry = RNA_boolean_get(op->ptr, "geometry");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bGPDstroke *gps = NULL;
/* sanity checks */
if (ELEM(NULL, gpd)) {
@@ -2812,39 +2815,55 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
/* loop all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- if (gpl->actframe == NULL) {
- continue;
- }
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
- continue;
- }
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) ||
+ ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* skip hidden or locked colors */
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ continue;
+ }
- switch (type) {
- case GP_STROKE_CYCLIC_CLOSE:
- /* Close all (enable) */
- gps->flag |= GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_OPEN:
- /* Open all (disable) */
- gps->flag &= ~GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_TOGGLE:
- /* Just toggle flag... */
- gps->flag ^= GP_STROKE_CYCLIC;
- break;
- default:
- BLI_assert(0);
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ /* Create new geometry. */
+ if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) {
+ BKE_gpencil_close_stroke(gps);
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
break;
+ }
}
}
}
@@ -2863,6 +2882,8 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
*/
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem cyclic_type[] = {
{GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
{GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
@@ -2884,6 +2905,9 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+ prop = RNA_def_boolean(
+ ot->srna, "geometry", false, "Create Geometry", "Create new geometry for closing stroke");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************* Flat Stroke Caps ************************** */
@@ -4515,3 +4539,23 @@ void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
/* properties */
WM_operator_properties_gesture_lasso(ot);
}
+
+bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
+{
+ bool ok = false;
+ if (ob) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ gpd->flag &= ~(GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE |
+ GP_DATA_STROKE_WEIGHTMODE);
+
+ ob->restore_mode = ob->mode;
+ ob->mode &= ~(OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL |
+ OB_MODE_WEIGHT_GPENCIL);
+
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
+ ok = true;
+ }
+ return ok;
+}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 73e239f0d33..0e3204b30c7 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -226,6 +226,7 @@ struct Object *ED_gpencil_add_object(struct bContext *C,
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
/* set object modes */
void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
+bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
void ED_gp_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index a6c8697ec2c..ec0b01d4341 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2502,6 +2502,31 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
+static void rgb_tint(char cp[3], int tint)
+{
+ cp[0] = clamp_i(cp[0] + tint, 0, 255);
+ cp[1] = clamp_i(cp[1] + tint, 0, 255);
+ cp[2] = clamp_i(cp[2] + tint, 0, 255);
+}
+
+static void rgb_ensure_contrast(char cp[3], const char cp_other[3], int contrast)
+{
+ BLI_assert(contrast > 0);
+ const int item_value = rgb_to_grayscale_byte((const uchar *)cp);
+ const int inner_value = rgb_to_grayscale_byte((const uchar *)cp_other);
+ const int delta = item_value - inner_value;
+ if (delta >= 0) {
+ if (contrast > delta) {
+ rgb_tint(cp, contrast - delta);
+ }
+ }
+ else {
+ if (contrast > -delta) {
+ rgb_tint(cp, -contrast - delta);
+ }
+ }
+}
+
static void widget_active_color(char cp[3])
{
cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
@@ -2509,6 +2534,28 @@ static void widget_active_color(char cp[3])
cp[2] = cp[2] >= 240 ? 255 : cp[2] + 15;
}
+static const char *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
+ int state,
+ int drawflag)
+{
+ if (drawflag & UI_BUT_ANIMATED_CHANGED) {
+ return wcol_state->inner_changed_sel;
+ }
+ if (state & UI_BUT_ANIMATED_KEY) {
+ return wcol_state->inner_key_sel;
+ }
+ if (state & UI_BUT_ANIMATED) {
+ return wcol_state->inner_anim_sel;
+ }
+ if (state & UI_BUT_DRIVEN) {
+ return wcol_state->inner_driven_sel;
+ }
+ if (state & UI_BUT_OVERRIDEN) {
+ return wcol_state->inner_overridden_sel;
+ }
+ return NULL;
+}
+
/* copy colors from theme, and set changes in it based on state */
static void widget_state(uiWidgetType *wt, int state, int drawflag)
{
@@ -2526,22 +2573,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
wt->wcol = *(wt->wcol_theme);
- const char *color_blend = NULL;
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- color_blend = wcol_state->inner_changed_sel;
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- color_blend = wcol_state->inner_key_sel;
- }
- else if (state & UI_BUT_ANIMATED) {
- color_blend = wcol_state->inner_anim_sel;
- }
- else if (state & UI_BUT_DRIVEN) {
- color_blend = wcol_state->inner_driven_sel;
- }
- else if (state & UI_BUT_OVERRIDEN) {
- color_blend = wcol_state->inner_overridden_sel;
- }
+ const char *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag);
if (state & UI_SELECT) {
copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
@@ -2592,52 +2624,23 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
- /* XXX special tweak to make sure that bar will still be visible */
- float blend = wcol_state->blend - 0.2f;
/* call this for option button */
widget_state(wt, state, drawflag);
- /* now, set the inner-part so that it reflects state settings too */
- /* TODO: maybe we should have separate settings for the blending colors used for this case? */
- if (state & UI_SELECT) {
-
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_changed_sel, blend);
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
- }
- else if (state & UI_BUT_ANIMATED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
- }
- else if (state & UI_BUT_DRIVEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
- }
- else if (state & UI_BUT_OVERRIDEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend);
- }
-
- if (state & UI_SELECT) {
- SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
- }
+ const char *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag);
+ if (color_blend != NULL) {
+ /* Set the slider 'item' so that it reflects state settings too.
+ * De-saturate so the color of the slider doesn't conflict with the blend color,
+ * which can make the color hard to see when the slider is set to full (see T66102). */
+ wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(
+ (const uchar *)wt->wcol.item);
+ widget_state_blend(wt->wcol.item, color_blend, wcol_state->blend);
+ rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 20);
}
- else {
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_changed, blend);
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
- }
- else if (state & UI_BUT_ANIMATED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
- }
- else if (state & UI_BUT_DRIVEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
- }
- else if (state & UI_BUT_OVERRIDEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend);
- }
+
+ if (state & UI_SELECT) {
+ SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 78b4cfe38d4..b4ef2620895 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -263,14 +263,14 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
initNumInput(&opdata->num_input[i]);
opdata->num_input[i].idx_max = 0;
opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
+ opdata->num_input[i].unit_type[0] = B_UNIT_NONE;
if (i == SEGMENTS_VALUE) {
opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
}
if (i == OFFSET_VALUE) {
opdata->num_input[i].unit_sys = scene->unit.system;
+ opdata->num_input[i].unit_type[0] = B_UNIT_LENGTH;
}
- /* Not sure this is a factor or a unit? */
- opdata->num_input[i].unit_type[0] = B_UNIT_NONE;
}
/* avoid the cost of allocating a bm copy */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 94d097612ae..f98a3248e76 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -8016,6 +8016,7 @@ static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
+/* TODO: make this work on multiple objects at once */
static int edbm_point_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -8238,44 +8239,54 @@ static void normals_split(BMesh *bm)
static int normals_split_merge(bContext *C, const bool do_merge)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMEdge *e;
- BMIter eiter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMEdge *e;
+ BMIter eiter;
- /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
- * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809. */
- BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm, true) :
- NULL;
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
- mesh_set_smooth_faces(em, do_merge);
+ /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
+ * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809.
+ */
+ BMLoopNorEditDataArray *lnors_ed_arr = do_merge ?
+ BM_loop_normal_editdata_array_init(bm, true) :
+ NULL;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
+ mesh_set_smooth_faces(em, do_merge);
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
+ }
}
- }
- bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
- if (do_merge) {
- normals_merge(bm, lnors_ed_arr);
- }
- else {
- normals_split(bm);
- }
+ if (do_merge) {
+ normals_merge(bm, lnors_ed_arr);
+ }
+ else {
+ normals_split(bm);
+ }
- if (lnors_ed_arr) {
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- }
+ if (lnors_ed_arr) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8344,131 +8355,140 @@ static EnumPropertyItem average_method_items[] = {
static int edbm_average_normals_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMLoop *l, *l_curr, *l_first;
- BMIter fiter;
-
- BKE_editmesh_ensure_autosmooth(em);
- bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
const int average_type = RNA_enum_get(op->ptr, "average_type");
- const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
const float absweight = (float)RNA_int_get(op->ptr, "weight");
const float threshold = RNA_float_get(op->ptr, "threshold");
- float weight = absweight / 50.0f;
- if (absweight == 100.0f) {
- weight = (float)SHRT_MAX;
- }
- else if (absweight == 1.0f) {
- weight = 1 / (float)SHRT_MAX;
- }
- else if ((weight - 1) * 25 > 1) {
- weight = (weight - 1) * 25;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *l_curr, *l_first;
+ BMIter fiter;
- BM_normals_loops_edges_tag(bm, true);
+ BKE_editmesh_ensure_autosmooth(em);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
- HeapSimple *loop_weight = BLI_heapsimple_new();
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- l_curr = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
- (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
- (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) {
- if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
- const int loop_index = BM_elem_index_get(l_curr);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
- }
- else {
- BMVert *v_pivot = l_curr->v;
- UNUSED_VARS_NDEBUG(v_pivot);
- BMEdge *e_next;
- const BMEdge *e_org = l_curr->e;
- BMLoop *lfan_pivot, *lfan_pivot_next;
+ float weight = absweight / 50.0f;
+ if (absweight == 100.0f) {
+ weight = (float)SHRT_MAX;
+ }
+ else if (absweight == 1.0f) {
+ weight = 1 / (float)SHRT_MAX;
+ }
+ else if ((weight - 1) * 25 > 1) {
+ weight = (weight - 1) * 25;
+ }
- lfan_pivot = l_curr;
- e_next = lfan_pivot->e;
+ BM_normals_loops_edges_tag(bm, true);
- while (true) {
- lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
- if (lfan_pivot_next) {
- BLI_assert(lfan_pivot_next->v == v_pivot);
- }
- else {
- e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
- }
+ HeapSimple *loop_weight = BLI_heapsimple_new();
- float val = 1.0f;
- if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
- val = 1.0f / BM_face_calc_area(lfan_pivot->f);
- }
- else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
- val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
- }
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
+ (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
+ (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) &&
+ BM_loop_check_cyclic_smooth_fan(l_curr)))) {
+ if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_curr);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_curr->v;
+ UNUSED_VARS_NDEBUG(v_pivot);
+ BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_curr;
+ e_next = lfan_pivot->e;
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
- BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
+ float val = 1.0f;
+ if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
+ val = 1.0f / BM_face_calc_area(lfan_pivot->f);
+ }
+ else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
+ val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
+ }
- if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
- break;
- }
- lfan_pivot = lfan_pivot_next;
- }
+ BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
- float wnor[3], avg_normal[3] = {0.0f}, count = 0;
- float val = BLI_heapsimple_top_value(loop_weight);
-
- while (!BLI_heapsimple_is_empty(loop_weight)) {
- const float cur_val = BLI_heapsimple_top_value(loop_weight);
- if (!compare_ff(val, cur_val, threshold)) {
- count++;
- val = cur_val;
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
}
- l = BLI_heapsimple_pop_min(loop_weight);
- BLI_SMALLSTACK_PUSH(loops, l);
- const float n_weight = pow(weight, count);
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float wnor[3], avg_normal[3] = {0.0f}, count = 0;
+ float val = BLI_heapsimple_top_value(loop_weight);
+
+ while (!BLI_heapsimple_is_empty(loop_weight)) {
+ const float cur_val = BLI_heapsimple_top_value(loop_weight);
+ if (!compare_ff(val, cur_val, threshold)) {
+ count++;
+ val = cur_val;
+ }
+ l = BLI_heapsimple_pop_min(loop_weight);
+ BLI_SMALLSTACK_PUSH(loops, l);
+
+ const float n_weight = pow(weight, count);
+
+ if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
+ }
+ else {
+ copy_v3_v3(wnor, l->f->no);
+ }
+ mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
+ add_v3_v3(avg_normal, wnor);
+ }
- if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
+ if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If avg normal is nearly 0, set clnor to default value. */
+ zero_v3(avg_normal);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
- }
- else {
- copy_v3_v3(wnor, l->f->no);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
}
- mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
- add_v3_v3(avg_normal, wnor);
- }
-
- if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
- /* If avg normal is nearly 0, set clnor to default value. */
- zero_v3(avg_normal);
- }
- while ((l = BLI_SMALLSTACK_POP(loops))) {
- const int l_index = BM_elem_index_get(l);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
}
}
- }
- } while ((l_curr = l_curr->next) != l_first);
- }
+ } while ((l_curr = l_curr->next) != l_first);
+ }
- BLI_heapsimple_free(loop_weight, NULL);
- EDBM_update_generic(em, true, false);
+ BLI_heapsimple_free(loop_weight, NULL);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8567,135 +8587,151 @@ static EnumPropertyItem normal_vector_tool_items[] = {
static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- if (bm->totloop == 0) {
- return OPERATOR_CANCELLED;
- }
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
const int mode = RNA_enum_get(op->ptr, "mode");
const bool absolute = RNA_boolean_get(op->ptr, "absolute");
+ float *normal_vector = scene->toolsettings->normal_vector;
+ bool done_copy = false;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
- BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- float *normal_vector = scene->toolsettings->normal_vector;
+ if (bm->totloop == 0) {
+ continue;
+ }
- switch (mode) {
- case EDBM_CLNOR_TOOLS_COPY:
- if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Can only copy one custom normal, vertex normal or face normal");
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- return OPERATOR_CANCELLED;
- }
- if (lnors_ed_arr->totloop == 1) {
- copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
- }
- else if (bm->totfacesel == 1) {
- BMFace *f;
- BMIter fiter;
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- copy_v3_v3(scene->toolsettings->normal_vector, f->no);
- }
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ switch (mode) {
+ case EDBM_CLNOR_TOOLS_COPY:
+ if (bm->totfacesel == 0 || bm->totvertsel == 0) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ continue;
}
- }
- else {
- /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
- * only if they are all the same. */
- bool are_same_lnors = true;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
- are_same_lnors = false;
- }
+
+ if (done_copy ||
+ (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Can only copy one custom normal, vertex normal or face normal");
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ continue;
}
- if (are_same_lnors) {
+ if (lnors_ed_arr->totloop == 1) {
copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
}
- }
- break;
+ else if (bm->totfacesel == 1) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ copy_v3_v3(scene->toolsettings->normal_vector, f->no);
+ }
+ }
+ }
+ else {
+ /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
+ * only if they are all the same. */
+ bool are_same_lnors = true;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
+ are_same_lnors = false;
+ }
+ }
+ if (are_same_lnors) {
+ copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
+ }
+ }
+ done_copy = true;
+ break;
- case EDBM_CLNOR_TOOLS_PASTE:
- if (!absolute) {
- if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
- /* If normal is nearly 0, do nothing. */
- break;
+ case EDBM_CLNOR_TOOLS_PASTE:
+ if (!absolute) {
+ if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
+ /* If normal is nearly 0, do nothing. */
+ break;
+ }
}
- }
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- if (absolute) {
- float abs_normal[3];
- copy_v3_v3(abs_normal, lnor_ed->loc);
- negate_v3(abs_normal);
- add_v3_v3(abs_normal, normal_vector);
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (absolute) {
+ float abs_normal[3];
+ copy_v3_v3(abs_normal, lnor_ed->loc);
+ negate_v3(abs_normal);
+ add_v3_v3(abs_normal, normal_vector);
+
+ if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(abs_normal, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ abs_normal,
+ lnor_ed->clnors_data);
+ }
+ else {
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ normal_vector,
+ lnor_ed->clnors_data);
+ }
+ }
+ break;
- if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
+ case EDBM_CLNOR_TOOLS_MULTIPLY:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ mul_v3_v3(lnor_ed->nloc, normal_vector);
+
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
/* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(abs_normal, lnor_ed->niloc);
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
}
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data);
- }
- else {
BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- normal_vector,
+ lnor_ed->nloc,
lnor_ed->clnors_data);
}
- }
- break;
+ break;
- case EDBM_CLNOR_TOOLS_MULTIPLY:
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- mul_v3_v3(lnor_ed->nloc, normal_vector);
+ case EDBM_CLNOR_TOOLS_ADD:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ add_v3_v3(lnor_ed->nloc, normal_vector);
- if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
- /* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ lnor_ed->nloc,
+ lnor_ed->clnors_data);
}
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- lnor_ed->nloc,
- lnor_ed->clnors_data);
- }
- break;
-
- case EDBM_CLNOR_TOOLS_ADD:
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- add_v3_v3(lnor_ed->nloc, normal_vector);
+ break;
- if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
- /* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ case EDBM_CLNOR_TOOLS_RESET:
+ zero_v3(normal_vector);
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ normal_vector,
+ lnor_ed->clnors_data);
}
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- lnor_ed->nloc,
- lnor_ed->clnors_data);
- }
- break;
+ break;
- case EDBM_CLNOR_TOOLS_RESET:
- zero_v3(normal_vector);
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- normal_vector,
- lnor_ed->clnors_data);
- }
- break;
+ default:
+ BLI_assert(0);
+ break;
+ }
- default:
- BLI_assert(0);
- break;
- }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ EDBM_update_generic(em, true, false);
+ }
- EDBM_update_generic(em, true, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8842,8 +8878,8 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
MEM_freeN(vnors);
EDBM_update_generic(em, true, false);
}
- MEM_freeN(objects);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8866,77 +8902,86 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMLoop *l;
- BMIter fiter, liter;
-
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
- BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
-
- float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- /* This is weird choice of operation, taking all loops of faces of current vertex.
- * Could lead to some rather far away loops weighting as much as very close ones
- * (topologically speaking), with complex polygons.
- * Using topological distance here (rather than geometrical one)
- * makes sense imho, but would rather go with a more consistent and flexible code,
- * we could even add max topological distance to take into account, * and a weighting curve.
- * Would do that later though, think for now we can live with that choice. --mont29. */
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- l = lnor_ed->loop;
- float loop_normal[3];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
- BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
- BMLoop *l_other;
- BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
- const int l_index_other = BM_elem_index_get(l_other);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
- add_v3_v3(smooth_normal[i], loop_normal);
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+
+ float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop,
+ __func__);
+
+ /* This is weird choice of operation, taking all loops of faces of current vertex.
+ * Could lead to some rather far away loops weighting as much as very close ones
+ * (topologically speaking), with complex polygons.
+ * Using topological distance here (rather than geometrical one)
+ * makes sense imho, but would rather go with a more consistent and flexible code,
+ * we could even add max topological distance to take into account, * and a weighting curve.
+ * Would do that later though, think for now we can live with that choice. --mont29. */
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ l = lnor_ed->loop;
+ float loop_normal[3];
+
+ BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
+ BMLoop *l_other;
+ BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
+ const int l_index_other = BM_elem_index_get(l_other);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
+ add_v3_v3(smooth_normal[i], loop_normal);
+ }
}
}
- }
- const float factor = RNA_float_get(op->ptr, "factor");
+ const float factor = RNA_float_get(op->ptr, "factor");
- lnor_ed = lnors_ed_arr->lnor_editdata;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- float current_normal[3];
+ lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ float current_normal[3];
- if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
- continue;
- }
+ if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
- /* Note: again, this is not true spherical interpolation that normals would need...
- * But it's probably good enough for now. */
- mul_v3_fl(current_normal, 1.0f - factor);
- mul_v3_fl(smooth_normal[i], factor);
- add_v3_v3(current_normal, smooth_normal[i]);
+ /* Note: again, this is not true spherical interpolation that normals would need...
+ * But it's probably good enough for now. */
+ mul_v3_fl(current_normal, 1.0f - factor);
+ mul_v3_fl(smooth_normal[i], factor);
+ add_v3_v3(current_normal, smooth_normal[i]);
- if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
- continue;
- }
+ if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
- }
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
+ }
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- MEM_freeN(smooth_normal);
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ MEM_freeN(smooth_normal);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8969,50 +9014,59 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot)
static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMIter fiter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- BM_select_history_clear(bm);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMIter fiter;
+ const int face_strength = RNA_enum_get(op->ptr, "face_strength");
+ const bool set = RNA_boolean_get(op->ptr, "set");
- const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
- int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
- if (cd_prop_int_index == -1) {
- BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id);
- cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
- }
- cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
- const int cd_prop_int_offset = CustomData_get_n_offset(
- &bm->pdata, CD_PROP_INT, cd_prop_int_index);
+ BM_select_history_clear(bm);
- const int face_strength = RNA_enum_get(op->ptr, "face_strength");
- const bool set = RNA_boolean_get(op->ptr, "set");
- BM_mesh_elem_index_ensure(bm, BM_FACE);
+ const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ if (cd_prop_int_index == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id);
+ cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ }
+ cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(
+ &bm->pdata, CD_PROP_INT, cd_prop_int_index);
- if (set) {
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
- *strength = face_strength;
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ if (set) {
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength = face_strength;
+ }
}
}
- }
- else {
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
- if (*strength == face_strength) {
- BM_face_select_set(bm, f, true);
- BM_select_history_store(bm, f);
- }
- else {
- BM_face_select_set(bm, f, false);
+ else {
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ if (*strength == face_strength) {
+ BM_face_select_set(bm, f, true);
+ BM_select_history_store(bm, f);
+ }
+ else {
+ BM_face_select_set(bm, f, false);
+ }
}
}
+
+ EDBM_update_generic(em, false, false);
}
- EDBM_update_generic(em, false, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 0fdb1cec16f..468efc0c9d9 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -2782,10 +2782,10 @@ void OBJECT_OT_join(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Join as Shape Key Operator
+/** \name Transfer Mix Operator for Shape Keys
* \{ */
-static bool join_shapes_poll(bContext *C)
+static bool shape_key_transfer_mix_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -2802,12 +2802,12 @@ static bool join_shapes_poll(bContext *C)
}
}
-static int join_shapes_exec(bContext *C, wmOperator *op)
+static int shape_key_transfer_mix_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
if (ob->mode & OB_MODE_EDIT) {
- BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
+ BKE_report(op->reports, RPT_ERROR, "Shape Keys cannot be transfered in edit mode");
return OPERATOR_CANCELLED;
}
else if (BKE_object_obdata_is_libdata(ob)) {
@@ -2822,16 +2822,16 @@ static int join_shapes_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-void OBJECT_OT_join_shapes(wmOperatorType *ot)
+void OBJECT_OT_shape_key_transfer_mix(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Join as Shapes";
- ot->description = "Merge selected objects to shapes of active object";
- ot->idname = "OBJECT_OT_join_shapes";
+ ot->name = "Transfer Mix";
+ ot->description = "Copy the current resulting shape of another selected object to this one";
+ ot->idname = "OBJECT_OT_shape_key_transfer_mix";
/* api callbacks */
- ot->exec = join_shapes_exec;
- ot->poll = join_shapes_poll;
+ ot->exec = shape_key_transfer_mix_exec;
+ ot->poll = shape_key_transfer_mix_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index b9350052093..f97a9c1b5b8 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -117,7 +117,7 @@ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot);
void OBJECT_OT_duplicate(struct wmOperatorType *ot);
void OBJECT_OT_delete(struct wmOperatorType *ot);
void OBJECT_OT_join(struct wmOperatorType *ot);
-void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
+void OBJECT_OT_shape_key_transfer_mix(struct wmOperatorType *ot);
void OBJECT_OT_convert(struct wmOperatorType *ot);
/* object_hook.c */
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 0f0d09c610b..0ec98e089a2 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -43,6 +43,7 @@
#include "DEG_depsgraph.h"
#include "ED_armature.h"
+#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_object.h" /* own include */
@@ -287,6 +288,12 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain,
ED_object_posemode_exit_ex(bmain, ob);
}
}
+ else if ((ob->type == OB_GPENCIL) && ((ob->mode & OB_MODE_OBJECT) == 0)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_gpencil_exit(bmain, ob);
+ }
else {
if (only_test) {
return false;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index b653c7fa70c..217a2e5a54d 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -117,7 +117,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_duplicates_make_real);
WM_operatortype_append(OBJECT_OT_duplicate);
WM_operatortype_append(OBJECT_OT_join);
- WM_operatortype_append(OBJECT_OT_join_shapes);
+ WM_operatortype_append(OBJECT_OT_shape_key_transfer_mix);
WM_operatortype_append(OBJECT_OT_convert);
WM_operatortype_append(OBJECT_OT_modifier_add);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 76b88b8df22..c6b1acfbd94 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -38,6 +38,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "BLO_readfile.h"
#include "DNA_world_types.h"
@@ -1209,6 +1211,10 @@ static void icon_preview_startjob_all_sizes(void *customdata,
for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
+ if (*stop) {
+ break;
+ }
+
if (prv->tag & PRV_TAG_DEFFERED_DELETE) {
/* Non-thread-protected reading is not an issue here. */
continue;
@@ -1379,7 +1385,10 @@ void ED_preview_icon_job(
/* setup job */
WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
+ /* Wait 2s to start rendering icon previews, to not bog down user interaction.
+ * Particularly important for heavy scenes and Eevee using OpenGL that blocks
+ * the user interface drawing. */
+ WM_jobs_timer(wm_job, 2.0, NC_WINDOW, NC_WINDOW);
WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -1470,6 +1479,9 @@ void ED_preview_shader_job(const bContext *C,
void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
{
if (wm) {
+ /* This is called to stop all preview jobs before scene data changes, to
+ * avoid invalid memory access. */
WM_jobs_kill(wm, NULL, common_preview_startjob);
+ WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
}
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 3b763c7d47a..e5552314a6e 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -43,8 +43,6 @@
#include "BKE_main.h"
#include "BKE_report.h"
-#include "BIF_gl.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -63,59 +61,25 @@ typedef struct ScreenshotData {
ImageFormatData im_format;
} ScreenshotData;
-static void screenshot_read_pixels(int x, int y, int w, int h, unsigned char *rect)
-{
- int i;
-
- glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- glFinish();
-
- /* clear alpha, it is not set to a meaningful value in opengl */
- for (i = 0, rect += 3; i < w * h; i++, rect += 4) {
- *rect = 255;
- }
-}
-
-/* get shot from frontbuffer */
-static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy)
-{
- wmWindow *win = CTX_wm_window(C);
- int x = 0, y = 0;
- unsigned int *dumprect = NULL;
-
- x = 0;
- y = 0;
- *dumpsx = WM_window_pixels_x(win);
- *dumpsy = WM_window_pixels_y(win);
-
- if (*dumpsx && *dumpsy) {
-
- dumprect = MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect");
- glReadBuffer(GL_FRONT);
- screenshot_read_pixels(x, y, *dumpsx, *dumpsy, (unsigned char *)dumprect);
- glReadBuffer(GL_BACK);
- }
-
- return dumprect;
-}
-
/* call from both exec and invoke */
static int screenshot_data_create(bContext *C, wmOperator *op)
{
- unsigned int *dumprect;
- int dumpsx, dumpsy;
+ int dumprect_size[2];
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
/* do redraw so we don't show popups/menus */
WM_redraw_windows(C);
- dumprect = screenshot(C, &dumpsx, &dumpsy);
+ uint *dumprect = WM_window_pixels_read(wm, win, dumprect_size);
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
ScrArea *sa = CTX_wm_area(C);
- scd->dumpsx = dumpsx;
- scd->dumpsy = dumpsy;
+ scd->dumpsx = dumprect_size[0];
+ scd->dumpsy = dumprect_size[1];
scd->dumprect = dumprect;
if (sa) {
scd->crop = sa->totrct;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index a151061ae64..86f99555e12 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1057,7 +1057,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
0,
- TIP_("Temporarly hide in viewport\n"
+ TIP_("Temporarily hide in viewport\n"
"* Shift to set children"));
UI_but_func_set(
bt, outliner__base_set_flag_recursive_cb, base, (void *)"hide_viewport");
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 2a0bc470bcb..d428a190549 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -2126,6 +2126,45 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag
return fnmatch(name, te->name, fn_flag) == 0;
}
+static bool outliner_element_is_collection_or_object(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ return true;
+ }
+ else if (outliner_is_collection_tree_element(te)) {
+ return true;
+ }
+
+ return false;
+}
+
+static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
+ ListBase *parent_subtree)
+{
+ TreeElement *te_next = element->next;
+
+ if (outliner_element_is_collection_or_object(element)) {
+ TreeElement *te_prev = NULL;
+ for (TreeElement *te = element->subtree.last; te; te = te_prev) {
+ te_prev = te->prev;
+
+ if (!outliner_element_is_collection_or_object(te)) {
+ continue;
+ }
+
+ te_next = te;
+ BLI_remlink(&element->subtree, te);
+ BLI_insertlinkafter(parent_subtree, element->prev, te);
+ te->parent = element->parent;
+ }
+ }
+
+ outliner_free_tree_element(element, parent_subtree);
+ return te_next;
+}
+
static int outliner_filter_subtree(SpaceOutliner *soops,
ViewLayer *view_layer,
ListBase *lb,
@@ -2137,9 +2176,9 @@ static int outliner_filter_subtree(SpaceOutliner *soops,
for (te = lb->first; te; te = te_next) {
te_next = te->next;
-
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
- outliner_free_tree_element(te, lb);
+ /* Don't free the tree, but extract the children from the parent and add to this tree. */
+ te_next = outliner_extract_children_from_subtree(te, lb);
continue;
}
else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index c3e683b5f59..ff0ab9285db 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1320,6 +1320,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
/* as last: */
BKE_sequencer_sort(scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 6e12091cf75..b6eb57a3c81 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -4607,7 +4607,7 @@ static int view3d_navigate_invoke(bContext *C,
void VIEW3D_OT_navigate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Navigation";
+ ot->name = "View Navigation (Walk/Fly)";
ot->description =
"Interactively navigate around the scene (uses the mode (walk/fly) preference)";
ot->idname = "VIEW3D_OT_navigate";
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index d330019c816..b856c831424 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -59,7 +59,12 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) {
- WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ ScrArea *sa = CTX_wm_area(C);
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, sa);
+ if (gzgt->users == 0) {
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ }
return false;
}
return true;