From 238d3fa4bbd63e58538b67ff00fd655fbebc8b49 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jun 2012 11:53:49 +0000 Subject: [PATCH] mask re-key feature - mango request. ability to reset selected points shape key data. useful if you add many keys to one part of a curve, then later want to key another part - but dont want to continuously make the same corrections. --- release/scripts/startup/bl_ui/space_clip.py | 1 + source/blender/blenkernel/BKE_mask.h | 1 + source/blender/blenkernel/intern/mask.c | 70 ++++---- source/blender/editors/mask/mask_edit.c | 1 + source/blender/editors/mask/mask_intern.h | 1 + source/blender/editors/mask/mask_shapekey.c | 176 ++++++++++++++++++++ 6 files changed, 217 insertions(+), 33 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index 579d44c2355..374588939e2 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1326,6 +1326,7 @@ class CLIP_MT_mask_animation(Menu): layout.operator("mask.shape_key_clear") layout.operator("mask.shape_key_insert") layout.operator("mask.shape_key_feather_reset") + layout.operator("mask.shape_key_rekey") class CLIP_MT_camera_presets(Menu): diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index ea50d0fac39..0682b16536c 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -122,6 +122,7 @@ void BKE_mask_update_display(struct Mask *mask, float ctime); void BKE_mask_evaluate_all_masks(struct Main *bmain, float ctime, const int do_newframe); void BKE_mask_evaluate(struct Mask *mask, const float ctime, const int do_newframe); +void BKE_mask_layer_evaluate(struct MaskLayer *masklay, const float ctime, const int do_newframe); void BKE_mask_update_scene(struct Main *bmain, struct Scene *scene, const int do_newframe); void BKE_mask_parent_init(struct MaskParent *parent); void BKE_mask_calc_handle_adjacent_interp(struct MaskSpline *spline, struct MaskSplinePoint *point, const float u); diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 3dc584c374e..d85722931a7 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -1473,51 +1473,46 @@ void BKE_mask_spline_ensure_deform(MaskSpline *spline) } } -void BKE_mask_evaluate(Mask *mask, const float ctime, const int do_newframe) +void BKE_mask_layer_evaluate(MaskLayer *masklay, const float ctime, const int do_newframe) { - MaskLayer *masklay; + /* animation if available */ + if (do_newframe) { + MaskLayerShape *masklay_shape_a; + MaskLayerShape *masklay_shape_b; + int found; - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { - - /* animation if available */ - if (do_newframe) { - MaskLayerShape *masklay_shape_a; - MaskLayerShape *masklay_shape_b; - int found; - - if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime, - &masklay_shape_a, &masklay_shape_b))) - { - if (found == 1) { + if ((found = BKE_mask_layer_shape_find_frame_range(masklay, ctime, + &masklay_shape_a, &masklay_shape_b))) + { + if (found == 1) { #if 0 - printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), - masklay_shape_a->frame); + printf("%s: exact %d %d (%d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame); #endif - BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); - } - else if (found == 2) { - float w = masklay_shape_b->frame - masklay_shape_a->frame; + BKE_mask_layer_shape_to_mask(masklay, masklay_shape_a); + } + else if (found == 2) { + float w = masklay_shape_b->frame - masklay_shape_a->frame; #if 0 - printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), - masklay_shape_a->frame, masklay_shape_b->frame); + printf("%s: tween %d %d (%d %d)\n", __func__, (int)ctime, BLI_countlist(&masklay->splines_shapes), + masklay_shape_a->frame, masklay_shape_b->frame); #endif - BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, - (ctime - masklay_shape_a->frame) / w); - } - else { - /* always fail, should never happen */ - BLI_assert(found == 2); - } + BKE_mask_layer_shape_to_mask_interp(masklay, masklay_shape_a, masklay_shape_b, + (ctime - masklay_shape_a->frame) / w); + } + else { + /* always fail, should never happen */ + BLI_assert(found == 2); } } - /* animation done... */ } + /* animation done... */ - BKE_mask_calc_handles(mask); + BKE_mask_layer_calc_handles(masklay); - - for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + /* update deform */ + { MaskSpline *spline; for (spline = masklay->splines.first; spline; spline = spline->next) { @@ -1561,6 +1556,15 @@ void BKE_mask_evaluate(Mask *mask, const float ctime, const int do_newframe) } } +void BKE_mask_evaluate(Mask *mask, const float ctime, const int do_newframe) +{ + MaskLayer *masklay; + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + BKE_mask_layer_evaluate(masklay, ctime, do_newframe); + } +} + /* the purpose of this function is to ensure spline->points_deform is never out of date. * for now re-evaluate all. eventually this might work differently */ void BKE_mask_update_display(Mask *mask, float ctime) diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 76fc7126cf2..6e0da5fd756 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -237,6 +237,7 @@ void ED_operatortypes_mask(void) WM_operatortype_append(MASK_OT_shape_key_insert); WM_operatortype_append(MASK_OT_shape_key_clear); WM_operatortype_append(MASK_OT_shape_key_feather_reset); + WM_operatortype_append(MASK_OT_shape_key_rekey); } void ED_keymap_mask(wmKeyConfig *keyconf) diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index 408b585bf4c..f1d72f59078 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -110,5 +110,6 @@ void ED_mask_point_pos__reverse(const struct bContext *C, float x, float y, floa void MASK_OT_shape_key_insert(struct wmOperatorType *ot); void MASK_OT_shape_key_clear(struct wmOperatorType *ot); void MASK_OT_shape_key_feather_reset(struct wmOperatorType *ot); +void MASK_OT_shape_key_rekey(struct wmOperatorType *ot); #endif /* __MASK_INTERN_H__ */ diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c index 8da083ab400..a619ac7e3cd 100644 --- a/source/blender/editors/mask/mask_shapekey.c +++ b/source/blender/editors/mask/mask_shapekey.c @@ -29,7 +29,11 @@ * \ingroup edmask */ +#include + #include "BLI_utildefines.h" +#include "BLI_listbase.h" +#include "BLI_math.h" #include "BKE_context.h" #include "BKE_depsgraph.h" @@ -39,6 +43,9 @@ #include "DNA_mask_types.h" #include "DNA_scene_types.h" +#include "RNA_access.h" +#include "RNA_define.h" + #include "WM_api.h" #include "WM_types.h" @@ -233,6 +240,175 @@ void MASK_OT_shape_key_feather_reset(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* + * - loop over selected shapekeys. + * - find firstsel/lastsel pairs. + * - move these into a temp list. + * - re-key all the original shapes. + * - copy unselected values back from the original. + * - free the original. + */ +static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + const int frame = CFRA; + Mask *mask = CTX_data_edit_mask(C); + MaskLayer *masklay; + int change = FALSE; + + const short do_feather = RNA_boolean_get(op->ptr, "feather"); + const short do_location = RNA_boolean_get(op->ptr, "location"); + + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + + if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { + continue; + } + + /* we need at least one point selected here to bother re-interpolating */ + if (!ED_mask_layer_select_check(masklay)) { + continue; + } + + if (masklay->splines_shapes.first) { + MaskLayerShape *masklay_shape; + MaskLayerShape *masklay_shape_lastsel = NULL; + + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + MaskLayerShape *masklay_shape_a = NULL; + MaskLayerShape *masklay_shape_b = NULL; + + /* find contiguous selections */ + if (masklay_shape->flag & MASK_SHAPE_SELECT) { + if (masklay_shape_lastsel == NULL) { + masklay_shape_lastsel = masklay_shape; + } + if ((masklay_shape->next == NULL) || + (((MaskLayerShape *)masklay_shape->next)->flag & MASK_SHAPE_SELECT) == 0) + { + masklay_shape_a = masklay_shape_lastsel; + masklay_shape_b = masklay_shape; + masklay_shape_lastsel = NULL; + } + } + + /* we have a from<>to? - re-interpolate! */ + if (masklay_shape_a && masklay_shape_b) { + ListBase shapes_tmp = {NULL, NULL}; + MaskLayerShape *masklay_shape_tmp; + MaskLayerShape *masklay_shape_tmp_next; + MaskLayerShape *masklay_shape_tmp_last = masklay_shape_b->next; + MaskLayerShape *masklay_shape_tmp_rekey; + + /* move keys */ + for (masklay_shape_tmp = masklay_shape_a; + masklay_shape_tmp && (masklay_shape_tmp != masklay_shape_tmp_last); + masklay_shape_tmp = masklay_shape_tmp_next) + { + masklay_shape_tmp_next = masklay_shape_tmp->next; + BLI_remlink(&masklay->splines_shapes, masklay_shape_tmp); + BLI_addtail(&shapes_tmp, masklay_shape_tmp); + } + + /* re-key, note: cant modify the keys here since it messes uop */ + for (masklay_shape_tmp = shapes_tmp.first; + masklay_shape_tmp; + masklay_shape_tmp = masklay_shape_tmp->next) + { + BKE_mask_layer_evaluate(masklay, masklay_shape_tmp->frame, TRUE); + masklay_shape_tmp_rekey = BKE_mask_layer_shape_varify_frame(masklay, masklay_shape_tmp->frame); + BKE_mask_layer_shape_from_mask(masklay, masklay_shape_tmp_rekey); + masklay_shape_tmp_rekey->flag = masklay_shape_tmp->flag & MASK_SHAPE_SELECT; + } + + /* restore unselected points and free copies */ + for (masklay_shape_tmp = shapes_tmp.first; + masklay_shape_tmp; + masklay_shape_tmp = masklay_shape_tmp_next) + { + /* restore */ + int i_abs = 0; + int i; + MaskSpline *spline; + MaskLayerShapeElem *shape_ele_src; + MaskLayerShapeElem *shape_ele_dst; + + masklay_shape_tmp_next = masklay_shape_tmp->next; + + /* we know this exists, added above */ + masklay_shape_tmp_rekey = BKE_mask_layer_shape_find_frame(masklay, masklay_shape_tmp->frame); + + shape_ele_src = (MaskLayerShapeElem *)masklay_shape_tmp->data; + shape_ele_dst = (MaskLayerShapeElem *)masklay_shape_tmp_rekey->data; + + for (spline = masklay->splines.first; spline; spline = spline->next) { + for (i = 0; i < spline->tot_point; i++) { + MaskSplinePoint *point = &spline->points[i]; + + /* not especially efficient but makes this easier to follow */ + SWAP(MaskLayerShapeElem, *shape_ele_src, *shape_ele_dst); + + if (MASKPOINT_ISSEL_ANY(point)) { + if (do_location) { + memcpy(shape_ele_dst->value, shape_ele_src->value, sizeof(float) * 6); + } + if (do_feather) { + shape_ele_dst->value[6] = shape_ele_src->value[6]; + } + } + + shape_ele_src++; + shape_ele_dst++; + + i_abs++; + } + } + + BKE_mask_layer_shape_free(masklay_shape_tmp); + } + + change = TRUE; + } + } + + /* re-evaluate */ + BKE_mask_layer_evaluate(masklay, frame, TRUE); + } + } + + if (change) { + WM_event_add_notifier(C, NC_MASK | ND_DATA, mask); + DAG_id_tag_update(&mask->id, 0); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +void MASK_OT_shape_key_rekey(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Re-Key Points of Selected Shapes"; + ot->description = "Recalculates animation data on selected points for frames selected in the dopesheet"; + ot->idname = "MASK_OT_shape_key_rekey"; + + /* api callbacks */ + ot->exec = mask_shape_key_rekey_exec; + ot->poll = ED_maskedit_mask_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "location", TRUE, "Location", ""); + RNA_def_boolean(ot->srna, "feather", TRUE, "Feather", ""); +} + /* *** Shape Key Utils *** */