diff options
author | Antonioya <blendergit@gmail.com> | 2019-07-23 10:46:29 +0300 |
---|---|---|
committer | Antonioya <blendergit@gmail.com> | 2019-07-23 10:46:29 +0300 |
commit | 2204bfcf9e1c3a38e60830bd97775dd72158f4d6 (patch) | |
tree | 4f9c827389a23a431f8771b4ca02f410860c0242 /source/blender/editors | |
parent | f64db794ee690f05905ace0a66d81d2e75549b90 (diff) | |
parent | 34ad6da4a06ef46cd19945f61cc5f968538546a8 (diff) |
Merge branch 'master' into temp-gpencil-drw-engine
Diffstat (limited to 'source/blender/editors')
128 files changed, 2056 insertions, 1265 deletions
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 21b9c7252d2..b93d52a1b2d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1711,8 +1711,7 @@ static void update_dependencies_on_delete(bAnimListElem *ale) AnimData *adt = BKE_animdata_from_id(id); /* TODO(sergey): Technically, if the animation element is being deleted * from a driver we don't have to tag action. This is something we can check - * for in the future. For now just do most reliable tag whic hwas always - * happening. */ + * for in the future. For now just do most reliable tag which was always happening. */ if (adt != NULL) { DEG_id_tag_update(id, ID_RECALC_ANIMATION); if (adt->action != NULL) { diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 8d30076103b..2d16ce30d31 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -2231,7 +2231,7 @@ static size_t animdata_filter_ds_textures( } } - /* Firstly check that we actuallly have some textures, + /* Firstly check that we actually have some textures, * by gathering all textures in a temp list. */ for (a = 0; a < MAX_MTEX; a++) { Tex *tex = (mtex[a]) ? mtex[a]->tex : NULL; @@ -3151,7 +3151,9 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, } /* movie clip's animation */ - items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); + if (!(ads->filterflag2 & ADS_FILTER_NOMOVIECLIPS) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) { + items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode); + } /* Scene-linked animation - e.g. world, compositing nodes, scene anim * (including sequencer currently). */ diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index d3c6109afcd..7a5b57b1ce6 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -322,8 +322,8 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph, /* reset original environment */ /* NOTE: We don't always need to reevaluate the main scene, as the depsgraph - * may be a temporary one that works on a subset of the data. We always have - * to resoture the current frame though. */ + * may be a temporary one that works on a subset of the data. + * We always have to restore the current frame though. */ CFRA = cfra; if (!current_frame_only && restore) { motionpaths_calc_update_scene(bmain, depsgraph); diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 31f7a337d57..2e7ed7eae34 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -532,7 +532,7 @@ int insert_vert_fcurve( * introduced discontinuities in how the param worked. */ beztr.back = 1.70158f; - /* "elastic" easing - values here were hand-optimised for a default duration of + /* "elastic" easing - values here were hand-optimized for a default duration of * ~10 frames (typical mograph motion length) */ beztr.amplitude = 0.8f; beztr.period = 4.1f; @@ -2249,10 +2249,16 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); float cfra = (float)CFRA; + int selected_objects_len = 0; + int selected_objects_success_len = 0; + int success_multi = 0; + CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { ID *id = &ob->id; int success = 0; + selected_objects_len += 1; + /* just those in active action... */ if ((ob->adt) && (ob->adt->action)) { AnimData *adt = ob->adt; @@ -2317,22 +2323,29 @@ static int delete_key_v3d_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&ob->adt->action->id, ID_RECALC_ANIMATION_NO_FLUSH); } - /* report success (or failure) */ + /* Only for reporting. */ if (success) { - BKE_reportf(op->reports, - RPT_INFO, - "Object '%s' successfully had %d keyframes removed", - id->name + 2, - success); - } - else { - BKE_reportf(op->reports, RPT_ERROR, "No keyframes removed from Object '%s'", id->name + 2); + selected_objects_success_len += 1; + success_multi += success; } DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } CTX_DATA_END; + /* report success (or failure) */ + if (selected_objects_success_len) { + BKE_reportf(op->reports, + RPT_INFO, + "%d object(s) successfully had %d keyframes removed", + selected_objects_success_len, + success_multi); + } + else { + BKE_reportf( + op->reports, RPT_ERROR, "No keyframes removed from %d object(s)", selected_objects_len); + } + /* send updates */ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL); diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index d02e58d48a9..d2fa77f90be 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -1121,6 +1121,8 @@ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z } + ED_armature_edit_refresh_layer_used(obedit->data); + /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index c5430e06b6e..4e6661b1d15 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -862,6 +862,7 @@ static int armature_fill_bones_exec(bContext *C, wmOperator *op) } /* updates */ + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); /* free points */ @@ -1053,6 +1054,7 @@ static int armature_merge_exec(bContext *C, wmOperator *op) /* updates */ ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit); } MEM_freeN(objects); @@ -1460,8 +1462,8 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) changed_multi = true; ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } } @@ -1635,6 +1637,7 @@ static int armature_dissolve_selected_exec(bContext *C, wmOperator *UNUSED(op)) if (changed) { changed_multi = true; ED_armature_edit_sync_selection(arm->edbo); + ED_armature_edit_refresh_layer_used(arm); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); } } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 2c61818d902..8722e575d15 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -38,6 +38,7 @@ #include "BKE_action.h" #include "BKE_animsys.h" +#include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_fcurve.h" @@ -426,6 +427,7 @@ int join_armature_exec(bContext *C, wmOperator *op) ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); + BKE_armature_refresh_layer_used(arm); DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); @@ -671,6 +673,9 @@ static int separate_armature_exec(bContext *C, wmOperator *op) ED_armature_to_edit(obedit->data); + ED_armature_edit_refresh_layer_used(obedit->data); + BKE_armature_refresh_layer_used(newob->data); + /* parents tips remain selected when connected children are removed. */ ED_armature_edit_deselect_all(obedit); diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 5d424594229..d8777b7e0b7 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -85,6 +85,18 @@ void ED_armature_edit_validate_active(struct bArmature *arm) } } +/* Update the layers_used variable after bones are moved between layer + * NOTE: Used to be done in drawing code in 2.7, but that won't work with + * Copy-on-Write, as drawing uses evaluated copies. + */ +void ED_armature_edit_refresh_layer_used(bArmature *arm) +{ + arm->layer_used = 0; + for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) { + arm->layer_used |= ebo->layer; + } +} + /* *************************************************************** */ /* Bone Operations */ diff --git a/source/blender/editors/armature/editarmature_undo.c b/source/blender/editors/armature/editarmature_undo.c index 3a2440af2da..4a82a8fccee 100644 --- a/source/blender/editors/armature/editarmature_undo.c +++ b/source/blender/editors/armature/editarmature_undo.c @@ -174,7 +174,8 @@ static bool armature_undosys_step_encode(struct bContext *C, static void armature_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { ArmatureUndoStep *us = (ArmatureUndoStep *)us_p; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 745af06c7af..5daf6b584e5 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -872,6 +872,8 @@ static int pose_bone_layers_exec(bContext *C, wmOperator *op) RNA_boolean_set_array(&ptr, "layers", layers); if (prev_ob != ob) { + BKE_armature_refresh_layer_used(ob->data); + /* Note, notifier might evolve. */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); DEG_id_tag_update((ID *)ob->data, ID_RECALC_COPY_ON_WRITE); @@ -949,6 +951,8 @@ static int armature_bone_layers_exec(bContext *C, wmOperator *op) } CTX_DATA_END; + ED_armature_edit_refresh_layer_used(ob->data); + /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index e9ea49aaf03..8434fee6e78 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -40,6 +40,7 @@ #include "BKE_object.h" #include "BKE_report.h" #include "BKE_layer.h" +#include "BKE_modifier.h" #include "DEG_depsgraph.h" @@ -181,10 +182,17 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, if (!extend && !deselect && !toggle) { { - uint bases_len = 0; - Base **bases = BKE_object_pose_base_array_get_unique(view_layer, v3d, &bases_len); - ED_pose_deselect_all_multi_ex(bases, bases_len, SEL_DESELECT, true); - MEM_freeN(bases); + /* Don't use 'BKE_object_pose_base_array_get_unique' + * because we may be selecting from object mode. */ + FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) { + Object *ob_iter = base_iter->object; + if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) { + if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) { + ED_pose_bone_select_tag_update(ob_iter); + } + } + } + FOREACH_VISIBLE_BASE_END; } nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = nearBone; @@ -240,6 +248,38 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, return nearBone != NULL; } +/** + * While in weight-paint mode, a single pose may be active as well. + * While not common, it's possible we have multiple armatures deforming a mesh. + * + * This function de-selects all other objects, and selects the new base. + * It can't be set to the active object because we need + * to keep this set to the weight paint object. + */ +void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select) +{ + BLI_assert(base_select && (base_select->object->type == OB_ARMATURE)); + Object *ob_active = OBACT(view_layer); + BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT)); + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Object *ob_arm = amd->object; + if (ob_arm != NULL) { + Base *base_arm = BKE_view_layer_base_find(view_layer, ob_arm); + if ((base_arm != NULL) && (base_arm != base_select) && (base_arm->flag & BASE_SELECTED)) { + ED_object_base_select(base_arm, BA_DESELECT); + } + } + } + } + if ((base_select->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base_select, BA_SELECT); + } +} + /* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT. * When true, 'ignore_visibility' makes this func also affect invisible bones * (hidden or on hidden layers). */ diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index 97317a86104..4c5a42cade6 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -584,7 +584,7 @@ static void pose_slide_apply_quat(tPoseSlideOp *pso, tPChanFCurveLink *pfl) /* perform blending */ if (pso->mode == POSESLIDE_BREAKDOWN) { - /* Just perform the interpol between quat_prev and + /* Just perform the interpolation between quat_prev and * quat_next using pso->percentage as a guide. */ interp_qt_qtqt(quat_final, quat_prev, quat_next, pso->percentage); } diff --git a/source/blender/editors/curve/editcurve_undo.c b/source/blender/editors/curve/editcurve_undo.c index d0c2afcb1d2..835abd1a630 100644 --- a/source/blender/editors/curve/editcurve_undo.c +++ b/source/blender/editors/curve/editcurve_undo.c @@ -238,10 +238,8 @@ static bool curve_undosys_step_encode(struct bContext *C, return true; } -static void curve_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int UNUSED(dir)) +static void curve_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { CurveUndoStep *us = (CurveUndoStep *)us_p; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index ffbfb692ca9..db3d5ad401d 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -73,9 +73,9 @@ static int kill_selection(Object *obedit, int ins); /************************* utilities ******************************/ -static char findaccent(char char1, unsigned int code) +static wchar_t findaccent(wchar_t char1, unsigned int code) { - char new = 0; + wchar_t new = 0; if (char1 == 'a') { if (code == '`') { @@ -170,7 +170,7 @@ static char findaccent(char char1, unsigned int code) new = 186; } else if (code == 'e') { - new = 143; + new = 339; } else if (code == 'c') { new = 169; @@ -191,7 +191,7 @@ static char findaccent(char char1, unsigned int code) } else if (char1 == 't') { if (code == 'm') { - new = 153; + new = 8482; } } else if (char1 == 'u') { @@ -342,7 +342,7 @@ static char findaccent(char char1, unsigned int code) new = 247; } if (code == '|') { - new = 135; + new = 8224; } if (code == '+') { new = 177; @@ -350,15 +350,15 @@ static char findaccent(char char1, unsigned int code) } else if (char1 == '|') { if (code == '-') { - new = 135; + new = 8224; } if (code == '=') { - new = 136; + new = 8225; } } else if (char1 == '=') { if (code == '|') { - new = 136; + new = 8225; } } else if (char1 == '+') { diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index 82c19db7a4a..2f8f15bc6c7 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -62,7 +62,7 @@ typedef struct UndoFont { wchar_t *textbuf; struct CharInfo *textbufinfo; - int len, pos; + int len, pos, selstart, selend; #ifdef USE_ARRAY_STORE struct { @@ -241,10 +241,10 @@ static void undofont_to_editfont(UndoFont *uf, Curve *cu) memcpy(ef->textbufinfo, uf->textbufinfo, final_size); ef->pos = uf->pos; + ef->selstart = uf->selstart; + ef->selend = uf->selend; ef->len = uf->len; - ef->selstart = ef->selend = 0; - #ifdef USE_ARRAY_STORE uf_arraystore_expand_clear(uf); #endif @@ -269,6 +269,8 @@ static void *undofont_from_editfont(UndoFont *uf, Curve *cu) memcpy(uf->textbufinfo, ef->textbufinfo, final_size); uf->pos = ef->pos; + uf->selstart = ef->selstart; + uf->selend = ef->selend; uf->len = ef->len; #ifdef USE_ARRAY_STORE @@ -356,7 +358,8 @@ static bool font_undosys_step_encode(struct bContext *C, static void font_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_EDIT); diff --git a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c index 780cca66fb9..ba3b8c2602e 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/cage2d_gizmo.c @@ -101,6 +101,7 @@ static bool gizmo_calc_rect_view_margin(const wmGizmo *gz, const float dims[2], handle_size *= gz->scale_final; float scale_xy[2]; if (!gizmo_calc_rect_view_scale(gz, dims, scale_xy)) { + zero_v2(margin); return false; } margin[0] = ((handle_size * scale_xy[0])); diff --git a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c index 31e30a0dd1a..6d8ab096a26 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/dial3d_gizmo.c @@ -129,7 +129,26 @@ static void dial_geom_draw(const float color[4], immUniformColor4fv(color); if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + if (arc_partial_angle == 0.0f) { + if (arc_inner_factor == 0.0f) { + imm_draw_circle_fill_2d(pos, 0, 0, 1.0, DIAL_RESOLUTION); + } + else { + imm_draw_disk_partial_fill_2d( + pos, 0, 0, arc_inner_factor, 1.0f, DIAL_RESOLUTION, 0, RAD2DEGF(M_PI * 2)); + } + } + else { + float arc_partial_deg = RAD2DEGF((M_PI * 2) - arc_partial_angle); + imm_draw_disk_partial_fill_2d(pos, + 0, + 0, + arc_inner_factor, + 1.0f, + DIAL_RESOLUTION, + -arc_partial_deg / 2, + arc_partial_deg); + } } else { if (arc_partial_angle == 0.0f) { diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 5f08035a56b..809acc3b322 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -888,7 +888,7 @@ static void gp_draw_strokes(tGPDdraw *tgpw) /* if disable fill, the colors with fill must be omitted too except fill boundary strokes */ if ((tgpw->disable_fill == 1) && (gp_style->fill_rgba[3] > 0.0f) && - ((gps->flag & GP_STROKE_NOFILL) == 0)) { + ((gps->flag & GP_STROKE_NOFILL) == 0) && (gp_style->flag & GP_STYLE_FILL_SHOW)) { continue; } diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index f5b27d8268d..7d866aedd87 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -579,6 +579,7 @@ static bool gp_brush_push_apply( mul_v3_v3fl(delta, gso->dvec, inf); /* apply */ + mul_mat3_m4_v3(gso->object->obmat, delta); /* only rotation component */ add_v3_v3(&pt->x, delta); /* compute lock axis */ @@ -646,7 +647,9 @@ static bool gp_brush_pinch_apply( inf = gp_brush_influence_calc(gso, radius, co) / 5.0f; /* 1) Make this point relative to the cursor/midpoint (dvec) */ - sub_v3_v3v3(vec, &pt->x, gso->dvec); + float fpt[3]; + mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + sub_v3_v3v3(vec, fpt, gso->dvec); /* 2) Shrink the distance by pulling the point towards the midpoint * (0.0 = at midpoint, 1 = at edge of brush region) @@ -664,7 +667,8 @@ static bool gp_brush_pinch_apply( mul_v3_fl(vec, fac); /* 3) Translate back to original space, with the shrinkage applied */ - add_v3_v3v3(&pt->x, gso->dvec, vec); + add_v3_v3v3(fpt, gso->dvec, vec); + mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); @@ -713,11 +717,14 @@ static bool gp_brush_twist_apply( axis_angle_normalized_to_mat3(rmat, axis, angle); - /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */ - sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center - * (center is stored in dvec) */ + /* Rotate point */ + float fpt[3]; + mul_v3_m4v3(fpt, gso->object->obmat, &pt->x); + sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center + * (center is stored in dvec) */ mul_m3_v3(rmat, vec); - add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */ + add_v3_v3v3(fpt, vec, gso->dvec); /* restore */ + mul_v3_m4v3(&pt->x, gso->object->imat, fpt); /* compute lock axis */ gpsculpt_compute_lock_axis(gso, pt, save_pt); @@ -1090,8 +1097,12 @@ static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso) * get pasted relative to where the cursor is now */ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) { + /* Rotate around center new position */ + mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */ + /* assume that the delta can just be applied, and then everything works */ add_v3_v3(&pt->x, delta); + mul_m4_v3(gso->object->imat, &pt->x); } /* Store ref for later */ diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 941c7645dc0..90a2b2d613c 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1521,8 +1521,10 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op)) /* first lock all colors */ for (short i = 0; i < *totcol; i++) { Material *tmp_ma = give_current_material(ob, i + 1); - tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); + if (tmp_ma) { + tmp_ma->gp_style->flag |= GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* loop all selected strokes and unlock any color */ @@ -2433,10 +2435,12 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; - gp_style->flag |= GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; + gp_style->flag |= GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* loop all selected strokes and unlock any color used in active layer */ @@ -2515,7 +2519,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); /* Skip if this is the active one */ - if (ma == active_ma) { + if ((ma == NULL) || (ma == active_ma)) { continue; } @@ -2534,6 +2538,9 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) /* Set flags on all "other" colors */ for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } gp_style = ma->gp_style; if (gp_style == active_color) { continue; @@ -2548,6 +2555,9 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op) /* Clear flags - Restore everything else */ for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); + if (ma == NULL) { + continue; + } gp_style = ma->gp_style; gp_style->flag &= ~flags; DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); @@ -2610,10 +2620,12 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op) MaterialGPencilStyle *color = NULL; for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - color = ma->gp_style; - if (active_color != color) { - color->flag |= GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + color = ma->gp_style; + if (active_color != color) { + color->flag |= GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } } } @@ -2671,9 +2683,11 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_HIDE; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_HIDE; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ @@ -2722,9 +2736,11 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag |= GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag |= GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ @@ -2773,9 +2789,11 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op)) for (short i = 0; i < *totcol; i++) { ma = give_current_material(ob, i + 1); - gp_style = ma->gp_style; - gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; - DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + if (ma) { + gp_style = ma->gp_style; + gp_style->flag &= ~GP_STYLE_COLOR_LOCKED; + DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE); + } } /* updates */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 5459cd09e53..0c1c24a9432 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -883,7 +883,7 @@ static void gpencil_add_move_points(bGPDframe *gpf, bGPDstroke *gps) } gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* if first point, add new point at the begining */ + /* If first point, add new point at the beginning. */ if (do_first) { copy_move_point(gps, temp_points, temp_dverts, 0, 0, true); /* deselect old */ @@ -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 ************************** */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 8a9f7c1224a..4d5548dcdf3 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -996,8 +996,9 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) float factor; /* get interpolation factor */ - factor = (float)(cframe - prevFrame->framenum) / - (nextFrame->framenum - prevFrame->framenum + 1); + float framerange = nextFrame->framenum - prevFrame->framenum; + CLAMP_MIN(framerange, 1.0f); + factor = (float)(cframe - prevFrame->framenum) / framerange; if (ipo_settings->type == GP_IPO_CURVEMAP) { /* custom curvemap */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index f6691f4813b..b49094c4fd6 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3708,7 +3708,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* handle drawing event */ /* printf("\t\tGP - add point\n"); */ - if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0)) { + if (((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) && (p->paintmode != GP_PAINTMODE_ERASER)) { gpencil_add_missing_events(C, op, event, p); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 21bee0a9d4e..cca94925e6e 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -225,8 +225,8 @@ static void gp_primitive_update_cps(tGPDprimitive *tgpi) } else if (tgpi->type == GP_STROKE_CURVE) { mid_v2_v2v2(tgpi->midpoint, tgpi->start, tgpi->end); - copy_v2_v2(tgpi->cp1, tgpi->midpoint); - copy_v2_v2(tgpi->cp2, tgpi->cp1); + interp_v2_v2v2(tgpi->cp1, tgpi->midpoint, tgpi->start, 0.33f); + interp_v2_v2v2(tgpi->cp2, tgpi->midpoint, tgpi->end, 0.33f); } else if (tgpi->type == GP_STROKE_ARC) { if (tgpi->flip) { @@ -1284,6 +1284,11 @@ static void gpencil_primitive_interaction_end(bContext *C, } } + /* Close stroke with geometry */ + if ((tgpi->type == GP_STROKE_BOX) || (tgpi->type == GP_STROKE_CIRCLE)) { + BKE_gpencil_close_stroke(gps); + } + DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_COPY_ON_WRITE); DEG_id_tag_update(&tgpi->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 7d4b6dbeea2..101a65d151a 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -172,8 +172,6 @@ int ED_draw_imbuf_method(struct ImBuf *ibuf); /* OpenGL drawing utility functions. Do not use these in new code, these * are intended to be moved or removed in the future. */ -void set_inverted_drawing(int enable); - /* own working polygon offset */ float bglPolygonOffsetCalc(const float winmat[16], float viewdist, float dist); void bglPolygonOffset(float viewdist, float dist); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index aca59e2868f..6629eed8328 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -170,6 +170,10 @@ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, bool deselect, bool toggle, bool do_nearest); + +void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer, + struct Base *base_select); + bool ED_armature_edit_select_pick( struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); @@ -184,6 +188,8 @@ EditBone *ED_armature_ebone_get_mirrored(const struct ListBase *edbo, EditBone * void ED_armature_edit_sync_selection(struct ListBase *edbo); void ED_armature_edit_validate_active(struct bArmature *arm); +void ED_armature_edit_refresh_layer_used(struct bArmature *arm); + struct Base *ED_armature_base_and_ebone_from_select_buffer(struct Base **bases, uint bases_len, int hit, diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 5d8038d0b28..d2613facd83 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -393,6 +393,9 @@ bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); void ED_mesh_report_mirror(struct wmOperator *op, int totmirr, int totfail); void ED_mesh_report_mirror_ex(struct wmOperator *op, int totmirr, int totfail, char selectmode); +/* Returns the pinned mesh, the mesh from the pinned object, or the mesh from the active object. */ +struct Mesh *ED_mesh_context(struct bContext *C); + /* mesh backup */ typedef struct BMBackup { struct BMesh *bmcopy; diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index a4c68c2c5ad..038f1bf52a6 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -121,6 +121,9 @@ void ED_object_parent_clear(struct Object *ob, const int type); void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode); void ED_object_base_activate(struct bContext *C, struct Base *base); +void ED_object_base_active_refresh(struct Main *bmain, + struct Scene *scene, + struct ViewLayer *view_layer); void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob); bool ED_object_base_deselect_all_ex(struct ViewLayer *view_layer, struct View3D *v3d, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 7689a9f97cd..d36d2559f26 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -93,7 +93,8 @@ void ED_preview_icon_job(const struct bContext *C, struct ID *id, unsigned int *rect, int sizex, - int sizey); + int sizey, + const bool delay); void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain); void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index fc43144417a..e67a3b003fc 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -337,6 +337,7 @@ bool ED_operator_object_active(struct bContext *C); bool ED_operator_object_active_editable(struct bContext *C); bool ED_operator_object_active_editable_mesh(struct bContext *C); bool ED_operator_object_active_editable_font(struct bContext *C); +bool ED_operator_editable_mesh(struct bContext *C); bool ED_operator_editmesh(struct bContext *C); bool ED_operator_editmesh_view3d(struct bContext *C); bool ED_operator_editmesh_region_view3d(struct bContext *C); diff --git a/source/blender/editors/include/ED_text.h b/source/blender/editors/include/ED_text.h index 7638249d49a..ed71439bd37 100644 --- a/source/blender/editors/include/ED_text.h +++ b/source/blender/editors/include/ED_text.h @@ -26,7 +26,7 @@ struct ARegion; struct SpaceText; -struct TextUndoBuf; +struct UndoStep; struct UndoType; bool ED_text_region_location_from_cursor(struct SpaceText *st, @@ -37,6 +37,6 @@ bool ED_text_region_location_from_cursor(struct SpaceText *st, /* text_undo.c */ void ED_text_undosys_type(struct UndoType *ut); -struct TextUndoBuf *ED_text_undo_push_init(struct bContext *C); +struct UndoStep *ED_text_undo_push_init(struct bContext *C); #endif /* __ED_TEXT_H__ */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 75564ddd947..f27523bb1f8 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -121,16 +121,16 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx, bool sort, struct ListBase *r_hit_list); -bool ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, - const unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - struct Object **r_ob, - float r_obmat[4][4]); +short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, + const unsigned short snap_to, + const struct SnapObjectParams *params, + const float mval[2], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + struct Object **r_ob, + float r_obmat[4][4]); bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, const unsigned short snap_to, const struct SnapObjectParams *params, diff --git a/source/blender/editors/include/ED_undo.h b/source/blender/editors/include/ED_undo.h index ebc50e186a2..fa2630ba726 100644 --- a/source/blender/editors/include/ED_undo.h +++ b/source/blender/editors/include/ED_undo.h @@ -54,6 +54,9 @@ bool ED_undo_is_valid(const struct bContext *C, const char *undoname); bool ED_undo_is_memfile_compatible(const struct bContext *C); +/* Unfortunate workaround for limits mixing undo systems. */ +bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, struct ID *id); + void ED_undo_object_editmode_restore_helper(struct bContext *C, struct Object **object_array, uint object_array_len, diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 3d2052f1fa9..47cf827ed66 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -45,6 +45,9 @@ #ifndef DEF_ICON_COLOR # define DEF_ICON_COLOR DEF_ICON #endif +#ifndef DEF_ICON_FUND +# define DEF_ICON_FUND DEF_ICON +#endif /* ICON_ prefix added */ DEF_ICON_COLOR(NONE) @@ -289,7 +292,7 @@ DEF_ICON(DECORATE_LIBRARY_OVERRIDE) DEF_ICON(DECORATE_UNLOCKED) DEF_ICON(DECORATE_LOCKED) DEF_ICON(DECORATE_OVERRIDE) -DEF_ICON_BLANK(111) +DEF_ICON_FUND(FUND) DEF_ICON(TRACKER_DATA) DEF_ICON(HEART) DEF_ICON(ORPHAN_DATA) @@ -1033,4 +1036,5 @@ DEF_ICON_COLOR(EVENT_RETURN) #undef DEF_ICON_SHADING #undef DEF_ICON_VECTOR #undef DEF_ICON_COLOR +#undef DEF_ICON_FUND #undef DEF_ICON_BLANK diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index bf728ec7772..3b2a80c1e05 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -723,7 +723,7 @@ bool UI_block_active_only_flagged_buttons(const struct bContext *C, struct ARegion *ar, struct uiBlock *block); -void UI_but_execute(const struct bContext *C, uiBut *but); +void UI_but_execute(const struct bContext *C, struct ARegion *ar, uiBut *but); bool UI_but_online_manual_id(const uiBut *but, char *r_str, diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index db6bb35560d..3b080b6df95 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -272,6 +272,7 @@ typedef enum ThemeColorID { TH_ICON_OBJECT_DATA, TH_ICON_MODIFIER, TH_ICON_SHADING, + TH_ICON_FUND, TH_SCROLL_TEXT, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 137c431e3bf..0dbf3c710d6 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -71,7 +71,7 @@ enum eView2D_CommonViewTypes { #define V2D_SCROLL_HANDLE_SIZE_HOTSPOT (0.6f * U.widget_unit) /** Don't allow scroll thumb to show below this size (so it's never too small to click on). */ -#define V2D_SCROLL_THUMB_SIZE_MIN (50.0 * UI_DPI_FAC) +#define V2D_SCROLL_THUMB_SIZE_MIN (30.0 * UI_DPI_FAC) /* ------ Define for UI_view2d_sync ----- */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 697c289491a..a2138a1b3a5 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -896,9 +896,8 @@ bool UI_block_active_only_flagged_buttons(const bContext *C, ARegion *ar, uiBloc } /* simulate button click */ -void UI_but_execute(const bContext *C, uiBut *but) +void UI_but_execute(const bContext *C, ARegion *ar, uiBut *but) { - ARegion *ar = CTX_wm_region(C); void *active_back; ui_but_execute_begin((bContext *)C, ar, but, &active_back); /* Value is applied in begin. No further action required. */ diff --git a/source/blender/editors/interface/interface_align.c b/source/blender/editors/interface/interface_align.c index be02def1693..cc68e303e4a 100644 --- a/source/blender/editors/interface/interface_align.c +++ b/source/blender/editors/interface/interface_align.c @@ -251,7 +251,7 @@ static void block_align_proximity_compute(ButAlign *butal, ButAlign *butal_other } } /* We assume two buttons can only share one side at most - for until - * we have sperical UI... */ + * we have spherical UI. */ return; } } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 36e197a0591..7cec8af46de 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -1030,23 +1030,6 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) 0, ""); UI_but_func_set(but2, popup_change_shortcut_func, but, NULL); - - but2 = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_BLANK1, - CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), - 0, - 0, - w, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - ""); - UI_but_func_set(but2, remove_shortcut_func, but, NULL); } else { but2 = uiDefIconTextBut(block, @@ -1067,6 +1050,23 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) "please use User Preferences otherwise")); UI_but_flag_enable(but2, UI_BUT_DISABLED); } + + but2 = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Shortcut"), + 0, + 0, + w, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + ""); + UI_but_func_set(but2, remove_shortcut_func, but, NULL); } /* only show 'assign' if there's a suitable key map for it to go in */ else if (WM_keymap_guess_opname(C, idname)) { diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c index 67e5a6c806c..ffe93e48936 100644 --- a/source/blender/editors/interface/interface_eyedropper_colorband.c +++ b/source/blender/editors/interface/interface_eyedropper_colorband.c @@ -84,22 +84,40 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op) uiBut *but = UI_context_active_but_get(C); + PointerRNA rna_update_ptr = PointerRNA_NULL; + PropertyRNA *rna_update_prop = NULL; + bool is_undo = true; + if (but == NULL) { /* pass */ } - else if (but->type == UI_BTYPE_COLORBAND) { - /* When invoked with a hotkey, we can find the band in 'but->poin'. */ - band = (ColorBand *)but->poin; - } else { - /* When invoked from a button it's in custom_data field. */ - band = (ColorBand *)but->custom_data; + if (but->type == UI_BTYPE_COLORBAND) { + /* When invoked with a hotkey, we can find the band in 'but->poin'. */ + band = (ColorBand *)but->poin; + } + else { + /* When invoked from a button it's in custom_data field. */ + band = (ColorBand *)but->custom_data; + } + + if (band) { + rna_update_ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; + rna_update_prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; + is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + } } if (!band) { PointerRNA ptr = CTX_data_pointer_get_type(C, "color_ramp", &RNA_ColorRamp); if (ptr.data != NULL) { band = ptr.data; + + /* Set this to a sub-member of the property to trigger an update. */ + extern PropertyRNA rna_ColorRamp_color_mode; + rna_update_ptr = ptr; + rna_update_prop = &rna_ColorRamp_color_mode; + is_undo = RNA_struct_undo_check(ptr.type); } } @@ -113,9 +131,9 @@ static bool eyedropper_colorband_init(bContext *C, wmOperator *op) eye->color_buffer_len = 0; eye->color_band = band; eye->init_color_band = *eye->color_band; - eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr; - eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop; - eye->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + eye->ptr = rna_update_ptr; + eye->prop = rna_update_prop; + eye->is_undo = is_undo; op->customdata = eye; @@ -186,7 +204,9 @@ static void eyedropper_colorband_apply(bContext *C, wmOperator *op) BKE_colorband_init_from_table_rgba( eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples); eye->is_set = true; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } } static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) @@ -194,7 +214,9 @@ static void eyedropper_colorband_cancel(bContext *C, wmOperator *op) EyedropperColorband *eye = op->customdata; if (eye->is_set) { *eye->color_band = eye->init_color_band; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } } eyedropper_colorband_exit(C, op); } @@ -267,7 +289,9 @@ static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const w break; case EYE_MODAL_SAMPLE_RESET: *eye->color_band = eye->init_color_band; - RNA_property_update(C, &eye->ptr, eye->prop); + if (eye->prop) { + RNA_property_update(C, &eye->ptr, eye->prop); + } eye->color_buffer_len = 0; break; } diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index adb317f488c..fc60fc06ac0 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -31,6 +31,7 @@ #include "DNA_space_types.h" #include "DNA_screen_types.h" #include "DNA_object_types.h" +#include "DNA_camera_types.h" #include "DNA_view3d_types.h" #include "BLI_string.h" @@ -102,8 +103,9 @@ static int depthdropper_init(bContext *C, wmOperator *op) if (rv3d && rv3d->persp == RV3D_CAMOB) { View3D *v3d = CTX_wm_view3d(C); if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) { - RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); - ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); + Camera *camera = (Camera *)v3d->camera->data; + RNA_pointer_create(&camera->id, &RNA_CameraDOFSettings, &camera->dof, &ddr->ptr); + ddr->prop = RNA_struct_find_property(&ddr->ptr, "focus_distance"); ddr->is_undo = true; } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e59431d265d..a7fc0cfec25 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -551,12 +551,15 @@ static bool ui_but_dragedit_update_mval(uiHandleButtonData *data, int mx) return true; } -static void ui_but_update_preferences_dirty(uiBut *but) +static void ui_rna_update_preferences_dirty(PointerRNA *ptr, PropertyRNA *prop) { /* Not very elegant, but ensures preference changes force re-save. */ bool tag = false; - if (but->rnaprop) { - StructRNA *base = RNA_struct_base(but->rnapoin.type); + if (prop && !(RNA_property_flag(prop) & PROP_NO_DEG_UPDATE)) { + StructRNA *base = RNA_struct_base(ptr->type); + if (base == NULL) { + base = ptr->type; + } if (ELEM(base, &RNA_AddonPreferences, &RNA_KeyConfigPreferences, &RNA_KeyMapItem)) { tag = true; } @@ -568,6 +571,16 @@ static void ui_but_update_preferences_dirty(uiBut *but) } } +static void ui_but_update_preferences_dirty(uiBut *but) +{ + ui_rna_update_preferences_dirty(&but->rnapoin, but->rnaprop); +} + +static void ui_afterfunc_update_preferences_dirty(uiAfterFunc *after) +{ + ui_rna_update_preferences_dirty(&after->rnapoin, after->rnaprop); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -743,6 +756,22 @@ static void ui_apply_but_undo(uiBut *but) str = "Unknown Action"; } + /* Optionally override undo when undo system doesn't support storing properties. */ + if (but->rnapoin.id.data) { + /* Exception for renaming ID data, we always need undo pushes in this case, + * because undo systems track data by their ID, see: T67002. */ + extern PropertyRNA rna_ID_name; + if (but->rnaprop == &rna_ID_name) { + /* pass */ + } + else { + ID *id = but->rnapoin.id.data; + if (!ED_undo_is_legacy_compatible_for_property(but->block->evil_C, id)) { + str = ""; + } + } + } + /* delayed, after all other funcs run, popups are closed, etc */ after = ui_afterfunc_new(); BLI_strncpy(after->undostr, str, sizeof(after->undostr)); @@ -843,6 +872,8 @@ static void ui_apply_but_funcs_after(bContext *C) MEM_freeN(after.rename_orig); } + ui_afterfunc_update_preferences_dirty(&after); + if (after.undostr[0]) { ED_undo_push(C, after.undostr); } @@ -1347,7 +1378,7 @@ static bool ui_drag_toggle_set_xy_xy( /* is it pressed? */ int pushed_state_but = ui_drag_toggle_but_pushed_state(C, but); if (pushed_state_but != pushed_state) { - UI_but_execute(C, but); + UI_but_execute(C, ar, but); if (do_check) { ui_but_update_edited(but); } @@ -7278,7 +7309,11 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s button_tooltip_timer_reset(C, but); /* automatic open pulldown block timer */ - if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) { + if (ELEM(but->type, UI_BTYPE_BLOCK, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER) || + /* Menu button types may draw as popovers, check for this case + * ignoring other kinds of menus (mainly enums). (see T66538). */ + ((but->type == UI_BTYPE_MENU) && + (UI_but_paneltype_get(but) || ui_but_menu_draw_as_popover(but)))) { if (data->used_mouse && !data->autoopentimer) { int time; @@ -7939,6 +7974,8 @@ void ui_but_execute_begin(struct bContext *UNUSED(C), uiBut *but, void **active_back) { + BLI_assert(ar != NULL); + BLI_assert(BLI_findindex(&ar->uiblocks, but->block) != -1); /* note: ideally we would not have to change 'but->active' however * some functions we call don't use data (as they should be doing) */ uiHandleButtonData *data; @@ -9269,7 +9306,7 @@ static int ui_handle_menu_event(bContext *C, for (but = block->buttons.first; but; but = but->next) { if (!(but->flag & UI_BUT_DISABLED) && but->menu_key == event->type) { if (but->type == UI_BTYPE_BUT) { - UI_but_execute(C, but); + UI_but_execute(C, ar, but); } else { ui_handle_button_activate_by_type(C, ar, but); @@ -9350,7 +9387,7 @@ static int ui_handle_menu_event(bContext *C, ar, UI_BUT_ACTIVE_DEFAULT, UI_HIDDEN); if ((but_default != NULL) && (but_default->active == NULL)) { if (but_default->type == UI_BTYPE_BUT) { - UI_but_execute(C, but_default); + UI_but_execute(C, ar, but_default); } else { ui_handle_button_activate_by_type(C, ar, but_default); @@ -10100,9 +10137,10 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE if ((data->state == BUTTON_STATE_MENU_OPEN) && /* make sure mouse isn't inside another menu (see T43247) */ - (is_inside_menu == false) && (ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER)) && + (is_inside_menu == false) && + (ELEM(but->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU)) && (but_other = ui_but_find_mouse_over(ar, event)) && (but != but_other) && - (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER))) { + (ELEM(but_other->type, UI_BTYPE_PULLDOWN, UI_BTYPE_POPOVER, UI_BTYPE_MENU))) { /* if mouse moves to a different root-level menu button, * open it to replace the current menu */ if ((but_other->flag & UI_BUT_DISABLED) == 0) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 6f1f4dde1ab..ea5ef94d90d 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -169,6 +169,7 @@ static const IconType icontypes[] = { # define DEF_ICON_OBJECT_DATA(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_OBJECT_DATA}, # define DEF_ICON_MODIFIER(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_MODIFIER}, # define DEF_ICON_SHADING(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_SHADING}, +# define DEF_ICON_FUND(name) {ICON_TYPE_MONO_TEXTURE, TH_ICON_FUND}, # define DEF_ICON_VECTOR(name) {ICON_TYPE_VECTOR, 0}, # define DEF_ICON_COLOR(name) {ICON_TYPE_COLOR_TEXTURE, 0}, # define DEF_ICON_BLANK(name) {ICON_TYPE_BLANK, 0}, @@ -1417,11 +1418,13 @@ static void icon_set_image(const bContext *C, return; } + const bool delay = prv_img->rect[size] != NULL; icon_create_rect(prv_img, size); if (use_job) { /* Job (background) version */ - ED_preview_icon_job(C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size]); + ED_preview_icon_job( + C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay); } else { if (!scene) { diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index aa7e7f97478..f2b2a478ba9 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1052,8 +1052,7 @@ static int reports_to_text_exec(bContext *C, wmOperator *UNUSED(op)) str = BKE_reports_string(reports, (G.debug & G_DEBUG) ? RPT_DEBUG : RPT_INFO); if (str) { - TextUndoBuf *utxt = NULL; // FIXME - BKE_text_write(txt, utxt, str); + BKE_text_write(txt, str); MEM_freeN(str); return OPERATOR_FINISHED; @@ -1507,29 +1506,21 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot) /** \name Press Button Operator * \{ */ -static ARegion *region_event_inside_for_screen(bContext *C, const int xy[2]) -{ - bScreen *sc = CTX_wm_screen(C); - if (sc) { - for (ARegion *ar = sc->regionbase.first; ar; ar = ar->next) { - if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) { - return ar; - } - } - } - return NULL; -} - static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + bScreen *sc = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *ar_prev = CTX_wm_region(C); - ARegion *ar = region_event_inside_for_screen(C, &event->x); + ARegion *ar = sc ? BKE_screen_find_region_xy(sc, RGN_TYPE_ANY, event->x, event->y) : NULL; if (ar == NULL) { ar = ar_prev; } + if (ar == NULL) { + return OPERATOR_PASS_THROUGH; + } + CTX_wm_region_set(C, ar); uiBut *but = UI_context_active_but_get(C); CTX_wm_region_set(C, ar_prev); @@ -1545,7 +1536,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev * having this avoids a minor drawing glitch. */ void *but_optype = but->optype; - UI_but_execute(C, but); + UI_but_execute(C, ar, but); but->optype = but_optype; diff --git a/source/blender/editors/interface/interface_region_color_picker.c b/source/blender/editors/interface/interface_region_color_picker.c index 5c231f5e51a..917c35f0135 100644 --- a/source/blender/editors/interface/interface_region_color_picker.c +++ b/source/blender/editors/interface/interface_region_color_picker.c @@ -63,6 +63,21 @@ enum ePickerType { /** \name Color Conversion * \{ */ +static void ui_color_picker_rgb_round(float rgb[3]) +{ + /* Handle small rounding errors in color space conversions. Doing these for + * all color space conversions would be expensive, but for the color picker + * we can do the extra work. */ + for (int i = 0; i < 3; i++) { + if (fabsf(rgb[i]) < 1e-6f) { + rgb[i] = 0.0f; + } + else if (fabsf(1.0f - rgb[i]) < 1e-6f) { + rgb[i] = 1.0f; + } + } +} + void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]) { switch (U.color_picker_type) { @@ -131,6 +146,7 @@ void ui_scene_linear_to_color_picker_space(uiBut *but, float rgb[3]) * space for intuitive color picking. */ if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_scene_linear_to_color_picking_v3(rgb); + ui_color_picker_rgb_round(rgb); } } @@ -138,6 +154,7 @@ void ui_color_picker_to_scene_linear_space(uiBut *but, float rgb[3]) { if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_color_picking_to_scene_linear_v3(rgb); + ui_color_picker_rgb_round(rgb); } } @@ -201,6 +218,7 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but, copy_v3_v3(rgb_hex, rgb); if (from_but && !ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); + ui_color_picker_rgb_round(rgb_hex); } rgb_float_to_uchar(rgb_hex_uchar, rgb_hex); @@ -287,6 +305,7 @@ static void ui_colorpicker_hex_rna_cb(bContext *UNUSED(C), void *bt1, void *hexc /* Hex code is assumed to be in sRGB space (coming from other applications, web, etc) */ if (!ui_but_is_color_gamma(but)) { IMB_colormanagement_srgb_to_scene_linear_v3(rgb); + ui_color_picker_rgb_round(rgb); } ui_update_color_picker_buts_rgb(but, but->block, cpicker, rgb); @@ -765,6 +784,7 @@ static void ui_block_colorpicker(uiBlock *block, uiBut *from_but, float rgba[4], if (!ui_but_is_color_gamma(from_but)) { IMB_colormanagement_scene_linear_to_srgb_v3(rgb_hex); + ui_color_picker_rgb_round(rgb_hex); } rgb_float_to_uchar(rgb_hex_uchar, rgb_hex); diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index 6d1b2baeff9..43afdc534ad 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -27,6 +27,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_screen_types.h" #include "DNA_userdef_types.h" #include "BLI_string.h" @@ -231,6 +232,11 @@ ARegionType *ED_area_type_hud(int space_type) art->init = hud_region_init; art->free = hud_region_free; + /* We need to indicate a preferred size to avoid false `RGN_FLAG_TOO_SMALL` + * the first time the region is created. */ + art->prefsizex = AREAMINX; + art->prefsizey = HEADERY; + hud_panels_register(art, space_type, art->regionid); art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index 22c62ecd6f7..53c96fb72a7 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -355,7 +355,7 @@ uiPopover *UI_popover_begin(bContext *C, int ui_size_x) } pup->ui_size_x = ui_size_x; - /* Opertor context default same as menus, change if needed. */ + /* Operator context default same as menus, change if needed. */ ui_popover_create_block(C, pup, WM_OP_EXEC_REGION_WIN); /* create in advance so we can let buttons point to retval already */ @@ -404,7 +404,7 @@ void UI_popover_end(bContext *C, uiPopover *pup, wmKeyMap *keymap) /* TODO(campbell): we may want to make this configurable. * The begin/end stype of calling popups doesn't allow to 'can_refresh' to be set. - * For now close this style of popvers when accessed. */ + * For now close this style of popovers when accessed. */ UI_block_flag_disable(pup->block, UI_BLOCK_KEEP_OPEN); /* panels are created flipped (from event handling pov) */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 5d3ef5c625e..1fc1af9815f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -952,7 +952,7 @@ static void template_ID(bContext *C, /* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack. * Only for images, sound and fonts */ - if (id && BKE_pack_check(id)) { + if (id && BKE_packedfile_id_check(id)) { but = uiDefIconButO(block, UI_BTYPE_BUT, "FILE_OT_unpack_item", diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index ec0b01d4341..0bf8247dc17 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2636,7 +2636,7 @@ static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag) 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); + rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 30); } if (state & UI_SELECT) { diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index e281c6c9e9c..25116934b06 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -901,6 +901,12 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case TH_ICON_SHADING: cp = btheme->tui.icon_shading; break; + case TH_ICON_FUND: { + /* Development fund icon color is not part of theme. */ + static const char red[4] = {204, 48, 72, 255}; + cp = red; + break; + } case TH_SCROLL_TEXT: cp = btheme->tui.wcol_scroll.text; @@ -1377,12 +1383,14 @@ bool UI_GetIconThemeColor4ubv(int colorid, uchar col[4]) if (colorid == 0) { return false; } - - /* Only colored icons in outliner and popups, overall UI is intended - * to stay monochrome and out of the way except a few places where it - * is important to communicate different data types. */ - if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || - (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { + else if (colorid == TH_ICON_FUND) { + /* Always color development fund icon. */ + } + else if (!((theme_spacetype == SPACE_OUTLINER && theme_regionid == RGN_TYPE_WINDOW) || + (theme_spacetype == SPACE_PROPERTIES && theme_regionid == RGN_TYPE_NAV_BAR))) { + /* Only colored icons in outliner and popups, overall UI is intended + * to stay monochrome and out of the way except a few places where it + * is important to communicate different data types. */ return false; } diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 1f844961d19..dad84c87fd7 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -593,8 +593,8 @@ void WM_OT_collada_export(wmOperatorType *ot) "apply_global_orientation", false, "Apply Global Orientation", - "enabled: Rotate all root objects to match the global orientation " - "settings.\ndisabled: set global orientation in Collada assets"); + "Rotate all root objects to match the global orientation settings " + "otherwise set the global orientation per Collada asset"); RNA_def_boolean(func, "selected", false, "Selection Only", "Export only selected elements"); @@ -726,8 +726,8 @@ void WM_OT_collada_export(wmOperatorType *ot) INT_MIN, INT_MAX, "Transform", - "Transformation type for translation, scale and rotation\n" - "Note: The Animation transformation type in the Anim Tab\n" + "Transformation type for translation, scale and rotation. " + "Note: The Animation transformation type in the Anim Tab " "is always equal to the Object transformation type in the Geom tab", INT_MIN, INT_MAX); @@ -737,8 +737,8 @@ void WM_OT_collada_export(wmOperatorType *ot) prop_bc_export_transformation_type, 0, "Transform", - "Transformation type for translation, scale and rotation\n" - "Note: The Animation transformation type in the Anim Tab\n" + "Transformation type for translation, scale and rotation. " + "Note: The Animation transformation type in the Anim Tab " "is always equal to the Object transformation type in the Geom tab"); RNA_def_boolean(func, diff --git a/source/blender/editors/lattice/editlattice_undo.c b/source/blender/editors/lattice/editlattice_undo.c index 166201adc15..abc5224c4d6 100644 --- a/source/blender/editors/lattice/editlattice_undo.c +++ b/source/blender/editors/lattice/editlattice_undo.c @@ -68,9 +68,19 @@ typedef struct UndoLattice { static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt) { - int len = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + const int len_src = ult->pntsu * ult->pntsv * ult->pntsw; + const int len_dst = editlatt->latt->pntsu * editlatt->latt->pntsv * editlatt->latt->pntsw; + if (len_src != len_dst) { + MEM_freeN(editlatt->latt->def); + editlatt->latt->def = MEM_dupallocN(ult->def); + } + else { + memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len_src); + } - memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len); + editlatt->latt->pntsu = ult->pntsu; + editlatt->latt->pntsv = ult->pntsv; + editlatt->latt->pntsw = ult->pntsw; editlatt->latt->actbp = ult->actbp; } @@ -176,7 +186,8 @@ static bool lattice_undosys_step_encode(struct bContext *C, static void lattice_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { LatticeUndoStep *us = (LatticeUndoStep *)us_p; diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index fc85eab6e66..883dfe9ad7c 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -869,7 +869,7 @@ static int primitive_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUS return op->type->exec(C, op); } -static void define_prinitive_add_properties(wmOperatorType *ot) +static void define_primitive_add_properties(wmOperatorType *ot) { RNA_def_float( ot->srna, "size", 100, -FLT_MAX, FLT_MAX, "Size", "Size of new circle", -FLT_MAX, FLT_MAX); @@ -913,7 +913,7 @@ void MASK_OT_primitive_circle_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - define_prinitive_add_properties(ot); + define_primitive_add_properties(ot); } /******************** primitive add suqare *********************/ @@ -944,5 +944,5 @@ void MASK_OT_primitive_square_add(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - define_prinitive_add_properties(ot); + define_primitive_add_properties(ot); } diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index a205f6878e3..8e4efddd8a7 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -441,6 +441,7 @@ static int masklay_new_exec(bContext *C, wmOperator *op) mask->masklay_act = mask->masklay_tot - 1; WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -474,6 +475,7 @@ static int masklay_remove_exec(bContext *C, wmOperator *UNUSED(op)) BKE_mask_layer_remove(mask, masklay); WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); } return OPERATOR_FINISHED; @@ -2206,6 +2208,7 @@ static int mask_layer_move_exec(bContext *C, wmOperator *op) } WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } 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 26d830ccaec..919de4cdb20 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -534,6 +534,9 @@ static int edbm_delete_exec(bContext *C, wmOperator *op) EDBM_flag_disable_all(em, BM_ELEM_SELECT); EDBM_update_generic(em, true, true); + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); } MEM_freeN(objects); @@ -7415,7 +7418,7 @@ void MESH_OT_symmetry_snap(struct wmOperatorType *ot) #ifdef WITH_FREESTYLE /* -------------------------------------------------------------------- */ -/** \name Mark Edge (FreeStyle) Operator +/** \name Mark Edge (Freestyle) Operator * \{ */ static int edbm_mark_freestyle_edge_exec(bContext *C, wmOperator *op) @@ -7495,7 +7498,7 @@ void MESH_OT_mark_freestyle_edge(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mark Face (FreeStyle) Operator +/** \name Mark Face (Freestyle) Operator * \{ */ static int edbm_mark_freestyle_face_exec(bContext *C, wmOperator *op) @@ -8015,6 +8018,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); @@ -8237,44 +8241,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; } @@ -8343,131 +8357,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; } @@ -8566,135 +8589,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; } @@ -8841,8 +8880,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; } @@ -8865,77 +8904,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; } @@ -8968,50 +9016,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/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 28b14b0060d..e823fb46140 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -741,7 +741,8 @@ static bool mesh_undosys_step_encode(struct bContext *C, static void mesh_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { MeshUndoStep *us = (MeshUndoStep *)us_p; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index a6934326d68..ee8de9d8ea9 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -41,6 +41,7 @@ #include "DEG_depsgraph.h" +#include "RNA_access.h" #include "RNA_define.h" #include "WM_api.h" @@ -629,8 +630,7 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot) static int mesh_customdata_clear_exec__internal(bContext *C, char htype, int type) { - Object *obedit = ED_object_context(C); - Mesh *me = obedit->data; + Mesh *me = ED_mesh_context(C); int tot; CustomData *data = mesh_customdata_get_type(me, htype, &tot); @@ -788,8 +788,7 @@ void MESH_OT_customdata_skin_clear(wmOperatorType *ot) /* Clear custom loop normals */ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Mesh *me = ED_mesh_context(C); if (!BKE_mesh_has_custom_loop_normals(me)) { CustomData *data = GET_CD_DATA(me, ldata); @@ -853,7 +852,7 @@ void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_customdata_custom_splitnormals_add_exec; - ot->poll = ED_operator_object_active_editable_mesh; + ot->poll = ED_operator_editable_mesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -861,8 +860,7 @@ void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot) static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - Object *ob = ED_object_context(C); - Mesh *me = ob->data; + Mesh *me = ED_mesh_context(C); if (BKE_mesh_has_custom_loop_normals(me)) { return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL); @@ -879,7 +877,7 @@ void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot) /* api callbacks */ ot->exec = mesh_customdata_custom_splitnormals_clear_exec; - ot->poll = ED_operator_object_active_editable_mesh; + ot->poll = ED_operator_editable_mesh; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -1289,3 +1287,23 @@ void ED_mesh_report_mirror(wmOperator *op, int totmirr, int totfail) { ED_mesh_report_mirror_ex(op, totmirr, totfail, SCE_SELECT_VERTEX); } + +Mesh *ED_mesh_context(struct bContext *C) +{ + Mesh *mesh = CTX_data_pointer_get_type(C, "mesh", &RNA_Mesh).data; + if (mesh != NULL) { + return mesh; + } + + Object *ob = ED_object_active_context(C); + if (ob == NULL) { + return NULL; + } + + ID *data = (ID *)ob->data; + if (data == NULL || GS(data->name) != ID_ME) { + return NULL; + } + + return (Mesh *)data; +} diff --git a/source/blender/editors/metaball/editmball_undo.c b/source/blender/editors/metaball/editmball_undo.c index d255fac26ad..9a95560ccdd 100644 --- a/source/blender/editors/metaball/editmball_undo.c +++ b/source/blender/editors/metaball/editmball_undo.c @@ -185,7 +185,8 @@ static bool mball_undosys_step_encode(struct bContext *C, static void mball_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { MBallUndoStep *us = (MBallUndoStep *)us_p; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 0fdb1cec16f..f8cf55933aa 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1658,54 +1658,80 @@ static void copy_object_set_idnew(bContext *C) /** \name Make Instanced Objects Real Operator * \{ */ +/* XXX TODO That whole hierarchy handling based on persistent_id tricks is + * very confusing and convoluted, and it will fail in many cases besides basic ones. + * Think this should be replaced by a proper tree-like representation of the instantiations, + * should help a lot in both readability, and precise consistent rebuilding of hierarchy. + */ + /** - * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, + * \note regarding hashing dupli-objects which come from OB_DUPLICOLLECTION, * skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same * dupli-group instance. + * + * \note regarding hashing dupli-objects which come from non-OB_DUPLICOLLECTION, + * include the first member of #DupliObject.persistent_id + * since its the index of the vertex/face the object is instantiated on and we want to identify + * objects on the same vertex/face. + * In other words, we consider each group of objects from a same item as being + * the 'local group' where to check for parents. */ -static unsigned int dupliobject_group_hash(const void *ptr) +static unsigned int dupliobject_hash(const void *ptr) { const DupliObject *dob = ptr; unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - unsigned int i; - for (i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { - hash ^= (dob->persistent_id[i] ^ i); + + if (dob->type == OB_DUPLICOLLECTION) { + for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } + } + else { + hash ^= (dob->persistent_id[0] ^ 0); } return hash; } /** - * \note regarding hashing dupli-objects when NOT using OB_DUPLICOLLECTION, - * include the first member of #DupliObject.persistent_id - * since its the index of the vertex/face the object is instantiated on and we want to identify - * objects on the same vertex/face. + * \note regarding hashing dupli-objects when using OB_DUPLICOLLECTION, + * skip the first member of #DupliObject.persistent_id + * since its a unique index and we only want to know if the group objects are from the same + * dupli-group instance. */ -static unsigned int dupliobject_hash(const void *ptr) +static unsigned int dupliobject_instancer_hash(const void *ptr) { const DupliObject *dob = ptr; - unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); - hash ^= (dob->persistent_id[0] ^ 0); + unsigned int hash = BLI_ghashutil_inthash(dob->persistent_id[0]); + for (int i = 1; (i < MAX_DUPLI_RECUR) && dob->persistent_id[i] != INT_MAX; i++) { + hash ^= (dob->persistent_id[i] ^ i); + } return hash; } -/* Compare function that matches dupliobject_group_hash */ -static bool dupliobject_group_cmp(const void *a_, const void *b_) +/* Compare function that matches dupliobject_hash */ +static bool dupliobject_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; - unsigned int i; if (a->ob != b->ob) { return true; } - for (i = 1; (i < MAX_DUPLI_RECUR); i++) { - if (a->persistent_id[i] != b->persistent_id[i]) { - return true; + if (ELEM(a->type, b->type, OB_DUPLICOLLECTION)) { + for (int i = 1; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } } - else if (a->persistent_id[i] == INT_MAX) { - break; + } + else { + if (a->persistent_id[0] != b->persistent_id[0]) { + return true; } } @@ -1713,18 +1739,19 @@ static bool dupliobject_group_cmp(const void *a_, const void *b_) return false; } -/* Compare function that matches dupliobject_hash */ -static bool dupliobject_cmp(const void *a_, const void *b_) +/* Compare function that matches dupliobject_instancer_hash. */ +static bool dupliobject_instancer_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; - if (a->ob != b->ob) { - return true; - } - - if (a->persistent_id[0] != b->persistent_id[0]) { - return true; + for (int i = 0; (i < MAX_DUPLI_RECUR); i++) { + if (a->persistent_id[i] != b->persistent_id[i]) { + return true; + } + else if (a->persistent_id[i] == INT_MAX) { + break; + } } /* matching */ @@ -1739,7 +1766,7 @@ static void make_object_duplilist_real( Depsgraph *depsgraph = CTX_data_depsgraph(C); ListBase *lb_duplis; DupliObject *dob; - GHash *dupli_gh, *parent_gh = NULL; + GHash *dupli_gh, *parent_gh = NULL, *instancer_gh = NULL; if (!(base->object->transflag & OB_DUPLI)) { return; @@ -1750,11 +1777,11 @@ static void make_object_duplilist_real( dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - if (base->object->transflag & OB_DUPLICOLLECTION) { - parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); - } - else { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + + if (use_base_parent) { + instancer_gh = BLI_ghash_new( + dupliobject_instancer_hash, dupliobject_instancer_cmp, __func__); } } @@ -1788,7 +1815,12 @@ static void make_object_duplilist_real( ob_dst->parent = NULL; BKE_constraints_free(&ob_dst->constraints); ob_dst->runtime.curve_cache = NULL; + const bool is_dupli_instancer = (ob_dst->transflag & OB_DUPLI) != 0; ob_dst->transflag &= ~OB_DUPLI; + /* Remove instantiated collection, it's annoying to keep it here + * (and get potentially a lot of usages of it then...). */ + id_us_min((ID *)ob_dst->instance_collection); + ob_dst->instance_collection = NULL; copy_m4_m4(ob_dst->obmat, dob->mat); BKE_object_apply_mat4(ob_dst, ob_dst->obmat, false, false); @@ -1802,6 +1834,13 @@ static void make_object_duplilist_real( if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { *val = ob_dst; } + + if (is_dupli_instancer && instancer_gh) { + /* Same as above, we may have several 'hits'. */ + if (!BLI_ghash_ensure_p(instancer_gh, dob, &val)) { + *val = ob_dst; + } + } } } @@ -1825,7 +1864,8 @@ static void make_object_duplilist_real( * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - if (base->object->transflag & OB_DUPLICOLLECTION) { + dob_key.type = dob->type; + if (dob->type == OB_DUPLICOLLECTION) { memcpy(&dob_key.persistent_id[1], &dob->persistent_id[1], sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); @@ -1848,15 +1888,30 @@ static void make_object_duplilist_real( ob_dst->parent = ob_dst_par; } - else if (use_base_parent) { - ob_dst->parent = base->object; - ob_dst->partype = PAROBJECT; - } } - else if (use_base_parent) { - /* since we are ignoring the internal hierarchy - parent all to the - * base object */ - ob_dst->parent = base->object; + if (use_base_parent && ob_dst->parent == NULL) { + Object *ob_dst_par = NULL; + + if (instancer_gh != NULL) { + /* OK to keep most of the members uninitialized, + * they won't be read, this is simply for a hash lookup. */ + DupliObject dob_key; + /* We are looking one step upper in hierarchy, so we need to 'shift' the persitent_id, + * ignoring the first item. + * We only check on persistent_id here, since we have no idea what object it might be. */ + memcpy(&dob_key.persistent_id[0], + &dob->persistent_id[1], + sizeof(dob_key.persistent_id[0]) * (MAX_DUPLI_RECUR - 1)); + ob_dst_par = BLI_ghash_lookup(instancer_gh, &dob_key); + } + + if (ob_dst_par == NULL) { + /* Default to parenting to root object... + * Always the case when use_hierarchy is false. */ + ob_dst_par = base->object; + } + + ob_dst->parent = ob_dst_par; ob_dst->partype = PAROBJECT; } @@ -1878,12 +1933,16 @@ static void make_object_duplilist_real( DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); } } + base->object->instance_collection = NULL; } BLI_ghash_free(dupli_gh, NULL, NULL); if (parent_gh) { BLI_ghash_free(parent_gh, NULL, NULL); } + if (instancer_gh) { + BLI_ghash_free(instancer_gh, NULL, NULL); + } free_object_duplilist(lb_duplis); @@ -1977,7 +2036,13 @@ static void curvetomesh(Main *bmain, Depsgraph *depsgraph, Object *ob) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); Curve *curve = ob->data; + Mesh *mesh = BKE_mesh_new_from_object_to_bmain(bmain, depsgraph, object_eval, true); + if (mesh == NULL) { + /* Unable to convert the curve to a mesh. */ + return; + } + BKE_object_free_modifiers(ob, 0); /* Replace curve used by the object itself. */ ob->data = mesh; @@ -2066,7 +2131,7 @@ static Base *duplibase_for_convert( static int convert_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); Base *basen = NULL, *basact = NULL; @@ -2285,8 +2350,9 @@ static int convert_exec(bContext *C, wmOperator *op) BKE_curve_curve_dimension_update(cu); if (target == OB_MESH) { + /* No assumption should be made that the resulting objects is a mesh, as conversion can + * fail. */ curvetomesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2309,8 +2375,9 @@ static int convert_exec(bContext *C, wmOperator *op) newob = ob; } + /* No assumption should be made that the resulting objects is a mesh, as conversion can + * fail. */ curvetomesh(bmain, depsgraph, newob); - /* meshes doesn't use displist */ BKE_object_free_curve_cache(newob); } @@ -2826,7 +2893,7 @@ void OBJECT_OT_join_shapes(wmOperatorType *ot) { /* identifiers */ ot->name = "Join as Shapes"; - ot->description = "Merge selected objects to shapes of active object"; + ot->description = "Copy the current resulting shape of another selected object to this one"; ot->idname = "OBJECT_OT_join_shapes"; /* api callbacks */ diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 6164958bf2c..410ccccbd0d 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -707,7 +707,7 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re /* create new mesh with edit mode changes and modifiers applied */ static Mesh *bake_mesh_new_from_object(Object *object) { - Mesh *me = BKE_object_to_mesh(NULL, object, false); + Mesh *me = BKE_mesh_new_from_object(NULL, object, false); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -927,7 +927,7 @@ static int bake(Render *re, } } else if (is_cage) { - BKE_object_eval_reset(ob_low_eval); + bool is_changed = false; ModifierData *md = ob_low_eval->modifiers.first; while (md) { @@ -942,11 +942,23 @@ static int bake(Render *re, if (md->type == eModifierType_EdgeSplit) { BLI_remlink(&ob_low_eval->modifiers, md); modifier_free(md); + is_changed = true; } md = md_next; } - me_cage = BKE_object_to_mesh(NULL, ob_low_eval, false); + if (is_changed) { + /* Make sure object is evaluated with the new modifier settings. + * + * NOTE: Since the dependency graph was fully evaluated prior to bake, and we only made + * single modification to this object all the possible dependencies for evaluation are + * already up to date. This means we can do a cheap single object update + * (as an opposite of full depsgraph update). */ + BKE_object_eval_reset(ob_low_eval); + BKE_object_handle_data_update(depsgraph, scene, ob_low_eval); + } + + me_cage = BKE_mesh_new_from_object(NULL, ob_low_eval, false); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -965,7 +977,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = BKE_object_to_mesh(NULL, highpoly[i].ob_eval, false); + highpoly[i].me = BKE_mesh_new_from_object(NULL, highpoly[i].ob_eval, false); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1088,7 +1100,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_object_to_mesh(NULL, ob_low_eval, false); + me_nores = BKE_mesh_new_from_object(NULL, ob_low_eval, false); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, @@ -1098,7 +1110,7 @@ static int bake(Render *re, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_object_to_mesh_clear(ob_low_eval); + BKE_id_free(NULL, &me_nores->id); if (md) { md->mode = mode; @@ -1221,8 +1233,8 @@ cleanup: if (highpoly) { int i; for (i = 0; i < tot_highpoly; i++) { - if (highpoly[i].ob_eval) { - BKE_object_to_mesh_clear(highpoly[i].ob_eval); + if (highpoly[i].me != NULL) { + BKE_id_free(NULL, &highpoly[i].me->id); } } MEM_freeN(highpoly); @@ -1252,12 +1264,12 @@ cleanup: MEM_freeN(result); } - if (ob_low_eval) { - BKE_object_to_mesh_clear(ob_low_eval); + if (me_low != NULL) { + BKE_id_free(NULL, &me_low->id); } - if (ob_cage_eval) { - BKE_object_to_mesh_clear(ob_cage_eval); + if (me_cage != NULL) { + BKE_id_free(NULL, &me_cage->id); } DEG_graph_free(depsgraph); diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 53bc037c736..5ef133e87de 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -34,6 +34,7 @@ #include "BLT_translation.h" #include "DNA_anim_types.h" +#include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_curve_types.h" #include "DNA_scene_types.h" @@ -53,6 +54,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #ifdef WITH_PYTHON # include "BPY_extern.h" @@ -861,94 +863,107 @@ void CONSTRAINT_OT_limitdistance_reset(wmOperatorType *ot) /* ------------- Child-Of Constraint ------------------ */ -static void child_get_inverse_matrix(const bContext *C, - Scene *scene, - Object *ob, - bConstraint *con, - float invmat[4][4], - const int owner) +static void child_get_inverse_matrix_owner_bone( + const bContext *C, wmOperator *op, Scene *scene, Object *ob, float invmat[4][4]) { + /* For bone owner we want to do this in evaluated domain. + * BKE_pose_where_is / BKE_pose_where_is_bone relies on (re)evaluating parts of the scene + * and copying new evaluated stuff back to original. + */ Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bConstraint *con_eval = edit_constraint_property_get(op, ob_eval, CONSTRAINT_TYPE_CHILDOF); /* nullify inverse matrix first */ unit_m4(invmat); - if (owner == EDIT_CONSTRAINT_OWNER_BONE) { - bPoseChannel *pchan; - /* try to find a pose channel - assume that this is the constraint owner */ - /* TODO: get from context instead? */ - if (ob && ob->pose && (pchan = BKE_pose_channel_active(ob))) { - bConstraint *con_last; - /* calculate/set inverse matrix: - * We just calculate all transform-stack eval up to but not including this constraint. - * This is because inverse should just inverse correct for just the constraint's influence - * when it gets applied; that is, at the time of application, we don't know anything about - * what follows. - */ - float imat[4][4], tmat[4][4]; - float pmat[4][4]; + bPoseChannel *pchan_eval = BKE_pose_channel_active(ob_eval); - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&pchan->constraints, con) != -1); + /* try to find a pose channel - assume that this is the constraint owner */ + /* TODO: get from context instead? */ + if (ob_eval && ob_eval->pose && pchan_eval) { + bConstraint *con_last; - /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), - * to use as baseline ("pmat") to derive delta from. This extra calc saves users - * from having pressing "Clear Inverse" first - */ - BKE_pose_where_is(depsgraph, scene, ob); - copy_m4_m4(pmat, pchan->pose_mat); + /* calculate/set inverse matrix: + * We just calculate all transform-stack eval up to but not including this constraint. + * This is because inverse should just inverse correct for just the constraint's influence + * when it gets applied; that is, at the time of application, we don't know anything about + * what follows. + */ + float imat[4][4], tmat[4][4]; + float pmat[4][4]; - /* 2. knock out constraints starting from this one */ - con_last = pchan->constraints.last; - pchan->constraints.last = con->prev; + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&pchan_eval->constraints, con_eval) != -1); - if (con->prev) { - /* new end must not point to this one, else this chain cutting is useless */ - con->prev->next = NULL; - } - else { - /* constraint was first */ - pchan->constraints.first = NULL; - } + /* 1. calculate posemat where inverse doesn't exist yet (inverse was cleared above), + * to use as baseline ("pmat") to derive delta from. This extra calc saves users + * from having pressing "Clear Inverse" first + */ + BKE_pose_where_is(depsgraph, scene, ob_eval); + copy_m4_m4(pmat, pchan_eval->pose_mat); - /* 3. solve pose without disabled constraints */ - BKE_pose_where_is(depsgraph, scene, ob); + /* 2. knock out constraints starting from this one */ + con_last = pchan_eval->constraints.last; + pchan_eval->constraints.last = con_eval->prev; - /* 4. determine effect of constraint by removing the newly calculated - * pchan->pose_mat from the original pchan->pose_mat, thus determining - * the effect of the constraint - */ - invert_m4_m4(imat, pchan->pose_mat); - mul_m4_m4m4(tmat, pmat, imat); - invert_m4_m4(invmat, tmat); + if (con_eval->prev) { + /* new end must not point to this one, else this chain cutting is useless */ + con_eval->prev->next = NULL; + } + else { + /* constraint was first */ + pchan_eval->constraints.first = NULL; + } - /* 5. restore constraints */ - pchan->constraints.last = con_last; + /* 3. solve pose without disabled constraints */ + BKE_pose_where_is(depsgraph, scene, ob_eval); - if (con->prev) { - /* hook up prev to this one again */ - con->prev->next = con; - } - else { - /* set as first again */ - pchan->constraints.first = con; - } + /* 4. determine effect of constraint by removing the newly calculated + * pchan->pose_mat from the original pchan->pose_mat, thus determining + * the effect of the constraint + */ + invert_m4_m4(imat, pchan_eval->pose_mat); + mul_m4_m4m4(tmat, pmat, imat); + invert_m4_m4(invmat, tmat); + + /* 5. restore constraints */ + pchan_eval->constraints.last = con_last; - /* 6. recalculate pose with new inv-mat applied */ - BKE_pose_where_is(depsgraph, scene, ob); + if (con_eval->prev) { + /* hook up prev to this one again */ + con_eval->prev->next = con_eval; } + else { + /* set as first again */ + pchan_eval->constraints.first = con_eval; + } + + /* 6. recalculate pose with new inv-mat applied */ + /* this one is unnecessary? (DEG seems to update correctly without) + + if we leave this in, we have to click "Set Inverse" twice to see updates... + BKE_pose_where_is(depsgraph, scene, ob_eval); */ } - if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { - if (ob) { - Object workob; +} - /* make sure we passed the correct constraint */ - BLI_assert(BLI_findindex(&ob->constraints, con) != -1); +static void child_get_inverse_matrix_owner_object( + const bContext *C, Scene *scene, Object *ob, bConstraint *con, float invmat[4][4]) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); - /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ - BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); - invert_m4_m4(invmat, workob.obmat); - } + /* nullify inverse matrix first */ + unit_m4(invmat); + + if (ob) { + Object workob; + + /* make sure we passed the correct constraint */ + BLI_assert(BLI_findindex(&ob->constraints, con) != -1); + UNUSED_VARS_NDEBUG(con); + + /* use BKE_object_workob_calc_parent to find inverse - just like for normal parenting */ + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + invert_m4_m4(invmat, workob.obmat); } } @@ -969,7 +984,12 @@ static int childof_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + child_get_inverse_matrix_owner_object(C, scene, ob, con, data->invmat); + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + child_get_inverse_matrix_owner_bone(C, op, scene, ob, data->invmat); + } ED_object_constraint_update(bmain, ob); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); @@ -1203,6 +1223,7 @@ void CONSTRAINT_OT_followpath_path_animate(wmOperatorType *ot) static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = ED_object_active_context(C); bConstraint *con = edit_constraint_property_get(op, ob, CONSTRAINT_TYPE_OBJECTSOLVER); @@ -1216,8 +1237,14 @@ static int objectsolver_set_inverse_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - child_get_inverse_matrix(C, scene, ob, con, data->invmat, owner); + if (owner == EDIT_CONSTRAINT_OWNER_OBJECT) { + child_get_inverse_matrix_owner_object(C, scene, ob, con, data->invmat); + } + else if (owner == EDIT_CONSTRAINT_OWNER_BONE) { + child_get_inverse_matrix_owner_bone(C, op, scene, ob, data->invmat); + } + ED_object_constraint_update(bmain, ob); WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); return OPERATOR_FINISHED; @@ -1789,10 +1816,15 @@ static bool get_new_constraint_target( */ if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && (!only_curve && !only_mesh)) { - /* just use the active bone, and assume that it is visible + usable */ - *tar_ob = ob; - *tar_pchan = BKE_pose_channel_active(ob); - found = true; + + /* Only use the object & bone if the bone is visible & selected + * since we may have multiple objects in pose mode at once. */ + bPoseChannel *pchan = BKE_pose_channel_active_or_first_selected(ob); + if (pchan != NULL) { + *tar_pchan = pchan; + *tar_ob = ob; + found = true; + } break; } diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index afdda8d6b7f..da06707ebac 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -119,18 +119,27 @@ void ED_object_base_select(Base *base, eObjectSelect_Mode mode) } /** + * Call when the active base has changed. + */ +void ED_object_base_active_refresh(Main *bmain, Scene *scene, ViewLayer *view_layer) +{ + WM_main_add_notifier(NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + struct wmMsgBus *mbus = ((wmWindowManager *)bmain->wm.first)->message_bus; + if (mbus != NULL) { + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } +} + +/** * Change active base, it includes the notifier */ void ED_object_base_activate(bContext *C, Base *base) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); view_layer->basact = base; - - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - DEG_id_tag_update(&CTX_data_scene(C)->id, ID_RECALC_SELECT); + ED_object_base_active_refresh(CTX_data_main(C), scene, view_layer); } bool ED_object_base_deselect_all_ex(ViewLayer *view_layer, diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 394fea2cf27..9c98fdc2a2e 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -466,6 +466,8 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob Object workob; Object *ob_child; + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + /* a change was made, adjust the children to compensate */ for (ob_child = bmain->objects.first; ob_child; ob_child = ob_child->id.next) { if (ob_child->parent == ob) { @@ -475,6 +477,14 @@ static void ignore_parent_tx(Main *bmain, Depsgraph *depsgraph, Scene *scene, Ob invert_m4_m4(ob_child->parentinv, workob.obmat); /* Copy result of BKE_object_apply_mat4(). */ BKE_object_transform_copy(ob_child, ob_child_eval); + /* Make sure evaluated object is in a consistent state with the original one. + * It might be needed for applying transform on its children. */ + copy_m4_m4(ob_child_eval->parentinv, ob_child->parentinv); + BKE_object_eval_transform_all(depsgraph, scene_eval, ob_child_eval); + /* Tag for update. + * This is because parent matrix did change, so in theory the child object might now be + * evaluated to a different location in another editing context. */ + DEG_id_tag_update(&ob_child->id, ID_RECALC_TRANSFORM); } } } @@ -537,7 +547,7 @@ static int apply_objects_internal(bContext *C, { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; @@ -965,7 +975,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); Object *obedit = CTX_data_edit_object(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); + Depsgraph *depsgraph = CTX_data_evaluated_depsgraph(C); Object *tob; float cent[3], cent_neg[3], centn[3]; const float *cursor = scene->cursor.location; @@ -1052,7 +1062,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) /* move active first */ if (ob == obact) { - memmove(&objects[1], objects, object_index); + memmove(&objects[1], objects, object_index * sizeof(Object *)); objects[0] = ob; } } @@ -1217,8 +1227,10 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) arm->id.tag |= LIB_TAG_DOIT; /* do_inverse_offset = true; */ /* docenter_armature() handles this */ - BKE_object_where_is_calc(depsgraph, scene, ob); - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); + BKE_pose_where_is(depsgraph, scene, ob_eval); /* needed for bone parents */ ignore_parent_tx(bmain, depsgraph, scene, ob); @@ -1353,9 +1365,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) add_v3_v3(ob->loc, centn); - BKE_object_where_is_calc(depsgraph, scene, ob); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + BKE_object_transform_copy(ob_eval, ob); + BKE_object_where_is_calc(depsgraph, scene, ob_eval); if (ob->type == OB_ARMATURE) { - BKE_pose_where_is(depsgraph, scene, ob); /* needed for bone parents */ + /* needed for bone parents */ + BKE_pose_where_is(depsgraph, scene, ob_eval); } ignore_parent_tx(bmain, depsgraph, scene, ob); @@ -1378,10 +1393,12 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) mul_v3_mat3_m4v3(centn, ob_other->obmat, cent); /* omit translation part */ add_v3_v3(ob_other->loc, centn); - BKE_object_where_is_calc(depsgraph, scene, ob_other); + Object *ob_other_eval = DEG_get_evaluated_object(depsgraph, ob_other); + BKE_object_transform_copy(ob_other_eval, ob_other); + BKE_object_where_is_calc(depsgraph, scene, ob_other_eval); if (ob_other->type == OB_ARMATURE) { /* needed for bone parents */ - BKE_pose_where_is(depsgraph, scene, ob_other); + BKE_pose_where_is(depsgraph, scene, ob_other_eval); } ignore_parent_tx(bmain, depsgraph, scene, ob_other); } @@ -1490,7 +1507,7 @@ void OBJECT_OT_origin_set(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /** \name Transform Axis Target * - * Note this is an experemental operator to point lights/cameras at objects. + * Note this is an experimental operator to point lights/cameras at objects. * We may re-work how this behaves based on user feedback. * - campbell. * \{ */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 678f6f50096..4f61443ac54 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3278,9 +3278,18 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob_ctx = ED_object_context(C); - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( - view_layer, CTX_wm_view3d(C), &objects_len, ob_ctx->mode); + uint objects_len; + Object **objects; + if (ob_ctx->mode == OB_MODE_WEIGHT_PAINT) { + /* Until weight paint supports multi-edit, use only the active. */ + objects_len = 1; + objects = &ob_ctx; + } + else { + objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + view_layer, CTX_wm_view3d(C), &objects_len, ob_ctx->mode); + } + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *ob = objects[ob_index]; @@ -3296,7 +3305,9 @@ static int vertex_group_smooth_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); } - MEM_freeN(objects); + if (objects != &ob_ctx) { + MEM_freeN(objects); + } return OPERATOR_FINISHED; } diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index dc634865a0a..4e6022cf18c 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -97,23 +97,38 @@ bool PE_poll(bContext *C) Object *ob = CTX_data_active_object(C); if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { - return 0; + return false; + } + + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit == NULL) { + return false; } - return (PE_get_current(scene, ob) != NULL); + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { + return false; + } + + return true; } bool PE_hair_poll(bContext *C) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - PTCacheEdit *edit; if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { - return 0; + return false; } - edit = PE_get_current(scene, ob); - return (edit && edit->psys); + PTCacheEdit *edit = PE_get_current(scene, ob); + if (edit == NULL || edit->psys == NULL) { + return false; + } + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { + return false; + } + + return true; } bool PE_poll_view3d(bContext *C) @@ -322,10 +337,13 @@ static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *o } } - if (edit) { + /* Don't consider inactive or render dependency graphs, since they might be evaluated for a + * different number of childrem. or have different pointer to evaluated particle system or + * modifier which will also cause troubles. */ + if (edit && DEG_is_active(depsgraph)) { edit->pid = *pid; if (edit->flags & PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL) { - if (edit->psys != NULL) { + if (edit->psys != NULL && edit->psys_eval != NULL) { psys_copy_particles(edit->psys, edit->psys_eval); pe_update_hair_particle_edit_pointers(edit); } @@ -1085,7 +1103,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) edit = psys->edit; psmd_eval = edit->psmd_eval; - if (!psmd_eval->mesh_final) { + if (psmd_eval == NULL || psmd_eval->mesh_final == NULL) { return; } @@ -1217,7 +1235,7 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) psys = edit->psys; - if (!edit->psmd_eval->mesh_final) { + if (edit->psmd_eval == NULL || edit->psmd_eval->mesh_final == NULL) { return; } @@ -1489,7 +1507,7 @@ void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edi KEY_K; float hairmat[4][4]; - if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL) { + if (psys == 0 || psys->edit == 0 || psmd_eval == NULL || psmd_eval->mesh_final == NULL) { return; } diff --git a/source/blender/editors/physics/particle_edit_undo.c b/source/blender/editors/physics/particle_edit_undo.c index be625eb939f..40d90676487 100644 --- a/source/blender/editors/physics/particle_edit_undo.c +++ b/source/blender/editors/physics/particle_edit_undo.c @@ -252,7 +252,8 @@ static bool particle_undosys_step_encode(struct bContext *C, static void particle_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { /* TODO(campbell): undo_system: use low-level API to set mode. */ ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT); diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index dc4ce138d9d..dc3673c972f 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -46,6 +46,7 @@ #include "DEG_depsgraph.h" #include "ED_screen.h" +#include "ED_object.h" #include "WM_types.h" #include "WM_api.h" @@ -1216,7 +1217,7 @@ static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( return OPERATOR_CANCELLED; } - if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), true)) { + if (!fluidsimBake(C, op->reports, ED_object_context(C), true)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 352593a15ad..9ac93f07300 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -914,7 +914,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even wmJob *wm_job; RenderJob *rj; Image *ima; - int jobflag; const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); @@ -973,12 +972,6 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* ensure at least 1 area shows result */ sa = render_view_open(C, event->x, event->y, op->reports); - jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; - - if (RNA_struct_property_is_set(op->ptr, "layer")) { - jobflag |= WM_JOB_SUSPEND; - } - /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = bmain; @@ -1038,12 +1031,20 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even name = "Render"; } - wm_job = WM_jobs_get( - CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER); + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + scene, + name, + WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, + WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); + if (RNA_struct_property_is_set(op->ptr, "layer")) { + WM_jobs_delay_start(wm_job, 0.2); + } + /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 35130988aba..fbabdc2f3c1 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1208,19 +1208,13 @@ static void icon_preview_startjob_all_sizes(void *customdata, IconPreview *ip = (IconPreview *)customdata; IconPreviewSize *cur_size; - /* 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. */ - for (int i = 0; i < 20; i++) { - PIL_sleep_ms(100); - if (*stop) { - return; - } - } - 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; @@ -1265,10 +1259,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, common_preview_startjob(sp, stop, do_update, progress); shader_preview_free(sp); - - if (*stop) { - break; - } } } @@ -1350,8 +1340,13 @@ void ED_preview_icon_render( BLI_freelistN(&ip.sizes); } -void ED_preview_icon_job( - const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) +void ED_preview_icon_job(const bContext *C, + void *owner, + ID *id, + unsigned int *rect, + int sizex, + int sizey, + const bool delay) { wmJob *wm_job; IconPreview *ip, *old_ip; @@ -1363,7 +1358,7 @@ void ED_preview_icon_job( CTX_wm_window(C), owner, "Icon Preview", - WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, + WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); ip = MEM_callocN(sizeof(IconPreview), "icon preview"); @@ -1396,6 +1391,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_delay_start(wm_job, (delay) ? 2.0 : 0.0); WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index fc771e0db77..af1e0eeed79 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -47,17 +47,6 @@ /* ******************************************** */ -/* Invert line handling */ - -#define GL_TOGGLE(mode, onoff) (((onoff) ? glEnable : glDisable)(mode)) - -void set_inverted_drawing(int enable) -{ - glLogicOp(enable ? GL_INVERT : GL_COPY); - GL_TOGGLE(GL_COLOR_LOGIC_OP, enable); - GL_TOGGLE(GL_DITHER, !enable); -} - static int get_cached_work_texture(int *r_w, int *r_h) { static GLint texid = -1; @@ -486,6 +475,9 @@ void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, float bglPolygonOffsetCalc(const float winmat[16], float viewdist, float dist) { + /* Seems like we have a factor of 2 more offset than 2.79 for some reason. Correct for this. */ + dist *= 0.5f; + if (winmat[15] > 0.5f) { #if 1 return 0.00001f * dist * viewdist; // ortho tweaking diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index ef99d39f990..c9a45728bc2 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -74,6 +74,7 @@ #include "ED_clip.h" #include "ED_image.h" #include "ED_keyframes_draw.h" +#include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" #include "ED_screen_types.h" @@ -371,6 +372,12 @@ bool ED_operator_object_active_editable_font(bContext *C) return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && (ob->type == OB_FONT)); } +bool ED_operator_editable_mesh(bContext *C) +{ + Mesh *mesh = ED_mesh_context(C); + return (mesh != NULL) && !ID_IS_LINKED(mesh); +} + bool ED_operator_editmesh(bContext *C) { Object *obedit = CTX_data_edit_object(C); @@ -4200,6 +4207,7 @@ static int match_region_with_redraws(int spacetype, static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); + wmWindow *win = CTX_wm_window(C); #ifdef PROFILE_AUDIO_SYNCH static int old_frame = 0; @@ -4209,8 +4217,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv if (screen->animtimer && screen->animtimer == event->customdata) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = WM_window_get_active_view_layer(win); + Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); + Scene *scene_eval = (depsgraph != NULL) ? DEG_get_evaluated_scene(depsgraph) : NULL; wmTimer *wt = screen->animtimer; ScreenAnimData *sad = wt->customdata; wmWindowManager *wm = CTX_wm_manager(C); @@ -4230,7 +4239,11 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv sync = (scene->flag & SCE_FRAME_DROP); } - if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { + if (scene_eval == NULL) { + /* Happens when undo/redo system is used during playback, nothing meaningful we can do here. + */ + } + else if (scene_eval->id.recalc & ID_RECALC_AUDIO_SEEK) { /* Ignore seek here, the audio will be updated to the scene frame after jump during next * dependency graph update. */ } @@ -4335,7 +4348,9 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } /* since we follow drawflags, we can't send notifier but tag regions ourselves */ - ED_update_for_newframe(bmain, depsgraph); + if (depsgraph != NULL) { + ED_update_for_newframe(bmain, depsgraph); + } for (window = wm->windows.first; window; window = window->next) { const bScreen *win_screen = WM_window_get_active_screen(window); diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index 86be939d41b..26849edeb44 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -298,7 +298,7 @@ void ED_screen_user_menu_register(void) { MenuType *mt = MEM_callocN(sizeof(MenuType), __func__); strcpy(mt->idname, "SCREEN_MT_user_menu"); - strcpy(mt->label, "Quick Favorites"); + strcpy(mt->label, N_("Quick Favorites")); strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); mt->draw = screen_user_menu_draw; WM_menutype_add(mt); diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index e5552314a6e..005c76d26b0 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -110,24 +110,6 @@ static void screenshot_data_free(wmOperator *op) } } -static void screenshot_crop(ImBuf *ibuf, rcti crop) -{ - unsigned int *to = ibuf->rect; - unsigned int *from = ibuf->rect + crop.ymin * ibuf->x + crop.xmin; - int crop_x = BLI_rcti_size_x(&crop); - int crop_y = BLI_rcti_size_y(&crop); - int y; - - if (crop_x > 0 && crop_y > 0) { - for (y = 0; y < crop_y; y++, to += crop_x, from += ibuf->x) { - memmove(to, from, sizeof(unsigned int) * crop_x); - } - - ibuf->x = crop_x; - ibuf->y = crop_y; - } -} - static int screenshot_exec(bContext *C, wmOperator *op) { ScreenshotData *scd = op->customdata; @@ -153,7 +135,8 @@ static int screenshot_exec(bContext *C, wmOperator *op) /* crop to show only single editor */ if (!RNA_boolean_get(op->ptr, "full")) { - screenshot_crop(ibuf, scd->crop); + IMB_rect_crop(ibuf, &scd->crop); + scd->dumprect = ibuf->rect; } if (scd->im_format.planes == R_IMF_PLANES_BW) { diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index f4138dd7847..61b737589c8 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -331,30 +331,6 @@ static void WORKSPACE_OT_delete(wmOperatorType *ot) ot->exec = workspace_delete_exec; } -static bool workspace_append_activate_poll(bContext *C) -{ - wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false); - return WM_operator_poll(C, ot); -} - -static int workspace_append(bContext *C, const char *directory, const char *idname) -{ - wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false); - PointerRNA opptr; - int retval; - - WM_operator_properties_create_ptr(&opptr, ot); - RNA_string_set(&opptr, "directory", directory); - RNA_string_set(&opptr, "filename", idname); - RNA_boolean_set(&opptr, "autoselect", false); - - retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr); - - WM_operator_properties_free(&opptr); - - return retval; -} - static int workspace_append_activate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -367,23 +343,20 @@ static int workspace_append_activate_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "idname", idname); RNA_string_get(op->ptr, "filepath", filepath); - if (workspace_append(C, filepath, idname) != OPERATOR_CANCELLED) { - WorkSpace *appended_workspace = BLI_findstring( - &bmain->workspaces, idname, offsetof(ID, name) + 2); - BLI_assert(appended_workspace != NULL); + WorkSpace *appended_workspace = (WorkSpace *)WM_file_append_datablock( + C, filepath, ID_WS, idname); - if (appended_workspace) { - /* Set defaults. */ - BLO_update_defaults_workspace(appended_workspace, NULL); + if (appended_workspace) { + /* Set defaults. */ + BLO_update_defaults_workspace(appended_workspace, NULL); - /* Reorder to last position. */ - BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); + /* Reorder to last position. */ + BKE_id_reorder(&bmain->workspaces, &appended_workspace->id, NULL, true); - /* Changing workspace changes context. Do delayed! */ - WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); + /* Changing workspace changes context. Do delayed! */ + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace); - return OPERATOR_FINISHED; - } + return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -398,7 +371,6 @@ static void WORKSPACE_OT_append_activate(wmOperatorType *ot) /* api callbacks */ ot->exec = workspace_append_activate_exec; - ot->poll = workspace_append_activate_poll; RNA_def_string(ot->srna, "idname", @@ -449,25 +421,21 @@ static void workspace_append_button(uiLayout *layout, { const ID *id = (ID *)workspace; PointerRNA opptr; - char lib_path[FILE_MAX_LIBEXTRA]; const char *filepath = from_main->name; if (strlen(filepath) == 0) { filepath = BLO_EMBEDDED_STARTUP_BLEND; } - BLI_path_join(lib_path, sizeof(lib_path), filepath, BKE_idcode_to_name(GS(id->name)), NULL); - BLI_assert(STREQ(ot_append->idname, "WORKSPACE_OT_append_activate")); uiItemFullO_ptr( layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &opptr); RNA_string_set(&opptr, "idname", id->name + 2); - RNA_string_set(&opptr, "filepath", lib_path); + RNA_string_set(&opptr, "filepath", filepath); } -static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) +static void workspace_add_menu(bContext *UNUSED(C), uiLayout *layout, void *template_v) { - Main *bmain = CTX_data_main(C); const char *app_template = template_v; bool has_startup_items = false; @@ -479,10 +447,6 @@ static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) for (WorkSpace *workspace = startup_config->workspaces.first; workspace; workspace = workspace->id.next) { uiLayout *row = uiLayoutRow(layout, false); - if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { - uiLayoutSetActive(row, false); - } - workspace_append_button(row, ot_append, workspace, startup_config->main); has_startup_items = true; } @@ -506,10 +470,6 @@ static void workspace_add_menu(bContext *C, uiLayout *layout, void *template_v) } uiLayout *row = uiLayoutRow(layout, false); - if (BLI_findstring(&bmain->workspaces, workspace->id.name, offsetof(ID, name))) { - uiLayoutSetActive(row, false); - } - workspace_append_button(row, ot_append, workspace, builtin_config->main); } } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 65e24cecf82..ac74afce79e 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -964,9 +964,9 @@ static void paint_draw_curve_cursor(Brush *brush, ViewContext *vc) immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); float selec_col[4], handle_col[4], pivot_col[4]; - UI_GetThemeColor4fv(TH_VERTEX_SELECT, selec_col); - UI_GetThemeColor4fv(TH_PAINT_CURVE_HANDLE, handle_col); - UI_GetThemeColor4fv(TH_PAINT_CURVE_PIVOT, pivot_col); + UI_GetThemeColorType4fv(TH_VERTEX_SELECT, SPACE_VIEW3D, selec_col); + UI_GetThemeColorType4fv(TH_PAINT_CURVE_HANDLE, SPACE_VIEW3D, handle_col); + UI_GetThemeColorType4fv(TH_PAINT_CURVE_PIVOT, SPACE_VIEW3D, pivot_col); for (i = 0; i < pc->tot_points - 1; i++, cp++) { int j; diff --git a/source/blender/editors/sculpt_paint/paint_curve_undo.c b/source/blender/editors/sculpt_paint/paint_curve_undo.c index c03cb69df88..7e283274383 100644 --- a/source/blender/editors/sculpt_paint/paint_curve_undo.c +++ b/source/blender/editors/sculpt_paint/paint_curve_undo.c @@ -122,7 +122,8 @@ static bool paintcurve_undosys_step_encode(struct bContext *C, static void paintcurve_undosys_step_decode(struct bContext *UNUSED(C), struct Main *UNUSED(bmain), UndoStep *us_p, - int UNUSED(dir)) + int UNUSED(dir), + bool UNUSED(is_final)) { PaintCurveUndoStep *us = (PaintCurveUndoStep *)us_p; undocurve_to_paintcurve(&us->data, us->pc); diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index dded9fcf45a..d7e1b47d973 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -126,7 +126,8 @@ static void partialvis_update_mesh(Object *ob, /* Hide or show elements in multires grids with a special GridFlags * customdata layer. */ -static void partialvis_update_grids(Object *ob, +static void partialvis_update_grids(Depsgraph *depsgraph, + Object *ob, PBVH *pbvh, PBVHNode *node, PartialVisAction action, @@ -208,7 +209,7 @@ static void partialvis_update_grids(Object *ob, if (any_changed) { BKE_pbvh_node_mark_rebuild_draw(node); BKE_pbvh_node_fully_hidden_set(node, !any_visible); - multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED); } } @@ -378,7 +379,7 @@ static int hide_show_exec(bContext *C, wmOperator *op) partialvis_update_mesh(ob, pbvh, nodes[i], action, area, clip_planes); break; case PBVH_GRIDS: - partialvis_update_grids(ob, pbvh, nodes[i], action, area, clip_planes); + partialvis_update_grids(depsgraph, ob, pbvh, nodes[i], action, area, clip_planes); break; case PBVH_BMESH: partialvis_update_bmesh(ob, pbvh, nodes[i], action, area, clip_planes); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 79731a6752d..22de22e8e59 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -1554,9 +1554,8 @@ static void screen_px_from_persp(const float uv[2], w_int[2] *= wtot_inv; } else { - w[0] = w[1] = w[2] = - /* dummy values for zero area face */ - w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f; + /* Dummy values for zero area face. */ + w[0] = w[1] = w[2] = w_int[0] = w_int[1] = w_int[2] = 1.0f / 3.0f; } /* done re-weighting */ diff --git a/source/blender/editors/sculpt_paint/paint_image_undo.c b/source/blender/editors/sculpt_paint/paint_image_undo.c index bb73d424152..e7f100ebacb 100644 --- a/source/blender/editors/sculpt_paint/paint_image_undo.c +++ b/source/blender/editors/sculpt_paint/paint_image_undo.c @@ -540,10 +540,8 @@ static void image_undosys_step_decode_redo(ImageUndoStep *us) } } -static void image_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int dir) +static void image_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool UNUSED(is_final)) { ImageUndoStep *us = (ImageUndoStep *)us_p; #if 0 diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 0dd2e8ee968..f60ea8410ef 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -167,7 +167,7 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) 0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); @@ -341,7 +341,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * } if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); @@ -528,7 +528,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) } if (multires) { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } sculpt_undo_push_end(); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 316ae6189f0..980b043bf8b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -56,6 +56,7 @@ #include "BKE_paint.h" #include "BKE_report.h" #include "BKE_subsurf.h" +#include "BKE_layer.h" #include "DEG_depsgraph.h" @@ -1305,18 +1306,47 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_toolslots_brush_validate(bmain, &ts->wpaint->paint); } - /* When locked, it's almost impossible to select the pose - * then the object to enter weight paint mode. + /* When locked, it's almost impossible to select the pose-object + * then the mesh-object to enter weight paint mode. + * Even when the object mode is not locked this is inconvenient - so allow in either case. + * * In this case move our pose object in/out of pose mode. - * This is in fits with the convention of selecting multiple objects and entering a mode. */ - if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - Object *ob_arm = modifiers_isDeformedByArmature(ob); - if (ob_arm && (ob_arm->base_flag & BASE_SELECTED)) { - if (ob_arm->mode & OB_MODE_POSE) { - ED_object_posemode_exit_ex(bmain, ob_arm); - } - else { - ED_object_posemode_enter_ex(bmain, ob_arm); + * This is in fits with the convention of selecting multiple objects and entering a mode. + */ + { + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + if (md != NULL) { + /* Can be NULL. */ + View3D *v3d = CTX_wm_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + Object *ob_arm = amd->object; + if (ob_arm != NULL) { + const Base *base_arm = BKE_view_layer_base_find(view_layer, ob_arm); + if (base_arm && BASE_VISIBLE(v3d, base_arm)) { + if (is_mode_set) { + if ((ob_arm->mode & OB_MODE_POSE) != 0) { + ED_object_posemode_exit_ex(bmain, ob_arm); + } + } + else { + /* Only check selected status when entering weight-paint mode + * because we may have multiple armature objects. + * Selecting one will de-select the other, which would leave it in pose-mode + * when exiting weight paint mode. While usable, this looks like inconsistent + * behavior from a user perspective. */ + if (base_arm->flag & BASE_SELECTED) { + if ((ob_arm->mode & OB_MODE_POSE) == 0) { + ED_object_posemode_enter_ex(bmain, ob_arm); + } + } + } + } + } + } } } } @@ -2271,7 +2301,6 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P vwpaint_update_cache_variants(C, wp, ob, itemptr); float mat[4][4]; - float mval[2]; const float brush_alpha_value = BKE_brush_alpha_get(scene, brush); @@ -2321,7 +2350,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); + paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); @@ -3273,12 +3302,12 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P VPaint *vp = ts->vpaint; ViewContext *vc = &vpd->vc; Object *ob = vc->obact; + SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; vwpaint_update_cache_variants(C, vp, ob, itemptr); float mat[4][4]; - float mval[2]; ED_view3d_init_mats_rv3d(ob, vc->rv3d); @@ -3300,7 +3329,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* calculate pivot for rotation around seletion if needed */ /* also needed for "View Selected" on last stroke */ - paint_last_stroke_update(scene, vc->ar, mval); + paint_last_stroke_update(scene, vc->ar, ss->cache->mouse); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ec7cb410f2c..173d6ed5085 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5186,15 +5186,13 @@ static void sculpt_flush_update_step(bContext *C) { Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *ob = CTX_data_active_object(C); - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); SculptSession *ss = ob->sculpt; ARegion *ar = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires; View3D *v3d = CTX_wm_view3d(C); if (mmd != NULL) { - /* NOTE: SubdivCCG is living in the evaluated object. */ - multires_mark_as_modified(ob_eval, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } DEG_id_tag_update(&ob->id, ID_RECALC_SHADING); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 8c8d4487ada..81bb9c35817 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -554,10 +554,10 @@ static void sculpt_undo_restore_list(bContext *C, ListBase *lb) if (BKE_sculpt_multires_active(scene, ob)) { if (rebuild) { - multires_mark_as_modified(ob, MULTIRES_HIDDEN_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_HIDDEN_MODIFIED); } else { - multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED); + multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); } } @@ -1109,10 +1109,8 @@ static void sculpt_undosys_step_decode_redo(struct bContext *C, SculptUndoStep * } } -static void sculpt_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int dir) +static void sculpt_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int dir, bool UNUSED(is_final)) { /* Ensure sculpt mode. */ { diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 30ddd8c7d33..0241a2fbe88 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -104,7 +104,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) } if (RNA_boolean_get(op->ptr, "cache")) { - BKE_sound_cache(sound); + sound->flags |= SOUND_FLAGS_CACHING; } /* hook into UI */ @@ -765,7 +765,8 @@ static int sound_pack_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - sound->packedfile = newPackedFile(op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); + sound->packedfile = BKE_packedfile_new( + op->reports, sound->name, ID_BLEND_PATH(bmain, &sound->id)); BKE_sound_load(bmain, sound); return OPERATOR_FINISHED; @@ -811,7 +812,7 @@ static int sound_unpack_exec(bContext *C, wmOperator *op) "AutoPack is enabled, so image will be packed again on file save"); } - unpackSound(bmain, op->reports, sound, method); + BKE_packedfile_unpack_sound(bmain, op->reports, sound, method); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index 99f9a91775e..e3fa8edd714 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1378,10 +1378,11 @@ static void draw_plane_marker_ex(SpaceClip *sc, immEnd(); } } + immUnbindProgram(); /* Draw sliders. */ if (is_selected_track) { - immUniform1f("dash_factor", 2.0f); /* Solid line */ + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); if (draw_outline) { immUniformThemeColor(TH_MARKER_OUTLINE); @@ -1400,9 +1401,8 @@ static void draw_plane_marker_ex(SpaceClip *sc, px, shdr_pos); } + immUnbindProgram(); } - - immUnbindProgram(); } } diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 83d8133a99e..45479c4253d 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1515,6 +1515,11 @@ static int mode_set_exec(bContext *C, wmOperator *op) sc->mode = mode; + if (sc->mode == SC_MODE_MASKEDIT && sc->view != SC_VIEW_CLIP) { + /* Make sure we are in the right view for mask editing */ + sc->view = SC_VIEW_CLIP; + } + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index c290e3a21d1..7e19ac255f0 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -420,6 +420,14 @@ static void clip_listener(wmWindow *UNUSED(win), ScrArea *sa, wmNotifier *wmn, S ED_area_tag_redraw(sa); } break; + case NC_WM: + switch (wmn->data) { + case ND_FILEREAD: + case ND_UNDO: + clip_area_sync_frame_from_scene(sa, scene); + break; + } + break; } } diff --git a/source/blender/editors/space_clip/tracking_ops_plane.c b/source/blender/editors/space_clip/tracking_ops_plane.c index 89478375658..b1bf88634bc 100644 --- a/source/blender/editors/space_clip/tracking_ops_plane.c +++ b/source/blender/editors/space_clip/tracking_ops_plane.c @@ -74,6 +74,7 @@ static int create_plane_track_tracks_exec(bContext *C, wmOperator *op) BKE_tracking_track_plane_from_existing_motion(plane_track, framenr); } + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); return OPERATOR_FINISHED; @@ -337,8 +338,7 @@ static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent * data->previous_mval[1] = event->mval[1]; copy_v2_v2(data->previous_corner, data->corner); - DEG_id_tag_update(&sc->clip->id, 0); - + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, NULL); break; @@ -355,7 +355,7 @@ static int slide_plane_marker_modal(bContext *C, wmOperator *op, const wmEvent * clip_tracking_show_cursor(C); - DEG_id_tag_update(&sc->clip->id, 0); + DEG_id_tag_update(&clip->id, ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 15f87235c0d..4e50413513a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -1736,7 +1736,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w ((numfiles % items_block_size) != 0 ? items_block_size : 0)) - (numfiles_layout / 2); /* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the - * begining/end of the view. */ + * beginning/end of the view. */ /* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf... * that is why we still need to keep the min/max_middle_offset checks too. :( */ const float min_tot_scroll = is_horizontal ? ar->v2d.tot.xmin : -ar->v2d.tot.ymax; @@ -1747,16 +1747,16 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w /* Check if we have reached our final scroll position. */ /* Filelist has to be ready, otherwise it makes no sense to stop scrolling yet. */ const bool is_ready = filelist_is_ready(sfile->files); - /* Edited item must be in the 'middle' of shown area (kind of approximative). + /* Edited item must be in the 'middle' of shown area (kind of approximated). * Note that we have to do the check in 'block space', not in 'item space' here. */ const bool is_centered = (abs(middle_offset / items_block_size - sfile->scroll_offset / items_block_size) == 0); - /* OR edited item must be towards the begining, and we are scrolled fully to the start. */ + /* OR edited item must be towards the beginning, and we are scrolled fully to the start. */ const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) && (min_curr_scroll - min_tot_scroll < 1.0f) && (middle_offset - min_middle_offset < items_block_size)); /* OR edited item must be towards the end, and we are scrolled fully to the end. - * This one is crucial (unlike the one for the begining), because without it we won't scroll + * This one is crucial (unlike the one for the beginning), because without it we won't scroll * fully to the end, and last column or row wil end up only partially drawn. */ const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) && (max_tot_scroll - max_curr_scroll < 1.0f) && diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 86db6d50fcc..97a3c7f2480 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -797,6 +797,11 @@ void draw_image_main(const bContext *C, ARegion *ar) ima = ED_space_image(sima); ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy); + /* Tag image as in active use for garbage collector. */ + if (ima) { + BKE_image_tag_time(ima); + } + show_viewer = (ima && ima->source == IMA_SRC_VIEWER) != 0; show_render = (show_viewer && ima->type == IMA_TYPE_R_RESULT) != 0; show_paint = (ima && (sima->mode == SI_MODE_PAINT) && (show_viewer == false) && diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 96eaa89d175..b79ed1c83c4 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1391,7 +1391,7 @@ static int image_open_exec(bContext *C, wmOperator *op) BKE_image_init_imageuser(ima, iuser); } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), bmain); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); @@ -1601,7 +1601,7 @@ static int image_replace_exec(bContext *C, wmOperator *op) sima->image->source = IMA_SRC_FILE; } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); BKE_icon_changed(BKE_icon_id_ensure(&sima->image->id)); @@ -2401,7 +2401,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); BKE_image_signal(bmain, ima, iuser, IMA_SIGNAL_RELOAD); @@ -2859,10 +2859,10 @@ static int image_unpack_exec(bContext *C, wmOperator *op) "AutoPack is enabled, so image will be packed again on file save"); } - /* XXX unpackImage frees image buffers */ + /* XXX BKE_packedfile_unpack_image frees image buffers */ ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - unpackImage(CTX_data_main(C), op->reports, ima, method); + BKE_packedfile_unpack_image(CTX_data_main(C), op->reports, ima, method); WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 6bf79711ae5..e8116193c1f 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -843,6 +843,11 @@ static void image_buttons_region_listener(wmWindow *UNUSED(win), ED_region_tag_redraw(ar); } break; + case NC_BRUSH: + if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } + break; } } @@ -946,6 +951,11 @@ static void image_header_region_listener(wmWindow *UNUSED(win), break; } break; + case NC_BRUSH: + if (wmn->action == NA_EDITED) { + ED_region_tag_redraw(ar); + } + break; } } diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index bf43e493cc5..14817e9ffa1 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -65,7 +65,7 @@ static int pack_libraries_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - packLibraries(bmain, op->reports); + BKE_packedfile_pack_all_libraries(bmain, op->reports); return OPERATOR_FINISHED; } @@ -88,7 +88,7 @@ static int unpack_libraries_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - unpackLibraries(bmain, op->reports); + BKE_packedfile_unpack_all_libraries(bmain, op->reports); return OPERATOR_FINISHED; } @@ -124,7 +124,7 @@ static int autopack_toggle_exec(bContext *C, wmOperator *op) G.fileflags &= ~G_FILE_AUTOPACK; } else { - packAll(bmain, op->reports, true); + BKE_packedfile_pack_all(bmain, op->reports, true); G.fileflags |= G_FILE_AUTOPACK; } @@ -151,7 +151,7 @@ static int pack_all_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - packAll(bmain, op->reports, true); + BKE_packedfile_pack_all(bmain, op->reports, true); return OPERATOR_FINISHED; } @@ -221,7 +221,7 @@ static int unpack_all_exec(bContext *C, wmOperator *op) int method = RNA_enum_get(op->ptr, "method"); if (method != PF_KEEP) { - unpackAll(bmain, op->reports, method); /* XXX PF_ASK can't work here */ + BKE_packedfile_unpack_all(bmain, op->reports, method); /* XXX PF_ASK can't work here */ } G.fileflags &= ~G_FILE_AUTOPACK; @@ -236,7 +236,7 @@ static int unpack_all_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED( char title[64]; int count = 0; - count = countPackedFiles(bmain); + count = BKE_packedfile_count_all(bmain); if (!count) { BKE_report(op->reports, RPT_WARNING, "No packed files to unpack"); @@ -321,7 +321,7 @@ static int unpack_item_exec(bContext *C, wmOperator *op) } if (method != PF_KEEP) { - BKE_unpack_id(bmain, id, op->reports, method); /* XXX PF_ASK can't work here */ + BKE_packedfile_id_unpack(bmain, id, op->reports, method); /* XXX PF_ASK can't work here */ } G.fileflags &= ~G_FILE_AUTOPACK; @@ -545,7 +545,8 @@ static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), co /* escape if not our timer */ if ((reports->reporttimer == NULL) || (reports->reporttimer != event->customdata) || - ((report = BKE_reports_last_displayable(reports)) == NULL) /* may have been deleted */ + ((report = BKE_reports_last_displayable(reports)) == NULL) + /* may have been deleted */ ) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index a5755ae43c6..d31256a1425 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -210,6 +210,7 @@ static void compo_initjob(void *cjv) /* NOTE: Don't update animation to preserve unkeyed changes, this means can not use * evaluate_on_framechange. */ + DEG_graph_flush_update(bmain, cj->compositor_depsgraph); DEG_evaluate_on_refresh(cj->compositor_depsgraph); bNodeTree *ntree_eval = (bNodeTree *)DEG_get_evaluated_id(cj->compositor_depsgraph, @@ -2418,6 +2419,7 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) } } + ntree->update |= NTREE_UPDATE_GROUP; ntreeUpdateTree(CTX_data_main(C), ntree); snode_notify(C, snode); diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index b33960bb454..7dec6f5a4ef 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -347,7 +347,7 @@ static int backimage_fit_exec(bContext *C, wmOperator *UNUSED(op)) BKE_image_release_ibuf(ima, ibuf, lock); - snode->zoom *= min_ff(facx, facy); + snode->zoom *= min_ff(facx, facy) * U.dpi_fac; snode->xof = 0; snode->yof = 0; diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 459183ff226..4740c412083 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -593,7 +593,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) if (ID_IS_LINKED(active_collection) || ((active_collection->flag & COLLECTION_IS_MASTER) && ID_IS_LINKED(scene))) { - BKE_report(op->reports, RPT_ERROR, "Cannot add a colection to a linked collection/scene"); + BKE_report(op->reports, RPT_ERROR, "Cannot add a collection to a linked collection/scene"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 86f99555e12..55130ae8894 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -116,6 +116,10 @@ static void outliner_tree_dimensions(SpaceOutliner *soops, int *r_width, int *r_ */ static bool is_object_data_in_editmode(const ID *id, const Object *obact) { + if (id == NULL) { + return false; + } + const short id_type = GS(id->name); if (id_type == ID_GD && obact && obact->data == id) { @@ -929,6 +933,40 @@ static void outliner_restrict_properties_enable_layer_collection_set( } } +static bool outliner_restrict_properties_collection_set(Scene *scene, + TreeElement *te, + PointerRNA *collection_ptr, + PointerRNA *layer_collection_ptr, + RestrictProperties *props, + RestrictPropertiesActive *props_active) +{ + TreeStoreElem *tselem = TREESTORE(te); + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : + NULL; + Collection *collection = outliner_collection_from_tree_element(te); + + if ((collection->flag & COLLECTION_IS_MASTER) || + (layer_collection && ((layer_collection->flag & LAYER_COLLECTION_EXCLUDE) != 0))) { + return false; + } + + /* Create the PointerRNA. */ + RNA_id_pointer_create(&collection->id, collection_ptr); + if (layer_collection != NULL) { + RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr); + } + + /* Update the restriction column values for the collection children. */ + if (layer_collection) { + outliner_restrict_properties_enable_layer_collection_set( + layer_collection_ptr, collection_ptr, props, props_active); + } + else { + outliner_restrict_properties_enable_collection_set(collection_ptr, props, props_active); + } + return true; +} + static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ViewLayer *view_layer, @@ -1333,30 +1371,16 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } else if (outliner_is_collection_tree_element(te)) { - LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - te->directdata : - NULL; - Collection *collection = outliner_collection_from_tree_element(te); - if ((!layer_collection || !(layer_collection->flag & LAYER_COLLECTION_EXCLUDE)) && - !(collection->flag & COLLECTION_IS_MASTER)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; - PointerRNA collection_ptr; - PointerRNA layer_collection_ptr; - RNA_id_pointer_create(&collection->id, &collection_ptr); - if (layer_collection != NULL) { - RNA_pointer_create( - &scene->id, &RNA_LayerCollection, layer_collection, &layer_collection_ptr); - } + if (outliner_restrict_properties_collection_set( + scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { - /* Update the restriction column values for the collection children. */ - if (layer_collection) { - outliner_restrict_properties_enable_layer_collection_set( - &layer_collection_ptr, &collection_ptr, &props, &props_active); - } - else { - outliner_restrict_properties_enable_collection_set( - &collection_ptr, &props, &props_active); - } + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? + te->directdata : + NULL; + Collection *collection = outliner_collection_from_tree_element(te); if (layer_collection != NULL) { if (soops->show_restrict_flags & SO_RESTRICT_HIDE) { @@ -1443,7 +1467,8 @@ static void outliner_draw_restrictbuts(uiBlock *block, layer_collection, (char *)"indirect_only"); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - if (!props_active.layer_collection_indirect_only) { + if (props_active.layer_collection_holdout || + !props_active.layer_collection_indirect_only) { UI_but_flag_enable(bt, UI_BUT_INACTIVE); } } @@ -1558,6 +1583,12 @@ static void outliner_draw_restrictbuts(uiBlock *block, } } } + else if (outliner_is_collection_tree_element(te)) { + PointerRNA collection_ptr; + PointerRNA layer_collection_ptr; + outliner_restrict_properties_collection_set( + scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active); + } if (TSELEM_OPEN(tselem, soops)) { outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree, props_active); @@ -2202,7 +2233,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break; case OB_EMPTY: - if (ob->instance_collection) { + if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; } else if (ob->empty_drawtype == OB_EMPTY_IMAGE) { diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index e1e7bf49606..89eb3b9d953 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -109,8 +109,9 @@ static void set_operation_types(SpaceOutliner *soops, } } else { - int idcode = GS(tselem->id->name); - switch (idcode) { + const int idcode = (int)GS(tselem->id->name); + bool is_standard_id = false; + switch ((ID_Type)idcode) { case ID_SCE: *scenelevel = 1; break; @@ -134,21 +135,47 @@ static void set_operation_types(SpaceOutliner *soops, case ID_KE: case ID_WO: case ID_AC: - case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: case ID_LI: - if (*idlevel == 0) { - *idlevel = idcode; - } - else if (*idlevel != idcode) { - *idlevel = -1; - } - if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { - *datalevel = 0; - } + case ID_VF: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_GD: + case ID_MC: + case ID_MSK: + case ID_PAL: + case ID_PC: + case ID_CF: + case ID_WS: + case ID_LP: + is_standard_id = true; break; + case ID_WM: + case ID_SCR: + /* Those are ignored here. */ + /* Note: while Screens should be manageable here, deleting a screen used by a workspace + * will cause crashes when trying to use that workspace, so for now let's play minimal, + * safe change. */ + break; + } + if (idcode == ID_NLA) { + /* Fake one, not an actual ID type... */ + is_standard_id = true; + } + + if (is_standard_id) { + if (*idlevel == 0) { + *idlevel = idcode; + } + else if (*idlevel != idcode) { + *idlevel = -1; + } + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } } } } @@ -288,31 +315,33 @@ static void unlink_object_cb(bContext *C, TreeStoreElem *tselem, void *UNUSED(user_data)) { - Main *bmain = CTX_data_main(C); - Object *ob = (Object *)tselem->id; + if (tsep && tsep->id) { + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)tselem->id; - if (GS(tsep->id->name) == ID_OB) { - /* Parented objects need to find which collection to unlink from. */ - TreeElement *te_parent = te->parent; - while (tsep && GS(tsep->id->name) == ID_OB) { - te_parent = te_parent->parent; - tsep = te_parent ? TREESTORE(te_parent) : NULL; + if (GS(tsep->id->name) == ID_OB) { + /* Parented objects need to find which collection to unlink from. */ + TreeElement *te_parent = te->parent; + while (tsep && GS(tsep->id->name) == ID_OB) { + te_parent = te_parent->parent; + tsep = te_parent ? TREESTORE(te_parent) : NULL; + } } - } - if (tsep) { - if (GS(tsep->id->name) == ID_GR) { - Collection *parent = (Collection *)tsep->id; - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_SCE) { - Scene *scene = (Scene *)tsep->id; - Collection *parent = BKE_collection_master(scene); - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + if (tsep && tsep->id) { + if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } } } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index d428a190549..cc062467dbe 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -515,7 +515,7 @@ static void outliner_add_object_contents(SpaceOutliner *soops, } /* duplicated group */ - if (ob->instance_collection) { + if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { outliner_add_element(soops, &te->subtree, ob->instance_collection, te, 0, 0); } } @@ -1545,7 +1545,7 @@ static void outliner_make_object_parent_hierarchy_collections(SpaceOutliner *soo if (!found) { /* We add the child in the tree even if it is not in the collection. - * We deliberately clear its subtree though, to make it less proeminent. */ + * We deliberately clear its sub-tree though, to make it less prominent. */ TreeElement *child_ob_tree_element = outliner_add_element( soops, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0); outliner_free_tree(&child_ob_tree_element->subtree); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e53a3cb02a7..76c198b3d6b 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2042,8 +2042,6 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) if (ed) { /* draw the data */ draw_seq_strips(C, ed, ar); - draw_cache_view(C); - /* text draw cached (for sequence names), in pixelspace now */ UI_view2d_text_cache_draw(ar); } @@ -2063,8 +2061,12 @@ void draw_timeline_seq(const bContext *C, ARegion *ar) } ED_markers_draw(C, marker_draw_flag); - /* preview range */ UI_view2d_view_ortho(v2d); + /* draw cache on top of markers area */ + if (ed) { + draw_cache_view(C); + } + /* preview range */ ANIM_draw_previewrange(C, v2d, 1); /* overlap playhead */ diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c index c36175489b3..b6c660ae5b2 100644 --- a/source/blender/editors/space_text/text_autocomplete.c +++ b/source/blender/editors/space_text/text_autocomplete.c @@ -260,7 +260,7 @@ static void get_suggest_prefix(Text *text, int offset) texttool_suggest_prefix(line + i, len); } -static void confirm_suggestion(Text *text, TextUndoBuf *utxt) +static void confirm_suggestion(Text *text) { SuggItem *sel; int i, over = 0; @@ -285,7 +285,7 @@ static void confirm_suggestion(Text *text, TextUndoBuf *utxt) // for (i = 0; i < skipleft; i++) // txt_move_left(text, 0); BLI_assert(memcmp(sel->name, &line[i], over) == 0); - txt_insert_buf(text, utxt, sel->name + over); + txt_insert_buf(text, sel->name + over); // for (i = 0; i < skipleft; i++) // txt_move_right(text, 0); @@ -308,8 +308,8 @@ static int text_autocomplete_invoke(bContext *C, wmOperator *op, const wmEvent * ED_area_tag_redraw(CTX_wm_area(C)); if (texttool_suggest_first() == texttool_suggest_last()) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); text_autocomplete_free(C, op); ED_undo_push(C, op->type->name); @@ -371,8 +371,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case MIDDLEMOUSE: if (event->val == KM_PRESS) { if (text_do_suggest_select(st, ar)) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); ED_undo_push(C, op->type->name); swallow = 1; @@ -410,8 +410,8 @@ static int text_autocomplete_modal(bContext *C, wmOperator *op, const wmEvent *e case PADENTER: if (event->val == KM_PRESS) { if (tools & TOOL_SUGG_LIST) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - confirm_suggestion(st->text, utxt); + ED_text_undo_push_init(C); + confirm_suggestion(st->text); text_update_line_edited(st->text->curl); ED_undo_push(C, op->type->name); swallow = 1; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 63d4f3e3119..8f7bd83cbf4 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -241,6 +241,8 @@ static int text_new_exec(bContext *C, wmOperator *UNUSED(op)) PropertyRNA *prop; text = BKE_text_add(bmain, "Text"); + /* Texts have no user by default... Only the 'real' user flag. */ + id_us_min(&text->id); /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); @@ -307,6 +309,8 @@ static int text_open_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", str); text = BKE_text_load_ex(bmain, str, BKE_main_blendfile_path(bmain), internal); + /* Texts have no user by default... Only the 'real' user flag. */ + id_us_min(&text->id); if (!text) { if (op->customdata) { @@ -322,8 +326,6 @@ static int text_open_exec(bContext *C, wmOperator *op) /* hook into UI */ pprop = op->customdata; - id_us_ensure_real(&text->id); - if (pprop->prop) { RNA_id_pointer_create(&text->id, &idptr); RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr, NULL); @@ -840,7 +842,7 @@ static int text_paste_exec(bContext *C, wmOperator *op) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); /* Convert clipboard content indentation to spaces if specified */ if (text->flags & TXT_TABSTOSPACES) { @@ -849,7 +851,7 @@ static int text_paste_exec(bContext *C, wmOperator *op) buf = new_buf; } - txt_insert_buf(text, utxt, buf); + txt_insert_buf(text, buf); text_update_edited(text); MEM_freeN(buf); @@ -893,9 +895,9 @@ static int text_duplicate_line_exec(bContext *C, wmOperator *UNUSED(op)) { Text *text = CTX_data_edit_text(C); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); - txt_duplicate_line(text, utxt); + txt_duplicate_line(text); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -932,7 +934,7 @@ static void txt_copy_clipboard(Text *text) return; } - buf = txt_sel_to_buf(text); + buf = txt_sel_to_buf(text, NULL); if (buf) { WM_clipboard_text_set(buf, 0); @@ -971,8 +973,8 @@ static int text_cut_exec(bContext *C, wmOperator *UNUSED(op)) txt_copy_clipboard(text); - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_delete_selected(text, utxt); + ED_text_undo_push_init(C); + txt_delete_selected(text); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -1008,14 +1010,14 @@ static int text_indent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (txt_has_sel(text)) { txt_order_cursors(text, false); - txt_indent(text, utxt); + txt_indent(text); } else { - txt_add_char(text, utxt, '\t'); + txt_add_char(text, '\t'); } text_update_edited(text); @@ -1049,10 +1051,10 @@ static int text_unindent_exec(bContext *C, wmOperator *UNUSED(op)) text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_unindent(text, utxt); + txt_unindent(text); text_update_edited(text); @@ -1090,15 +1092,15 @@ static int text_line_break_exec(bContext *C, wmOperator *UNUSED(op)) // double check tabs/spaces before splitting the line curts = txt_setcurr_tab_spaces(text, space); - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_split_curline(text, utxt); + ED_text_undo_push_init(C); + txt_split_curline(text); for (a = 0; a < curts; a++) { if (text->flags & TXT_TABSTOSPACES) { - txt_add_char(text, utxt, ' '); + txt_add_char(text, ' '); } else { - txt_add_char(text, utxt, '\t'); + txt_add_char(text, '\t'); } } @@ -1139,10 +1141,10 @@ static int text_comment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_comment(text, utxt); + txt_comment(text); text_update_edited(text); text_update_cursor_moved(C); @@ -1177,10 +1179,10 @@ static int text_uncomment_exec(bContext *C, wmOperator *UNUSED(op)) if (txt_has_sel(text)) { text_drawcache_tag_update(CTX_wm_space_text(C), 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); txt_order_cursors(text, false); - txt_uncomment(text, utxt); + txt_uncomment(text); text_update_edited(text); text_update_cursor_moved(C); @@ -1446,9 +1448,9 @@ static int move_lines_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); const int direction = RNA_enum_get(op->ptr, "direction"); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); - txt_move_lines(text, utxt, direction); + txt_move_lines(text, direction); text_update_cursor_moved(C); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -2230,13 +2232,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (type == DEL_PREV_WORD) { if (txt_cursor_is_line_start(text)) { - txt_backspace_char(text, utxt); + txt_backspace_char(text); } - txt_backspace_word(text, utxt); + txt_backspace_word(text); } else if (type == DEL_PREV_CHAR) { @@ -2252,13 +2254,13 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_backspace_char(text, utxt); + txt_backspace_char(text); } else if (type == DEL_NEXT_WORD) { if (txt_cursor_is_line_end(text)) { - txt_delete_char(text, utxt); + txt_delete_char(text); } - txt_delete_word(text, utxt); + txt_delete_word(text); } else if (type == DEL_NEXT_CHAR) { @@ -2274,7 +2276,7 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } - txt_delete_char(text, utxt); + txt_delete_char(text); } text_update_line_edited(text->curl); @@ -2994,7 +2996,7 @@ static void text_cursor_set_exit(bContext *C, wmOperator *op) char *buffer; if (txt_has_sel(text)) { - buffer = txt_sel_to_buf(text); + buffer = txt_sel_to_buf(text, NULL); WM_clipboard_text_set(buffer, 1); MEM_freeN(buffer); } @@ -3190,18 +3192,18 @@ static int text_insert_exec(bContext *C, wmOperator *op) str = RNA_string_get_alloc(op->ptr, "text", NULL, 0); - TextUndoBuf *utxt = ED_text_undo_push_init(C); + ED_text_undo_push_init(C); if (st && st->overwrite) { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_replace_char(text, utxt, code); + done |= txt_replace_char(text, code); } } else { while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, &i); - done |= txt_add_char(text, utxt, code); + done |= txt_add_char(text, code); } } @@ -3308,7 +3310,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) /* Replace current */ if (mode != TEXT_FIND && txt_has_sel(text)) { - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); if (flags & ST_MATCH_CASE) { found = STREQ(st->findstr, tmp); @@ -3319,8 +3321,8 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode) if (found) { if (mode == TEXT_REPLACE) { - TextUndoBuf *utxt = ED_text_undo_push_init(C); - txt_insert_buf(text, utxt, st->replacestr); + ED_text_undo_push_init(C); + txt_insert_buf(text, st->replacestr); if (text->curl && text->curl->format) { MEM_freeN(text->curl->format); text->curl->format = NULL; @@ -3406,7 +3408,7 @@ static int text_find_set_selected_exec(bContext *C, wmOperator *op) Text *text = CTX_data_edit_text(C); char *tmp; - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); BLI_strncpy(st->findstr, tmp, ST_MAX_FIND_STR); MEM_freeN(tmp); @@ -3437,7 +3439,7 @@ static int text_replace_set_selected_exec(bContext *C, wmOperator *UNUSED(op)) Text *text = CTX_data_edit_text(C); char *tmp; - tmp = txt_sel_to_buf(text); + tmp = txt_sel_to_buf(text, NULL); BLI_strncpy(st->replacestr, tmp, ST_MAX_FIND_STR); MEM_freeN(tmp); diff --git a/source/blender/editors/space_text/text_undo.c b/source/blender/editors/space_text/text_undo.c index 7db97f15a68..6ecb2b731b0 100644 --- a/source/blender/editors/space_text/text_undo.c +++ b/source/blender/editors/space_text/text_undo.c @@ -25,6 +25,7 @@ #include "DNA_text_types.h" +#include "BLI_array_store.h" #include "BLI_array_utils.h" #include "BLT_translation.h" @@ -35,6 +36,7 @@ #include "BKE_report.h" #include "BKE_text.h" #include "BKE_undo_system.h" +#include "BKE_main.h" #include "WM_api.h" #include "WM_types.h" @@ -53,18 +55,32 @@ #include "text_intern.h" #include "text_format.h" -/* TODO(campbell): undo_system: move text undo out of text block. */ - /* -------------------------------------------------------------------- */ /** \name Implements ED Undo System * \{ */ +#define ARRAY_CHUNK_SIZE 128 + typedef struct TextUndoStep { UndoStep step; UndoRefID_Text text_ref; - TextUndoBuf data; + struct { + BArrayState *state; + int buf_len; + } data; + + struct { + int line, line_select; + int column, column_select; + } cursor; + } TextUndoStep; +static struct { + BArrayStore *buffer_store; + int users; +} g_text_buffers = {NULL}; + static bool text_undosys_poll(bContext *UNUSED(C)) { /* Only use when operators initialized. */ @@ -77,12 +93,8 @@ static void text_undosys_step_encode_init(struct bContext *C, UndoStep *us_p) TextUndoStep *us = (TextUndoStep *)us_p; BLI_assert(BLI_array_is_zeroed(&us->data, 1)); - UNUSED_VARS(C); + UNUSED_VARS(C, us); /* XXX, use to set the undo type only. */ - - us->data.buf = NULL; - us->data.len = 0; - us->data.pos = -1; } static bool text_undosys_step_encode(struct bContext *C, @@ -93,97 +105,71 @@ static bool text_undosys_step_encode(struct bContext *C, Text *text = CTX_data_edit_text(C); - /* No undo data was generated. Hint, use global undo here. */ - if ((us->data.pos == -1) || (us->data.buf == NULL)) { - return false; - } + int buf_len = 0; - us_p->is_applied = true; - - us->text_ref.ptr = text; + uchar *buf = (uchar *)txt_to_buf_for_undo(text, &buf_len); + if (g_text_buffers.buffer_store == NULL) { + g_text_buffers.buffer_store = BLI_array_store_create(1, ARRAY_CHUNK_SIZE); + } + g_text_buffers.users += 1; + const size_t total_size_prev = BLI_array_store_calc_size_compacted_get( + g_text_buffers.buffer_store); - us->step.data_size = us->data.len; + us->data.state = BLI_array_store_state_add(g_text_buffers.buffer_store, buf, buf_len, NULL); + MEM_freeN(buf); - return true; -} + us->cursor.line = txt_get_span(text->lines.first, text->curl); + us->cursor.column = text->curc; -static void text_undosys_step_decode_undo_impl(Text *text, TextUndoStep *us) -{ - BLI_assert(us->step.is_applied == true); - TextUndoBuf data = us->data; - while (data.pos > -1) { - txt_do_undo(text, &data); + if (txt_has_sel(text)) { + us->cursor.line_select = (text->curl == text->sell) ? + us->cursor.line : + txt_get_span(text->lines.first, text->sell); + us->cursor.column_select = text->selc; } - BLI_assert(data.pos == -1); - us->step.is_applied = false; -} - -static void text_undosys_step_decode_redo_impl(Text *text, TextUndoStep *us) -{ - BLI_assert(us->step.is_applied == false); - TextUndoBuf data = us->data; - data.pos = -1; - while (data.pos < us->data.pos) { - txt_do_redo(text, &data); + else { + us->cursor.line_select = us->cursor.line; + us->cursor.column_select = us->cursor.column; } - BLI_assert(data.pos == us->data.pos); - us->step.is_applied = true; -} -static void text_undosys_step_decode_undo(Text *text, TextUndoStep *us) -{ - TextUndoStep *us_iter = us; - while (us_iter->step.next && (us_iter->step.next->type == us_iter->step.type)) { - if (us_iter->step.next->is_applied == false) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.next; - } - while (us_iter != us) { - text_undosys_step_decode_undo_impl(text, us_iter); - us_iter = (TextUndoStep *)us_iter->step.prev; - } -} + us_p->is_applied = true; -static void text_undosys_step_decode_redo(Text *text, TextUndoStep *us) -{ - TextUndoStep *us_iter = us; - while (us_iter->step.prev && (us_iter->step.prev->type == us_iter->step.type)) { - if (us_iter->step.prev->is_applied == true) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.prev; - } - while (us_iter && (us_iter->step.is_applied == false)) { - text_undosys_step_decode_redo_impl(text, us_iter); - if (us_iter == us) { - break; - } - us_iter = (TextUndoStep *)us_iter->step.next; - } + us->text_ref.ptr = text; + + us->step.data_size = BLI_array_store_calc_size_compacted_get(g_text_buffers.buffer_store) - + total_size_prev; + + return true; } static void text_undosys_step_decode(struct bContext *C, struct Main *UNUSED(bmain), UndoStep *us_p, - int dir) + int UNUSED(dir), + bool UNUSED(is_final)) { TextUndoStep *us = (TextUndoStep *)us_p; Text *text = us->text_ref.ptr; + size_t buf_len; - if (dir < 0) { - text_undosys_step_decode_undo(text, us); + { + const uchar *buf = BLI_array_store_state_data_get_alloc(us->data.state, &buf_len); + txt_from_buf_for_undo(text, (const char *)buf, buf_len); + MEM_freeN((void *)buf); } - else { - text_undosys_step_decode_redo(text, us); + + const bool has_select = ((us->cursor.line != us->cursor.line_select) || + (us->cursor.column != us->cursor.column_select)); + if (has_select) { + txt_move_to(text, us->cursor.line_select, us->cursor.column_select, false); } + txt_move_to(text, us->cursor.line, us->cursor.column, has_select); SpaceText *st = CTX_wm_space_text(C); if (st) { /* Not essential, always show text being undo where possible. */ st->text = text; } - text_update_edited(text); text_update_cursor_moved(C); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_EDITED, text); @@ -192,7 +178,14 @@ static void text_undosys_step_decode(struct bContext *C, static void text_undosys_step_free(UndoStep *us_p) { TextUndoStep *us = (TextUndoStep *)us_p; - MEM_SAFE_FREE(us->data.buf); + + BLI_array_store_state_remove(g_text_buffers.buffer_store, us->data.state); + + g_text_buffers.users -= 1; + if (g_text_buffers.users == 0) { + BLI_array_store_destroy(g_text_buffers.buffer_store); + g_text_buffers.buffer_store = NULL; + } } static void text_undosys_foreach_ID_ref(UndoStep *us_p, @@ -228,12 +221,16 @@ void ED_text_undosys_type(UndoType *ut) * \{ */ /* Use operator system to finish the undo step. */ -TextUndoBuf *ED_text_undo_push_init(bContext *C) +UndoStep *ED_text_undo_push_init(bContext *C) { UndoStack *ustack = ED_undo_stack_get(); - UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT); - TextUndoStep *us = (TextUndoStep *)us_p; - return &us->data; + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = bmain->wm.first; + if (wm->op_undo_depth <= 1) { + UndoStep *us_p = BKE_undosys_step_push_init_with_type(ustack, C, NULL, BKE_UNDOSYS_TYPE_TEXT); + return us_p; + } + return NULL; } /** \} */ diff --git a/source/blender/editors/space_userpref/userpref_ops.c b/source/blender/editors/space_userpref/userpref_ops.c index 04ef2ed8118..1ec459ccfca 100644 --- a/source/blender/editors/space_userpref/userpref_ops.c +++ b/source/blender/editors/space_userpref/userpref_ops.c @@ -26,6 +26,8 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" #include "BKE_report.h" #include "RNA_types.h" @@ -45,8 +47,10 @@ static int reset_default_theme_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); UI_theme_init_default(); UI_style_init_default(); + WM_reinit_gizmomap_all(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); U.runtime.is_dirty = true; return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index c1891865d6d..57b98ffeda3 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -662,7 +662,10 @@ static void view3d_widgets(void) WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera); WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_camera_view); WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_empty_image); + /* TODO(campbell): Not working well enough, disable for now. */ +#if 0 WM_gizmogrouptype_append_and_link(gzmap_type, VIEW3D_GGT_armature_spline); +#endif WM_gizmogrouptype_append(VIEW3D_GGT_xform_gizmo); WM_gizmogrouptype_append(VIEW3D_GGT_xform_cage); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index d14a6870a6c..eef36dae86a 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -169,7 +169,13 @@ void ED_view3d_update_viewmat(Depsgraph *depsgraph, v2[2] = rv3d->persmat[2][1]; len_px = 2.0f / sqrtf(min_ff(len_squared_v3(v1), len_squared_v3(v2))); - len_sc = (float)MAX2(ar->winx, ar->winy); + + if (rect) { + len_sc = (float)max_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)); + } + else { + len_sc = (float)MAX2(ar->winx, ar->winy); + } rv3d->pixsize = len_px / len_sc; } @@ -798,7 +804,11 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a GPU_depth_test(true); GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0); - DRW_draw_depth_loop(depsgraph, ar, v3d, viewport); + /* When Blender is starting, a click event can trigger a depth test while the viewport is not + * yet available. */ + if (viewport != NULL) { + DRW_draw_depth_loop(depsgraph, ar, v3d, viewport); + } if (rv3d->rflag & RV3D_CLIPPING) { ED_view3d_clipping_disable(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index b6eb57a3c81..7c4b35507b9 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4661,6 +4661,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven cam->flag |= CAM_SHOW_BG_IMAGE; WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); + DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE); return OPERATOR_FINISHED; } @@ -4721,6 +4722,8 @@ static int background_image_remove_exec(bContext *C, wmOperator *op) BKE_camera_background_image_remove(cam, bgpic_rem); WM_event_add_notifier(C, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, cam); + DEG_id_tag_update(&cam->id, ID_RECALC_COPY_ON_WRITE); + return OPERATOR_FINISHED; } else { @@ -4944,7 +4947,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C, ray_no, NULL, &ob_dummy, - obmat)) { + obmat) != 0) { if (use_depth) { copy_v3_v3(cursor_co, ray_co); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c index 9cbf179ab49..64697a59019 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.c @@ -21,7 +21,7 @@ * * Use for tools to hover over data before activation. * - * \note This is a slight mis-use of gizmo's, since clicking performs no action. + * \note This is a slight misuse of gizmo's, since clicking performs no action. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index ebfd66008f7..e781e129540 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -113,6 +113,13 @@ typedef struct RulerInfo { wmWindow *win; ScrArea *sa; ARegion *ar; /* re-assigned every modal update */ + + /* Track changes in state. */ + struct { + bool do_snap; + bool do_thickness; + } drag_state_prev; + } RulerInfo; /* -------------------------------------------------------------------- */ @@ -280,6 +287,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) /* pass */ } else if (state == RULER_STATE_DRAG) { + memset(&ruler_info->drag_state_prev, 0x0, sizeof(ruler_info->drag_state_prev)); ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( bmain, CTX_data_scene(C), CTX_data_depsgraph(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } @@ -857,27 +865,43 @@ static int gizmo_ruler_test_select(bContext *UNUSED(C), wmGizmo *gz, const int m static int gizmo_ruler_modal(bContext *C, wmGizmo *gz, const wmEvent *event, - eWM_GizmoFlagTweak UNUSED(tweak_flag)) + eWM_GizmoFlagTweak tweak_flag) { bool do_draw = false; int exit_code = OPERATOR_RUNNING_MODAL; RulerInfo *ruler_info = gz->parent_gzgroup->customdata; RulerItem *ruler_item = (RulerItem *)gz; ARegion *ar = CTX_wm_region(C); + bool do_cursor_update = false; ruler_info->ar = ar; switch (event->type) { case MOUSEMOVE: { - if (ruler_info->state == RULER_STATE_DRAG) { - if (view3d_ruler_item_mousemove( - ruler_info, ruler_item, event->mval, event->shift != 0, event->ctrl != 0)) { - do_draw = true; - } - } + do_cursor_update = true; break; } } + + const bool do_snap = tweak_flag & WM_GIZMO_TWEAK_SNAP; + const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE; + if ((ruler_info->drag_state_prev.do_snap != do_snap) || + (ruler_info->drag_state_prev.do_thickness != do_thickness)) { + do_cursor_update = true; + } + + if (do_cursor_update) { + if (ruler_info->state == RULER_STATE_DRAG) { + if (view3d_ruler_item_mousemove( + ruler_info, ruler_item, event->mval, do_thickness, do_snap)) { + do_draw = true; + } + } + } + + ruler_info->drag_state_prev.do_snap = do_snap; + ruler_info->drag_state_prev.do_thickness = do_thickness; + if (do_draw) { ED_region_tag_redraw(ar); } @@ -920,8 +944,7 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) } /* update the new location */ - view3d_ruler_item_mousemove( - ruler_info, ruler_item_pick, event->mval, event->shift != 0, event->ctrl != 0); + view3d_ruler_item_mousemove(ruler_info, ruler_item_pick, event->mval, false, false); } } else { diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 6ed0508f09f..2636062ed8b 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -38,6 +38,7 @@ #include "BKE_editmesh.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_iterators.h" +#include "BKE_modifier.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -293,8 +294,15 @@ void mesh_foreachScreenFace( data.clip_flag = clip_flag; BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - BKE_mesh_foreach_mapped_face_center( - me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + + if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) { + BKE_mesh_foreach_mapped_subdiv_face_center( + me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + } + else { + BKE_mesh_foreach_mapped_face_center( + me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); + } } /* ------------------------------------------------------------------------ */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 3ff97cdd59a..61de61c8e31 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1602,31 +1602,63 @@ static const EnumPropertyItem *object_select_menu_enum_itemf(bContext *C, static int object_select_menu_exec(bContext *C, wmOperator *op) { const int name_index = RNA_enum_get(op->ptr, "name"); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect = RNA_boolean_get(op->ptr, "deselect"); const bool toggle = RNA_boolean_get(op->ptr, "toggle"); bool changed = false; const char *name = object_mouse_select_menu_data[name_index].idname; - if (!toggle) { - CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { - if ((base->flag & BASE_SELECTED) != 0) { - ED_object_base_select(base, BA_DESELECT); - changed = true; - } - } - CTX_DATA_END; - } + View3D *v3d = CTX_wm_view3d(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *oldbasact = BASACT(view_layer); + Base *basact = NULL; CTX_DATA_BEGIN (C, Base *, base, selectable_bases) { /* This is a bit dodgy, there should only be ONE object with this name, * but library objects can mess this up. */ if (STREQ(name, base->object->id.name + 2)) { - ED_object_base_activate(C, base); - ED_object_base_select(base, BA_SELECT); - changed = true; + basact = base; + break; } } CTX_DATA_END; + if (basact == NULL) { + return OPERATOR_CANCELLED; + } + UNUSED_VARS_NDEBUG(v3d); + BLI_assert(BASE_SELECTABLE(v3d, basact)); + + if (extend) { + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + else if (deselect) { + ED_object_base_select(basact, BA_DESELECT); + changed = true; + } + else if (toggle) { + if (basact->flag & BASE_SELECTED) { + if (basact == oldbasact) { + ED_object_base_select(basact, BA_DESELECT); + changed = true; + } + } + else { + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + } + else { + object_deselect_all_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); + changed = true; + } + + if ((oldbasact != basact)) { + ED_object_base_activate(C, basact); + } + /* weak but ensures we activate menu again before using the enum */ memset(object_mouse_select_menu_data, 0, sizeof(object_mouse_select_menu_data)); @@ -1664,12 +1696,19 @@ void VIEW3D_OT_select_menu(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_ENUM_NO_TRANSLATE); ot->prop = prop; - RNA_def_boolean( - ot->srna, "toggle", 0, "Toggle", "Toggle selection instead of deselecting everything first"); + RNA_def_boolean(ot->srna, "extend", 0, "Extend", ""); + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); + RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); } -static Base *object_mouse_select_menu( - bContext *C, ViewContext *vc, uint *buffer, int hits, const int mval[2], bool toggle) +static Base *object_mouse_select_menu(bContext *C, + ViewContext *vc, + uint *buffer, + int hits, + const int mval[2], + bool extend, + bool deselect, + bool toggle) { short baseCount = 0; bool ok; @@ -1739,6 +1778,8 @@ static Base *object_mouse_select_menu( PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); + RNA_boolean_set(&ptr, "extend", extend); + RNA_boolean_set(&ptr, "deselect", deselect); RNA_boolean_set(&ptr, "toggle", toggle); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); WM_operator_properties_free(&ptr); @@ -2122,7 +2163,7 @@ static bool ed_object_select_pick(bContext *C, /* note; shift+alt goes to group-flush-selecting */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, toggle); + basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend, deselect, toggle); } else { base = startbase; @@ -2190,7 +2231,7 @@ static bool ed_object_select_pick(bContext *C, /* note; shift+alt goes to group-flush-selecting */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle); + basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle); } else { basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest); @@ -2278,11 +2319,17 @@ static bool ed_object_select_pick(bContext *C, retval = true; WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, basact->object); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - /* in weightpaint, we use selected bone to select vertexgroup, - * so no switch to new active object */ + /* In weight-paint, we use selected bone to select vertex-group, + * so don't switch to new active object. */ if (oldbasact && (oldbasact->object->mode & OB_MODE_WEIGHT_PAINT)) { - /* prevent activating */ + /* Prevent activating. + * Selection causes this to be considered the 'active' pose in weight-paint mode. + * Eventually this limitation may be removed. + * For now, de-select all other pose objects deforming this mesh. */ + ED_armature_pose_select_in_wpaint_mode(view_layer, basact); + basact = NULL; } } @@ -2353,7 +2400,7 @@ static bool ed_object_select_pick(bContext *C, } else { /* When enabled, this puts other objects out of multi pose-mode. */ - if (is_pose_mode == false) { + if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) { object_deselect_all_except(view_layer, basact); ED_object_base_select(basact, BA_SELECT); } @@ -2507,6 +2554,9 @@ static int view3d_select_exec(bContext *C, wmOperator *op) /* pass */ } } + if (retval) { + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { retval = PE_mouse_particles(C, location, extend, deselect, toggle); diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 51dc14f3dff..0103fd0df53 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -634,14 +634,12 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) TransVertStore tvs = {NULL}; TransVert *tv; float bmat[3][3], vec[3], min[3], max[3], centroid[3]; - int count, a; + int count = 0; - count = 0; INIT_MINMAX(min, max); zero_v3(centroid); if (obedit) { - int global_transverts_tot = 0; 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( @@ -662,13 +660,13 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES); } - global_transverts_tot += tvs.transverts_tot; + count += tvs.transverts_tot; if (tvs.transverts_tot != 0) { Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); copy_m3_m4(bmat, obedit_eval->obmat); tv = tvs.transverts; - for (a = 0; a < tvs.transverts_tot; a++, tv++) { + for (int i = 0; i < tvs.transverts_tot; i++, tv++) { copy_v3_v3(vec, tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit_eval->obmat[3]); @@ -679,14 +677,6 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) ED_transverts_free(&tvs); } MEM_freeN(objects); - - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { - mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot); - copy_v3_v3(cursor, centroid); - } - else { - mid_v3_v3v3(cursor, min, max); - } } else { Object *obact = CTX_data_active_object(C); @@ -725,18 +715,18 @@ static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]) } FOREACH_SELECTED_OBJECT_END; } + } - if (count == 0) { - return false; - } + if (count == 0) { + return false; + } - if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { - mul_v3_fl(centroid, 1.0f / (float)count); - copy_v3_v3(cursor, centroid); - } - else { - mid_v3_v3v3(cursor, min, max); - } + if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) { + mul_v3_fl(centroid, 1.0f / (float)count); + copy_v3_v3(cursor, centroid); + } + else { + mid_v3_v3v3(cursor, min, max); } return true; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 5865efa0ffa..c0902cd1cd5 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -30,6 +30,7 @@ #include "BLI_math.h" #include "BLI_rect.h" #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BKE_action.h" #include "BKE_camera.h" @@ -38,6 +39,7 @@ #include "BKE_global.h" #include "BKE_layer.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -962,8 +964,8 @@ static bool drw_select_filter_object_mode_lock(Object *ob, void *user_data) * we want to select pose bones (this doesn't switch modes). */ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void *user_data) { - const Object *ob_pose = user_data; - return (DEG_get_original_object(ob) == ob_pose); + LinkNode *ob_pose_list = user_data; + return ob_pose_list && (BLI_linklist_index(ob_pose_list, DEG_get_original_object(ob)) != -1); } /** @@ -1044,10 +1046,22 @@ int view3d_opengl_select(ViewContext *vc, case VIEW3D_SELECT_FILTER_WPAINT_POSE_MODE_LOCK: { Object *obact = vc->obact; BLI_assert(obact && (obact->mode & OB_MODE_WEIGHT_PAINT)); - Object *ob_pose = BKE_object_pose_armature_get(obact); + /* While this uses 'alloca' in a loop (which we typically avoid), + * the number of items is nearly always 1, maybe 2..3 in rare cases. */ + LinkNode *ob_pose_list = NULL; + VirtualModifierData virtualModifierData; + const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData); + for (; md; md = md->next) { + if (md->type == eModifierType_Armature) { + ArmatureModifierData *amd = (ArmatureModifierData *)md; + if (amd->object && (amd->object->mode & OB_MODE_POSE)) { + BLI_linklist_prepend_alloca(&ob_pose_list, amd->object); + } + } + } object_filter.fn = drw_select_filter_object_mode_lock_for_weight_paint; - object_filter.user_data = ob_pose; + object_filter.user_data = ob_pose_list; break; } case VIEW3D_SELECT_FILTER_NOP: diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 5b3f7d85b43..a316567fc63 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -617,6 +617,8 @@ static void viewRedrawForce(const bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_SEQ) { WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL); + /* Keyframes on strips has been moved, so make sure related editos are informed. */ + WM_event_add_notifier(C, NC_ANIMATION, NULL); } else if (t->spacetype == SPACE_IMAGE) { if (t->options & CTX_MASK) { @@ -6440,6 +6442,8 @@ static void slide_origdata_create_data(TransDataContainer *tc, layer_index_dst = 0; + /* TODO: We don't need `sod->layer_math_map` when there are no loops linked + * to one of the sliding vertices. */ if (CustomData_has_math(&bm->ldata)) { /* over alloc, only 'math' layers are indexed */ sod->layer_math_map = MEM_mallocN(bm->ldata.totlayer * sizeof(int), __func__); @@ -6583,7 +6587,7 @@ static void slide_origdata_interp_data_vert(SlideOrigData *sod, } } - if (sod->layer_math_map_num) { + if (sod->layer_math_map_num && sv->cd_loop_groups) { if (do_loop_weight) { for (j = 0; j < sod->layer_math_map_num; j++) { BM_vert_loop_groups_data_layer_merge_weights( @@ -6699,9 +6703,28 @@ static void slide_origdata_free_date(SlideOrigData *sod) /** \name Transform Edge Slide * \{ */ +/** + * Get the first valid EdgeSlideData. + * + * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that + * may leave items with invalid custom data in the transform data container. + */ +static EdgeSlideData *edgeSlideFirstGet(TransInfo *t) +{ + FOREACH_TRANS_DATA_CONTAINER (t, tc) { + EdgeSlideData *sld = tc->custom.mode.data; + if (sld == NULL) { + continue; + } + return sld; + } + BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid"); + return NULL; +} + static void calcEdgeSlideCustomPoints(struct TransInfo *t) { - EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld = edgeSlideFirstGet(t); setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start); @@ -7675,10 +7698,14 @@ void projectEdgeSlideData(TransInfo *t, bool is_final) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; - SlideOrigData *sod = &sld->orig_data; + if (sld == NULL) { + continue; + } + + SlideOrigData *sod = &sld->orig_data; if (sod->use_origfaces == false) { - return; + continue; } slide_origdata_interp_data(tc->obedit, @@ -7701,7 +7728,7 @@ void freeEdgeSlideVerts(TransInfo *UNUSED(t), { EdgeSlideData *sld = custom_data->data; - if (!sld) { + if (sld == NULL) { return; } @@ -7843,9 +7870,9 @@ static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEven static void drawEdgeSlide(TransInfo *t) { - if ((t->mode == TFM_EDGE_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) { + if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) { const EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld = edgeSlideFirstGet(t); const bool is_clamp = !(t->flag & T_ALT_TRANSFORM); /* Even mode */ @@ -7964,7 +7991,7 @@ static void drawEdgeSlide(TransInfo *t) static void doEdgeSlide(TransInfo *t, float perc) { EdgeSlideParams *slp = t->custom.mode.data; - EdgeSlideData *sld_active = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data; + EdgeSlideData *sld_active = edgeSlideFirstGet(t); slp->perc = perc; @@ -7975,6 +8002,11 @@ static void doEdgeSlide(TransInfo *t, float perc) const float perc_final = fabsf(perc); FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final); @@ -7988,6 +8020,11 @@ static void doEdgeSlide(TransInfo *t, float perc) const int side_index = sld_active->curr_side_unclamp; FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { float dir_flip[3]; @@ -8024,6 +8061,11 @@ static void doEdgeSlide(TransInfo *t, float perc) FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + + if (sld == NULL) { + continue; + } + TransDataEdgeSlideVert *sv = sld->sv; for (int i = 0; i < sld->totsv; i++, sv++) { if (sv->edge_len > FLT_EPSILON) { diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 06851451461..208242d53b3 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -235,8 +235,7 @@ static void axisProjection(const TransInfo *t, normalize_v3_v3_length(out, axis, -factor); } else { - float v[3], i1[3], i2[3]; - float v2[3], v4[3]; + float v[3]; float norm_center[3]; float plane[3]; @@ -261,14 +260,17 @@ static void axisProjection(const TransInfo *t, } } else { - add_v3_v3v3(v2, t_con_center, axis); - add_v3_v3v3(v4, v, norm); - - isect_line_line_v3(t_con_center, v2, v, v4, i1, i2); - - sub_v3_v3v3(v, i2, v); - - sub_v3_v3v3(out, i1, t_con_center); + /* Use ray-ray intersection instead of line-line because this gave + * precision issues adding small values to large numbers. */ + float mul; + if (isect_ray_ray_v3(v, norm, t_con_center, axis, &mul, NULL)) { + madd_v3_v3v3fl(out, t_con_center, axis, mul); + sub_v3_v3(out, t_con_center); + } + else { + /* In practice this should never fail. */ + BLI_assert(0); + } /* possible some values become nan when * viewpoint and object are both zero */ @@ -863,9 +865,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t) immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformThemeColor(TH_GRID); - set_inverted_drawing(1); + GPU_logic_op_invert_set(true); imm_drawcircball(t->center_global, t->prop_size, imat, pos); - set_inverted_drawing(0); + GPU_logic_op_invert_set(false); immUnbindProgram(); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 1ed0d5e9221..d13c0f8e8f1 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -1289,7 +1289,6 @@ static void createTransPose(TransInfo *t) bPose *pose = ob->pose; bArmature *arm; - short ik_on = 0; /* check validity of state */ arm = BKE_armature_from_object(tc->poseobj); @@ -1315,8 +1314,7 @@ static void createTransPose(TransInfo *t) /* do we need to add temporal IK chains? */ if ((pose->flag & POSE_AUTO_IK) && t->mode == TFM_TRANSLATION) { - ik_on = pose_grab_with_ik(bmain, ob); - if (ik_on) { + if (pose_grab_with_ik(bmain, ob)) { t->flag |= T_AUTOIK; has_translate_rotate[0] = true; } @@ -1359,7 +1357,6 @@ static void createTransPose(TransInfo *t) Object *ob = tc->poseobj; TransData *td; TransDataExtension *tdx; - short ik_on = 0; int i; PoseInitData_Mirror *pid = tc->custom.type.data; @@ -1407,7 +1404,7 @@ static void createTransPose(TransInfo *t) } /* initialize initial auto=ik chainlen's? */ - if (ik_on) { + if (t->flag & T_AUTOIK) { transform_autoik_update(t, 0); } } @@ -2537,6 +2534,7 @@ void flushTransParticles(TransInfo *t) } PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1); + BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO); } } @@ -2935,11 +2933,16 @@ static void VertsToTransData(TransInfo *t, } else if (t->mode == TFM_SKIN_RESIZE) { MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN); - /* skin node size */ - td->ext = tx; - copy_v3_v3(tx->isize, vs->radius); - tx->size = vs->radius; - td->val = vs->radius; + if (vs) { + /* skin node size */ + td->ext = tx; + copy_v3_v3(tx->isize, vs->radius); + tx->size = vs->radius; + td->val = vs->radius; + } + else { + td->flag |= TD_SKIP; + } } else if (t->mode == TFM_SHRINKFATTEN) { td->ext = tx; @@ -3705,50 +3708,48 @@ bool clipUVTransform(TransInfo *t, float vec[2], const bool resize) for (a = 0, td = tc->data; a < tc->data_len; a++, td++) { minmax_v2v2_v2(min, max, td->loc); } + } - if (resize) { - if (min[0] < 0.0f && t->center_global[0] > 0.0f && - t->center_global[0] < t->aspect[0] * 0.5f) { - vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); - } - else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { - vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); - } - else { - clipx = 0; - } + if (resize) { + if (min[0] < 0.0f && t->center_global[0] > 0.0f && t->center_global[0] < t->aspect[0] * 0.5f) { + vec[0] *= t->center_global[0] / (t->center_global[0] - min[0]); + } + else if (max[0] > t->aspect[0] && t->center_global[0] < t->aspect[0]) { + vec[0] *= (t->center_global[0] - t->aspect[0]) / (t->center_global[0] - max[0]); + } + else { + clipx = 0; + } - if (min[1] < 0.0f && t->center_global[1] > 0.0f && - t->center_global[1] < t->aspect[1] * 0.5f) { - vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); - } - else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { - vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); - } - else { - clipy = 0; - } + if (min[1] < 0.0f && t->center_global[1] > 0.0f && t->center_global[1] < t->aspect[1] * 0.5f) { + vec[1] *= t->center_global[1] / (t->center_global[1] - min[1]); + } + else if (max[1] > t->aspect[1] && t->center_global[1] < t->aspect[1]) { + vec[1] *= (t->center_global[1] - t->aspect[1]) / (t->center_global[1] - max[1]); } else { - if (min[0] < 0.0f) { - vec[0] -= min[0]; - } - else if (max[0] > t->aspect[0]) { - vec[0] -= max[0] - t->aspect[0]; - } - else { - clipx = 0; - } + clipy = 0; + } + } + else { + if (min[0] < 0.0f) { + vec[0] -= min[0]; + } + else if (max[0] > t->aspect[0]) { + vec[0] -= max[0] - t->aspect[0]; + } + else { + clipx = 0; + } - if (min[1] < 0.0f) { - vec[1] -= min[1]; - } - else if (max[1] > t->aspect[1]) { - vec[1] -= max[1] - t->aspect[1]; - } - else { - clipy = 0; - } + if (min[1] < 0.0f) { + vec[1] -= min[1]; + } + else if (max[1] > t->aspect[1]) { + vec[1] -= max[1] - t->aspect[1]; + } + else { + clipy = 0; } } @@ -6438,19 +6439,25 @@ static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer) } } -static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data)) +static void set_trans_object_base_deps_flag_cb(ID *id, + eDepsObjectComponentType component, + void *UNUSED(user_data)) { /* Here we only handle object IDs. */ if (GS(id->name) != ID_OB) { return; } + if (!ELEM(component, DEG_OB_COMP_TRANSFORM, DEG_OB_COMP_GEOMETRY)) { + return; + } id->tag |= LIB_TAG_DOIT; } static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object) { object->id.tag |= LIB_TAG_DOIT; - DEG_foreach_dependent_ID(depsgraph, &object->id, set_trans_object_base_deps_flag_cb, NULL); + DEG_foreach_dependent_ID_component( + depsgraph, &object->id, DEG_OB_COMP_TRANSFORM, set_trans_object_base_deps_flag_cb, NULL); } static void trans_object_base_deps_flag_finish(ViewLayer *view_layer) @@ -7093,6 +7100,10 @@ void special_aftertrans_update(bContext *C, TransInfo *t) FOREACH_TRANS_DATA_CONTAINER (t, tc) { EdgeSlideData *sld = tc->custom.mode.data; + if (sld == NULL) { + continue; + } + /* Free temporary faces to avoid auto-merging and deleting * during cleanup - psy-fi. */ freeEdgeSlideTempFaces(sld); diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 530abe6faff..a883b5b6ba5 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1489,7 +1489,12 @@ static GizmoGroup *gizmogroup_init(wmGizmoGroup *gzgroup) ggd->gizmos[MAN_AXIS_ROT_T]->flag |= WM_GIZMO_SELECT_BACKGROUND; /* Prevent axis gizmos overlapping the center point, see: T63744. */ - ggd->gizmos[MAN_AXIS_SCALE_C]->select_bias = ggd->gizmos[MAN_AXIS_TRANS_C]->select_bias = 2.0f; + ggd->gizmos[MAN_AXIS_TRANS_C]->select_bias = 2.0f; + + ggd->gizmos[MAN_AXIS_SCALE_C]->select_bias = -2.0f; + + /* Use 1/6 since this is '0.2' if the main scale is 1.2. */ + RNA_float_set(ggd->gizmos[MAN_AXIS_SCALE_C]->ptr, "arc_inner_factor", 1.0 / 6.0); return ggd; } @@ -1591,6 +1596,9 @@ static void gizmogroup_init_properties_from_twtype(wmGizmoGroup *gzgroup) WM_gizmo_set_flag(axis, WM_GIZMO_DRAW_VALUE, true); WM_gizmo_set_scale(axis, 1.2f); } + else if (axis_idx == MAN_AXIS_SCALE_C) { + WM_gizmo_set_scale(axis, 1.2f); + } else { WM_gizmo_set_scale(axis, 0.2f); } @@ -1868,7 +1876,7 @@ static void WIDGETGROUP_gizmo_invoke_prepare(const bContext *C, GizmoGroup *ggd = gzgroup->customdata; - /* Support gizmo spesific orientation. */ + /* Support gizmo specific orientation. */ if (gz != ggd->gizmos[MAN_AXIS_ROT_T]) { Scene *scene = CTX_data_scene(C); wmGizmoOpElem *gzop = WM_gizmo_operator_get(gz, 0); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index f028f2dc506..c6c2a441d94 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -33,6 +33,7 @@ #include "BKE_global.h" #include "BKE_report.h" #include "BKE_editmesh.h" +#include "BKE_layer.h" #include "BKE_scene.h" #include "RNA_access.h" @@ -754,16 +755,6 @@ static void TRANSFORM_OT_resize(struct wmOperatorType *ot) P_OPTIONS | P_GPENCIL_EDIT | P_CENTER); } -static bool skin_resize_poll(bContext *C) -{ - struct Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit->type == OB_MESH) { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - return (em && CustomData_has_layer(&em->bm->vdata, CD_MVERT_SKIN)); - } - return 0; -} - static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) { /* identifiers */ @@ -777,7 +768,7 @@ static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot) ot->exec = transform_exec; ot->modal = transform_modal; ot->cancel = transform_cancel; - ot->poll = skin_resize_poll; + ot->poll = ED_operator_editmesh; ot->poll_property = transform_poll_property; RNA_def_float_vector( diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 58a50da9846..d45a0588003 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -566,13 +566,8 @@ static void initSnappingMode(TransInfo *t) /* Edit mode */ if (t->tsnap.applySnap != NULL && // A snapping function actually exist ((obedit_type != -1) && - ELEM(obedit_type, - OB_MESH, - OB_ARMATURE, - OB_CURVE, - OB_LATTICE, - OB_MBALL))) // Temporary limited to edit mode meshes, armature, curves, metaballs - { + /* Temporary limited to edit mode meshes, armature, curves, metaballs. */ + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL))) { /* Exclude editmesh if using proportional edit */ if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { t->tsnap.modeSelect = SNAP_NOT_ACTIVE; diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 03c43c8d16d..6f06f8639bd 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -2820,16 +2820,16 @@ static short transform_snap_context_project_view3d_mixed_impl( return 0; } -bool ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, - const unsigned short snap_to, - const struct SnapObjectParams *params, - const float mval[2], - float *dist_px, - float r_loc[3], - float r_no[3], - int *r_index, - Object **r_ob, - float r_obmat[4][4]) +short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx, + const unsigned short snap_to, + const struct SnapObjectParams *params, + const float mval[2], + float *dist_px, + float r_loc[3], + float r_no[3], + int *r_index, + Object **r_ob, + float r_obmat[4][4]) { return transform_snap_context_project_view3d_mixed_impl( sctx, snap_to, params, mval, dist_px, r_loc, r_no, r_index, r_ob, r_obmat) != 0; @@ -2856,7 +2856,7 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx, float r_no[3]) { return ED_transform_snap_object_project_view3d_ex( - sctx, snap_to, params, mval, dist_px, r_loc, r_no, NULL, NULL, NULL); + sctx, snap_to, params, mval, dist_px, r_loc, r_no, NULL, NULL, NULL) != 0; } /** diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 6d5f486ebe9..183e140169d 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -99,6 +99,10 @@ void ED_undo_push(bContext *C, const char *str) BKE_undosys_stack_limit_steps_and_memory(wm->undo_stack, 0, memory_limit); } + if (CLOG_CHECK(&LOG, 1)) { + BKE_undosys_print(wm->undo_stack); + } + WM_file_tag_modified(); } @@ -236,6 +240,10 @@ static int ed_undo_step_impl( Main *bmain = CTX_data_main(C); WM_toolsystem_refresh_screen_all(bmain); + if (CLOG_CHECK(&LOG, 1)) { + BKE_undosys_print(wm->undo_stack); + } + return OPERATOR_FINISHED; } @@ -322,6 +330,39 @@ bool ED_undo_is_memfile_compatible(const bContext *C) } /** + * When a property of ID changes, return false. + * + * This is to avoid changes to a property making undo pushes + * which are ignored by the undo-system. + * For example, changing a brush property isn't stored by sculpt-mode undo steps. + * This workaround is needed until the limitation is removed, see: T61948. + */ +bool ED_undo_is_legacy_compatible_for_property(struct bContext *C, ID *id) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + if (view_layer != NULL) { + Object *obact = OBACT(view_layer); + if (obact != NULL) { + if (obact->mode & OB_MODE_ALL_PAINT) { + /* Don't store property changes when painting + * (only do undo pushes on brush strokes which each paint operator handles on it's own). */ + CLOG_INFO(&LOG, 1, "skipping undo for paint-mode"); + return false; + } + else if (obact->mode & OB_MODE_EDIT) { + if ((id == NULL) || (obact->data == NULL) || + (GS(id->name) != GS(((ID *)obact->data)->name))) { + /* No undo push on id type mismatch in edit-mode. */ + CLOG_INFO(&LOG, 1, "skipping undo for edit-mode"); + return false; + } + } + } + } + return true; +} + +/** * Ideally we wont access the stack directly, * this is needed for modes which handle undo themselves (bypassing #ED_undo_push). * diff --git a/source/blender/editors/undo/memfile_undo.c b/source/blender/editors/undo/memfile_undo.c index 0f495d64b29..f3e2ee92558 100644 --- a/source/blender/editors/undo/memfile_undo.c +++ b/source/blender/editors/undo/memfile_undo.c @@ -83,10 +83,8 @@ static bool memfile_undosys_step_encode(struct bContext *UNUSED(C), return true; } -static void memfile_undosys_step_decode(struct bContext *C, - struct Main *bmain, - UndoStep *us_p, - int UNUSED(dir)) +static void memfile_undosys_step_decode( + struct bContext *C, struct Main *bmain, UndoStep *us_p, int UNUSED(dir), bool UNUSED(is_final)) { ED_editors_exit(bmain, false); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1ee8ff6966c..c1b6a7b42b2 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -326,15 +326,15 @@ void unpack_menu(bContext *C, BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (!STREQ(abs_name, local_name)) { - switch (checkPackedFile(BKE_main_blendfile_path(bmain), local_name, pf)) { - case PF_NOFILE: + switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) { + case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_EQUAL: + case PF_CMP_EQUAL: BLI_snprintf(line, sizeof(line), TIP_("Use %s (identical)"), local_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -342,7 +342,7 @@ void unpack_menu(bContext *C, RNA_string_set(&props_ptr, "id", id_name); break; - case PF_DIFFERS: + case PF_CMP_DIFFERS: BLI_snprintf(line, sizeof(line), TIP_("Use %s (differs)"), local_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_LOCAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -359,22 +359,22 @@ void unpack_menu(bContext *C, } } - switch (checkPackedFile(BKE_main_blendfile_path(bmain), abs_name, pf)) { - case PF_NOFILE: + switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) { + case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_EQUAL: + case PF_CMP_EQUAL: BLI_snprintf(line, sizeof(line), TIP_("Use %s (identical)"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL); RNA_string_set(&props_ptr, "id", id_name); break; - case PF_DIFFERS: + case PF_CMP_DIFFERS: BLI_snprintf(line, sizeof(line), TIP_("Use %s (differs)"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_USE_ORIGINAL); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); diff --git a/source/blender/editors/util/select_buffer_utils.c b/source/blender/editors/util/select_buffer_utils.c index 130f6819e34..79f0f48830e 100644 --- a/source/blender/editors/util/select_buffer_utils.c +++ b/source/blender/editors/util/select_buffer_utils.c @@ -44,7 +44,7 @@ /** \name Select Bitmap from ID's * * Given a buffer of select ID's, fill in a booleans (true/false) per index. - * #BLI_bitmap is used for memory effeciency. + * #BLI_bitmap is used for memory efficiency. * * \{ */ @@ -215,7 +215,7 @@ uint ED_select_buffer_sample_point(const int center[2]) /** * Find the selection id closest to \a center. - * \param dist[in,out]: Use to initalize the distance, + * \param dist[in,out]: Use to initialize the distance, * when found, this value is set to the distance of the selection thats returned. */ uint ED_select_buffer_find_nearest_to_point(const int center[2], @@ -223,7 +223,7 @@ uint ED_select_buffer_find_nearest_to_point(const int center[2], const uint id_max, uint *dist) { - /* Smart function to sample a rect spiralling outside, nice for selection ID. */ + /* Smart function to sample a rect spiraling outside, nice for selection ID. */ /* Create region around center (typically the mouse cursor). * This must be square and have an odd width, diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index b1d22e12b10..ed8178d1908 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -412,10 +412,10 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * } } if (verts || facedots) { - float pointsize = UI_GetThemeValuef(TH_VERTEX_SIZE); UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); if (verts) { - float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ + const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE); + const float pinned_col[4] = {1.0f, 0.0f, 0.0f, 1.0f}; /* TODO Theme? */ UI_GetThemeColor4fv(TH_VERTEX, col1); GPU_blend(true); GPU_program_point_size(true); @@ -424,7 +424,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * GPU_batch_uniform_4f(verts, "vertColor", col1[0], col1[1], col1[2], 1.0f); GPU_batch_uniform_4fv(verts, "selectColor", transparent); GPU_batch_uniform_4fv(verts, "pinnedColor", pinned_col); - GPU_batch_uniform_1f(verts, "pointSize", (pointsize + 1.5f) * M_SQRT2); + GPU_batch_uniform_1f(verts, "pointSize", (point_size + 1.5f) * M_SQRT2); GPU_batch_uniform_1f(verts, "outlineWidth", 0.75f); GPU_batch_draw(verts); @@ -441,7 +441,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit, Depsgraph * GPU_program_point_size(false); } if (facedots) { - GPU_point_size(pointsize); + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE); + GPU_point_size(point_size); UI_GetThemeColor4fv(TH_WIRE, col1); GPU_batch_program_set_builtin(facedots, GPU_SHADER_2D_UV_FACEDOTS); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 14cdb674698..a42a6eba3ff 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -2282,7 +2282,6 @@ static void uvedit_unwrap_cube_project(BMesh *bm, * component, but clusters all together around the center of map. */ BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { continue; } |