diff options
author | YimingWu <xp8110@outlook.com> | 2019-07-01 04:49:08 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2019-07-01 04:49:08 +0300 |
commit | 27ca5cdfeee638226126822191b7e69cf5b90e79 (patch) | |
tree | 8bd4ebdc2dfcdaab35d93b05be67d4f2963ec21a /source/blender/editors | |
parent | 37c3aa8eabbb3ba5f5718070744c0c60b67f0f21 (diff) | |
parent | bbb3500c97167c070a76373e023bdd8820d3ca41 (diff) |
Merge branch 'master' into soc-2019-npr
Diffstat (limited to 'source/blender/editors')
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; |