diff options
author | Joshua Leung <aligorith@gmail.com> | 2017-01-17 14:48:15 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2017-01-18 09:41:57 +0300 |
commit | fd119a3723f0a17e86214257867aa92bb99f3c0a (patch) | |
tree | 0bbaf5e7b411315d106de53bccfdf0a01f34297a /source/blender/editors/gpencil/gpencil_interpolate.c | |
parent | cd8cde1a6a4a8294c0c63cf4962a8292a2cda61d (diff) |
Code Cleanup for GP Interpolation ops (first pass)
* Reshuffled some blocks of code for better ease of navigation/flow in the file
* Improved some tooltips
* Removed "Helper" tag from some functions that serve bigger roles
* Fixed some errant formatting
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_interpolate.c')
-rw-r--r-- | source/blender/editors/gpencil/gpencil_interpolate.c | 367 |
1 files changed, 207 insertions, 160 deletions
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 154776dbb5c..703bacf8554 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -80,19 +80,38 @@ #include "gpencil_intern.h" /* ************************************************ */ +/* Core/Shared Utilities */ -/* ========= Interpolation operators ========================== */ -/* Helper: Update point with interpolation */ +/* Poll callback for interpolation operators */ +static int gpencil_interpolate_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + + /* only 3D view */ + if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { + return 0; + } + + /* need data to interpolate */ + if (ELEM(NULL, gpd, gpl)) { + return 0; + } + + return 1; +} + +/* Perform interpolation */ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) { bGPDspoint *prev, *pt, *next; - + /* update points */ for (int i = 0; i < new_stroke->totpoints; i++) { prev = &gps_from->points[i]; pt = &new_stroke->points[i]; next = &gps_to->points[i]; - + /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); pt->pressure = interpf(prev->pressure, next->pressure, factor); @@ -101,32 +120,39 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t } } +/* ****************** Interpolate Interactive *********************** */ + /* Helper: Update all strokes interpolated */ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) { tGPDinterpolate_layer *tgpil; - bGPDstroke *new_stroke, *gps_from, *gps_to; - int cStroke; - float factor; - float shift = tgpi->shift; - + const float shift = tgpi->shift; + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - factor = tgpil->factor + shift; + bGPDstroke *new_stroke; + const float factor = tgpil->factor + shift; + for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { + bGPDstroke *gps_from, *gps_to; + int stroke_idx; + if (new_stroke->totpoints == 0) { continue; } + /* get strokes to interpolate */ - cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); - gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke); - gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke); + stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); + + gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx); + gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx); + /* update points position */ if ((gps_from) && (gps_to)) { gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); } } } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } @@ -135,12 +161,12 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) { ToolSettings *ts = CTX_data_tool_settings(C); int flag = ts->gp_sculpt.flag; - + bGPDlayer *gpl; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDstroke *gps_from, *gps_to; int fFrame; - + /* get layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ @@ -151,6 +177,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* read strokes */ for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { /* only selected */ @@ -165,12 +192,14 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); if (gps_to == NULL) { continue; } + return 1; } } @@ -186,13 +215,14 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDstroke *gps_from, *gps_to, *new_stroke; int fFrame; - + /* save initial factor for active layer to define shift limits */ tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1); + /* limits are 100% below 0 and 100% over the 100% */ tgpi->low_limit = -1.0f - tgpi->init_factor; tgpi->high_limit = 2.0f - tgpi->init_factor; - + /* set layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ @@ -203,47 +233,54 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* create temp data for each layer */ tgpil = NULL; tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); - + tgpil->gpl = gpl; tgpil->prevFrame = gpl->actframe; tgpil->nextFrame = gpl->actframe->next; - + BLI_addtail(&tgpi->ilayers, tgpil); + /* create a new temporary frame */ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe"); tgpil->interFrame->framenum = tgpi->cframe; - + /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { bool valid = true; + /* only selected */ if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { valid = false; } - /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps_from) == false) { valid = false; } + /* check if the color is editable */ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { valid = false; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); if (gps_to == NULL) { valid = false; } + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { @@ -262,26 +299,47 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->tot_triangles = 0; new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); } + /* add to strokes */ BLI_addtail(&tgpil->interFrame->strokes, new_stroke); } } } +/* ----------------------- */ +/* Drawing Callbacks */ + +/* Drawing callback for modal operator in screen mode */ +static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); +} + +/* Drawing callback for modal operator in 3d mode */ +static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); +} + +/* ----------------------- */ + /* Helper: calculate shift based on position of mouse (we only use x-axis for now. -* since this is more convenient for users to do), and store new shift value -*/ + * since this is more convenient for users to do), and store new shift value + */ static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event) { float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f; float mpos = event->x - tgpi->ar->winrct.xmin; + if (mpos >= mid) { tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid; } else { tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid); } - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); } @@ -292,23 +350,24 @@ static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) Scene *scene = p->scene; char status_str[UI_MAX_DRAW_STR]; char msg_str[UI_MAX_DRAW_STR]; - BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR); - + + BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"), UI_MAX_DRAW_STR); + if (hasNumInput(&p->num)) { char str_offs[NUM_STR_REP_LEN]; - + outputNumInput(&p->num, str_offs, &scene->unit); - + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); } else { BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f)); } - + ED_area_headerprint(p->sa, status_str); } -/* Helper: Update screen and stroke */ +/* Update screen and stroke */ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) { /* update shift indicator in header */ @@ -319,70 +378,14 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol gp_interpolate_update_strokes(C, tgpi); } -/* init new temporary interpolation data */ -static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata *gpd = CTX_data_gpencil_data(C); - - /* set current scene and window */ - tgpi->scene = CTX_data_scene(C); - tgpi->sa = CTX_wm_area(C); - tgpi->ar = CTX_wm_region(C); - tgpi->flag = ts->gp_sculpt.flag; - - /* set current frame number */ - tgpi->cframe = tgpi->scene->r.cfra; - - /* set GP datablock */ - tgpi->gpd = gpd; - - /* set interpolation weight */ - tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* set layers */ - gp_interpolate_set_points(C, tgpi); - - return 1; -} - -/* Poll handler: check if context is suitable for interpolation */ -static int gpencil_interpolate_poll(bContext *C) -{ - bGPdata * gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - /* only 3D view */ - if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { - return 0; - } - /* need data to interpolate */ - if (ELEM(NULL, gpd, gpl)) { - return 0; - } - - return 1; -} - -/* Allocate memory and initialize values */ -static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) -{ - tGPDinterpolate *tgpi = NULL; - - /* create new context data */ - tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); - - /* define initial values */ - gp_interpolate_set_init_values(C, op, tgpi); - - /* return context data for running operator */ - return tgpi; -} +/* ----------------------- */ /* Exit and free memory */ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = op->customdata; tGPDinterpolate_layer *tgpil; - + /* don't assume that operator data exists at all */ if (tgpi) { /* remove drawing handler */ @@ -392,34 +395,68 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) if (tgpi->draw_handle_3d) { ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); } + /* clear status message area */ ED_area_headerprint(tgpi->sa, NULL); + /* finally, free memory used by temp data */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { BKE_gpencil_free_strokes(tgpil->interFrame); MEM_freeN(tgpil->interFrame); } - + BLI_freelistN(&tgpi->ilayers); MEM_freeN(tgpi); } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* clear pointer */ op->customdata = NULL; } -/* Cancel handler */ -static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) +/* Init new temporary interpolation data */ +static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) { - /* this is just a wrapper around exit() */ - gpencil_interpolate_exit(C, op); + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + + /* set current scene and window */ + tgpi->scene = CTX_data_scene(C); + tgpi->sa = CTX_wm_area(C); + tgpi->ar = CTX_wm_region(C); + tgpi->flag = ts->gp_sculpt.flag; + + /* set current frame number */ + tgpi->cframe = tgpi->scene->r.cfra; + + /* set GP datablock */ + tgpi->gpd = gpd; + + /* set interpolation weight */ + tgpi->shift = RNA_float_get(op->ptr, "shift"); + /* set layers */ + gp_interpolate_set_points(C, tgpi); + + return 1; } -/* Init interpolation: Allocate memory and set init values */ +/* Allocate memory and initialize values */ +static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) +{ + tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); + + /* define initial values */ + gp_interpolate_set_init_values(C, op, tgpi); + + /* return context data for running operator */ + return tgpi; +} + +/* Init interpolation: Allocate memory and set init values */ static int gpencil_interpolate_init(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi; + /* check context */ tgpi = op->customdata = gp_session_init_interpolation(C, op); if (tgpi == NULL) { @@ -427,34 +464,19 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op) gpencil_interpolate_exit(C, op); return 0; } - + /* everything is now setup ok */ return 1; } -/* ********************** custom drawcall api ***************** */ -/* Helper: drawing callback for modal operator in screen mode */ -static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); -} - -/* Helper: drawing callback for modal operator in 3d mode */ -static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); -} +/* ----------------------- */ /* Invoke handler: Initialize the operator */ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); - bGPdata * gpd = CTX_data_gpencil_data(C); + bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); tGPDinterpolate *tgpi = NULL; @@ -463,41 +485,46 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); return OPERATOR_CANCELLED; } - + /* cannot interpolate in extremes */ if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); return OPERATOR_CANCELLED; } - + /* need editable strokes */ if (!gp_interpolate_check_todo(C, gpd)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke"); return OPERATOR_CANCELLED; } - + /* try to initialize context data needed */ if (!gpencil_interpolate_init(C, op)) { if (op->customdata) MEM_freeN(op->customdata); return OPERATOR_CANCELLED; } - else + else { tgpi = op->customdata; - - /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different - coord system */ - tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL); - tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW); + } + + /* Enable custom drawing handlers + * It needs 2 handlers because strokes can in 3d space and screen space + * and each handler use different coord system + */ + tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL); + tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW); + /* set cursor to indicate modal */ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); + /* update shift indicator in header */ gpencil_interpolate_status_indicators(tgpi); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); - + return OPERATOR_RUNNING_MODAL; } @@ -510,7 +537,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent bGPDstroke *gps_src, *gps_dst; tGPDinterpolate_layer *tgpil; const bool has_numinput = hasNumInput(&tgpi->num); - + switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: @@ -518,7 +545,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* insert keyframes as required... */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); @@ -530,6 +557,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if (gps_src->totpoints == 0) { continue; } + /* make copy of source stroke, then adjust pointer to points too */ gps_dst = MEM_dupallocN(gps_src); gps_dst->points = MEM_dupallocN(gps_src->points); @@ -538,31 +566,34 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent BLI_addtail(&gpf_dst->strokes, gps_dst); } } + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* done! */ return OPERATOR_FINISHED; } - + case ESCKEY: /* cancel */ case RIGHTMOUSE: { /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* canceled! */ return OPERATOR_CANCELLED; } + case WHEELUPMOUSE: { tgpi->shift = tgpi->shift + 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -572,6 +603,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent tgpi->shift = tgpi->shift - 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -582,6 +614,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if (has_numinput == false) { /* update shift based on position of mouse */ gpencil_mouse_update_shift(tgpi, op, event); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); } @@ -589,22 +622,23 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent } default: if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { + const float factor = tgpi->init_factor; float value; - float factor = tgpi->init_factor; - + /* Grab shift from numeric input, and store this new value (the user see an int) */ value = (factor + tgpi->shift) * 100.0f; applyNumInput(&tgpi->num, &value); tgpi->shift = value / 100.0f; + /* recalculate the shift to get the right value in the frame scale */ tgpi->shift = tgpi->shift - factor; - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); - + break; } else { @@ -612,38 +646,45 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; } } - + /* still running... */ return OPERATOR_RUNNING_MODAL; } -/* Define modal operator for interpolation */ +/* Cancel handler */ +static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_interpolate_exit(C, op); +} + void GPENCIL_OT_interpolate(wmOperatorType *ot) { /* identifiers */ ot->name = "Grease Pencil Interpolation"; ot->idname = "GPENCIL_OT_interpolate"; ot->description = "Interpolate grease pencil strokes between frames"; - - /* api callbacks */ + + /* callbacks */ ot->invoke = gpencil_interpolate_invoke; ot->modal = gpencil_interpolate_modal; ot->cancel = gpencil_interpolate_cancel; ot->poll = gpencil_interpolate_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - - RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f); + + /* properties */ + RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f); } -/* =============== Interpolate sequence ===============*/ -/* Create Sequence Interpolation */ +/* ****************** Interpolate Sequence *********************** */ + static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata * gpd = CTX_data_gpencil_data(C); + bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDlayer *gpl; bGPDframe *prevFrame, *nextFrame, *interFrame; @@ -651,15 +692,15 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) float factor; int cframe, fFrame; int flag = ts->gp_sculpt.flag; - + /* cannot interpolate if not between 2 frames */ if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + BKE_report(op->reports, RPT_ERROR, "Could not find a pair of grease pencil frames to interpolate between"); return OPERATOR_CANCELLED; } /* cannot interpolate in extremes */ if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has strokes"); return OPERATOR_CANCELLED; } @@ -673,16 +714,18 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* store extremes */ prevFrame = gpl->actframe; nextFrame = gpl->actframe->next; + /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { interFrame = NULL; - + /* get interpolation factor */ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); - + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { /* only selected */ @@ -697,21 +740,25 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&prevFrame->strokes, gps_from); gps_to = BLI_findlink(&nextFrame->strokes, fFrame); if (gps_to == NULL) { continue; } + /* create a new frame if needed */ if (interFrame == NULL) { interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); @@ -719,35 +766,35 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; } + /* update points position */ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); - + /* add to strokes */ BLI_addtail(&interFrame->strokes, new_stroke); } } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } -/* Define sequence interpolation */ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) { /* identifiers */ - ot->name = "Grease Pencil Sequence Interpolation"; + ot->name = "Interpolate Sequence"; ot->idname = "GPENCIL_OT_interpolate_sequence"; - ot->description = "Interpolate full grease pencil strokes sequence between frames"; - + ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames"; + /* api callbacks */ ot->exec = gpencil_interpolate_seq_exec; ot->poll = gpencil_interpolate_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ========= End Interpolation operators ========================== */ +/* *************************************************************** */ |