Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/gpencil/gpencil_interpolate.c
| Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_easing.h" | #include "BLI_easing.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLT_translation.h" | #include "BLT_translation.h" | ||||
| #include "DNA_color_types.h" | #include "DNA_color_types.h" | ||||
| #include "DNA_gpencil_types.h" | #include "DNA_gpencil_types.h" | ||||
| #include "DNA_meshdata_types.h" | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_screen_types.h" | #include "DNA_screen_types.h" | ||||
| #include "DNA_space_types.h" | #include "DNA_space_types.h" | ||||
| #include "DNA_view3d_types.h" | #include "DNA_view3d_types.h" | ||||
| #include "BKE_colortools.h" | #include "BKE_colortools.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_screen.h" | #include "BKE_screen.h" | ||||
| #include "BKE_deform.h" | |||||
| #include "UI_interface.h" | #include "UI_interface.h" | ||||
| #include "UI_resources.h" | #include "UI_resources.h" | ||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | #include "RNA_define.h" | ||||
| #include "RNA_enum_types.h" | #include "RNA_enum_types.h" | ||||
| #include "UI_view2d.h" | #include "UI_view2d.h" | ||||
| #include "ED_gpencil.h" | #include "ED_gpencil.h" | ||||
| #include "ED_object.h" | #include "ED_object.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_view3d.h" | #include "ED_view3d.h" | ||||
| #include "ED_space_api.h" | #include "ED_space_api.h" | ||||
| #include "DEG_depsgraph.h" | |||||
| #include "DEG_depsgraph_query.h" | |||||
| #include "gpencil_intern.h" | #include "gpencil_intern.h" | ||||
| /* ************************************************ */ | /* ************************************************ */ | ||||
| /* Core/Shared Utilities */ | /* Core/Shared Utilities */ | ||||
| /* Poll callback for interpolation operators */ | /* Poll callback for interpolation operators */ | ||||
| static bool gpencil_view3d_poll(bContext *C) | static bool gpencil_view3d_poll(bContext *C) | ||||
| { | { | ||||
| Show All 13 Lines | static bool gpencil_view3d_poll(bContext *C) | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| /* Perform interpolation */ | /* Perform interpolation */ | ||||
| static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) | static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) | ||||
| { | { | ||||
| bGPDspoint *prev, *pt, *next; | bGPDspoint *prev, *pt, *next; | ||||
| MDeformVert *dvert; | |||||
| /* update points */ | /* update points */ | ||||
| for (int i = 0; i < new_stroke->totpoints; i++) { | for (int i = 0; i < new_stroke->totpoints; i++) { | ||||
| prev = &gps_from->points[i]; | prev = &gps_from->points[i]; | ||||
| pt = &new_stroke->points[i]; | pt = &new_stroke->points[i]; | ||||
| dvert = &new_stroke->dvert[i]; | |||||
| next = &gps_to->points[i]; | next = &gps_to->points[i]; | ||||
| /* Interpolate all values */ | /* Interpolate all values */ | ||||
| interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); | interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); | ||||
| pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); | pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor); | ||||
| pt->strength = interpf(prev->strength, next->strength, 1.0f - factor); | pt->strength = interpf(prev->strength, next->strength, 1.0f - factor); | ||||
| CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); | ||||
| dvert->totweight = 0; | |||||
| dvert->dw = NULL; | |||||
| } | } | ||||
| } | } | ||||
| /* ****************** Interpolate Interactive *********************** */ | /* ****************** Interpolate Interactive *********************** */ | ||||
| /* Helper: Update all strokes interpolated */ | /* Helper: Update all strokes interpolated */ | ||||
| static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) | static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) | ||||
| { | { | ||||
| bGPdata *gpd = tgpi->gpd; | |||||
| tGPDinterpolate_layer *tgpil; | tGPDinterpolate_layer *tgpil; | ||||
| const float shift = tgpi->shift; | const float shift = tgpi->shift; | ||||
| for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { | for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { | ||||
| bGPDstroke *new_stroke; | bGPDstroke *new_stroke; | ||||
| const float factor = tgpil->factor + shift; | const float factor = tgpil->factor + shift; | ||||
| for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { | for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { | ||||
| Show All 12 Lines | for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { | ||||
| /* update points position */ | /* update points position */ | ||||
| if ((gps_from) && (gps_to)) { | if ((gps_from) && (gps_to)) { | ||||
| gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); | gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | ||||
| } | } | ||||
| /* Helper: Verify valid strokes for interpolation */ | /* Helper: Verify valid strokes for interpolation */ | ||||
| static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) | static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | |||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; | eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; | ||||
| /* get layers */ | /* get layers */ | ||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| /* all layers or only active */ | /* all layers or only active */ | ||||
| if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { | if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { | ||||
| continue; | continue; | ||||
| Show All 12 Lines | for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { | ||||
| if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* check if the color is editable */ | /* check if the color is editable */ | ||||
| if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { | if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* get final stroke to interpolate */ | /* get final stroke to interpolate */ | ||||
| fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); | fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); | ||||
| gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); | gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); | ||||
| if (gps_to == NULL) { | if (gps_to == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /* Helper: Create internal strokes interpolated */ | /* Helper: Create internal strokes interpolated */ | ||||
| static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) | static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) | ||||
| { | { | ||||
| bGPdata *gpd = tgpi->gpd; | bGPdata *gpd = tgpi->gpd; | ||||
| bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); | bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); | ||||
| bGPDframe *actframe = active_gpl->actframe; | bGPDframe *actframe = active_gpl->actframe; | ||||
| Object *ob = CTX_data_active_object(C); | |||||
| /* save initial factor for active layer to define shift limits */ | /* save initial factor for active layer to define shift limits */ | ||||
| tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1); | tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1); | ||||
| /* limits are 100% below 0 and 100% over the 100% */ | /* limits are 100% below 0 and 100% over the 100% */ | ||||
| tgpi->low_limit = -1.0f - tgpi->init_factor; | tgpi->low_limit = -1.0f - tgpi->init_factor; | ||||
| tgpi->high_limit = 2.0f - tgpi->init_factor; | tgpi->high_limit = 2.0f - tgpi->init_factor; | ||||
| Show All 26 Lines | for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ | /* 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); | 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 */ | /* create new strokes data with interpolated points reading original stroke */ | ||||
| for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { | for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { | ||||
| bGPDstroke *gps_to; | bGPDstroke *gps_to; | ||||
| int fFrame; | int fFrame; | ||||
| bGPDstroke *new_stroke; | bGPDstroke *new_stroke = NULL; | ||||
| bool valid = true; | bool valid = true; | ||||
| /* only selected */ | /* only selected */ | ||||
| if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | ||||
| valid = false; | valid = false; | ||||
| } | } | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | ||||
| valid = false; | valid = false; | ||||
| } | } | ||||
| /* check if the color is editable */ | /* check if the color is editable */ | ||||
| if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { | if (ED_gpencil_stroke_color_use(ob, tgpil->gpl, gps_from) == false) { | ||||
| valid = false; | valid = false; | ||||
| } | } | ||||
| /* get final stroke to interpolate */ | /* get final stroke to interpolate */ | ||||
| fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); | fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); | ||||
| gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); | gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); | ||||
| if (gps_to == NULL) { | if (gps_to == NULL) { | ||||
| valid = false; | valid = false; | ||||
| } | } | ||||
| /* create new stroke */ | /* create new stroke */ | ||||
| new_stroke = MEM_dupallocN(gps_from); | new_stroke = BKE_gpencil_stroke_duplicate(gps_from); | ||||
| new_stroke->points = MEM_dupallocN(gps_from->points); | |||||
| new_stroke->triangles = MEM_dupallocN(gps_from->triangles); | |||||
| new_stroke->tot_triangles = 0; | |||||
| new_stroke->flag |= GP_STROKE_RECALC_CACHES; | |||||
| if (valid) { | if (valid) { | ||||
| /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ | /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ | ||||
| if (gps_from->totpoints > gps_to->totpoints) { | if (gps_from->totpoints > gps_to->totpoints) { | ||||
| new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); | new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); | ||||
| new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints); | |||||
| new_stroke->totpoints = gps_to->totpoints; | new_stroke->totpoints = gps_to->totpoints; | ||||
| new_stroke->tot_triangles = 0; | new_stroke->tot_triangles = 0; | ||||
| new_stroke->flag |= GP_STROKE_RECALC_CACHES; | new_stroke->flag |= GP_STROKE_RECALC_CACHES; | ||||
| } | } | ||||
| /* update points position */ | /* update points position */ | ||||
| gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); | gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); | ||||
| } | } | ||||
| else { | else { | ||||
| /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ | /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ | ||||
| new_stroke->totpoints = 0; | new_stroke->totpoints = 0; | ||||
| new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); | new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); | ||||
| new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert)); | |||||
| new_stroke->tot_triangles = 0; | new_stroke->tot_triangles = 0; | ||||
| new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); | new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); | ||||
| new_stroke->flag |= GP_STROKE_RECALC_CACHES; | new_stroke->flag |= GP_STROKE_RECALC_CACHES; | ||||
| } | } | ||||
| /* add to strokes */ | /* add to strokes */ | ||||
| BLI_addtail(&tgpil->interFrame->strokes, new_stroke); | BLI_addtail(&tgpil->interFrame->strokes, new_stroke); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* ----------------------- */ | /* ----------------------- */ | ||||
| /* Drawing Callbacks */ | /* Drawing Callbacks */ | ||||
| /* Drawing callback for modal operator in screen mode */ | /* Drawing callback for modal operator in screen mode */ | ||||
| static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) | static void gpencil_interpolate_draw_screen(const struct bContext *C, ARegion *UNUSED(ar), void *arg) | ||||
| { | { | ||||
| tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; | tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; | ||||
| ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); | ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_PIXEL); | ||||
| } | } | ||||
| /* Drawing callback for modal operator in 3d mode */ | /* Drawing callback for modal operator in 3d mode */ | ||||
| static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) | static void gpencil_interpolate_draw_3d(const bContext *C, ARegion *UNUSED(ar), void *arg) | ||||
| { | { | ||||
| tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; | tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; | ||||
| ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); | ED_gp_draw_interpolation(C, tgpi, REGION_DRAW_POST_VIEW); | ||||
| } | } | ||||
| /* ----------------------- */ | /* ----------------------- */ | ||||
| /* Helper: calculate shift based on position of mouse (we only use x-axis for now. | /* 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) | static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event) | ||||
| ▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | |||||
| /* ----------------------- */ | /* ----------------------- */ | ||||
| /* Exit and free memory */ | /* Exit and free memory */ | ||||
| static void gpencil_interpolate_exit(bContext *C, wmOperator *op) | static void gpencil_interpolate_exit(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| tGPDinterpolate *tgpi = op->customdata; | tGPDinterpolate *tgpi = op->customdata; | ||||
| tGPDinterpolate_layer *tgpil; | tGPDinterpolate_layer *tgpil; | ||||
| bGPdata *gpd = tgpi->gpd; | |||||
| /* don't assume that operator data exists at all */ | /* don't assume that operator data exists at all */ | ||||
| if (tgpi) { | if (tgpi) { | ||||
| /* remove drawing handler */ | /* remove drawing handler */ | ||||
| if (tgpi->draw_handle_screen) { | if (tgpi->draw_handle_screen) { | ||||
| ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen); | ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen); | ||||
| } | } | ||||
| if (tgpi->draw_handle_3d) { | if (tgpi->draw_handle_3d) { | ||||
| ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); | ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); | ||||
| } | } | ||||
| /* clear status message area */ | /* clear status message area */ | ||||
| ED_area_status_text(tgpi->sa, NULL); | ED_area_status_text(tgpi->sa, NULL); | ||||
| ED_workspace_status_text(C, NULL); | ED_workspace_status_text(C, NULL); | ||||
| /* finally, free memory used by temp data */ | /* finally, free memory used by temp data */ | ||||
| for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { | for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { | ||||
| BKE_gpencil_free_strokes(tgpil->interFrame); | BKE_gpencil_free_strokes(tgpil->interFrame); | ||||
| MEM_freeN(tgpil->interFrame); | MEM_freeN(tgpil->interFrame); | ||||
| } | } | ||||
| BLI_freelistN(&tgpi->ilayers); | BLI_freelistN(&tgpi->ilayers); | ||||
| MEM_freeN(tgpi); | MEM_freeN(tgpi); | ||||
| } | } | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | ||||
| /* clear pointer */ | /* clear pointer */ | ||||
| op->customdata = NULL; | op->customdata = NULL; | ||||
| } | } | ||||
| /* Init new temporary interpolation data */ | /* Init new temporary interpolation data */ | ||||
| static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) | static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) | ||||
| ▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /* ----------------------- */ | /* ----------------------- */ | ||||
| /* Invoke handler: Initialize the operator */ | /* Invoke handler: Initialize the operator */ | ||||
| static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | 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); | bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); | ||||
| Depsgraph *depsgraph = CTX_data_depsgraph(C); | |||||
| int cfra_eval = (int)DEG_get_ctime(depsgraph); | |||||
| bGPDframe *actframe = gpl->actframe; | bGPDframe *actframe = gpl->actframe; | ||||
| tGPDinterpolate *tgpi = NULL; | tGPDinterpolate *tgpi = NULL; | ||||
| /* cannot interpolate if not between 2 frames */ | /* cannot interpolate if not between 2 frames */ | ||||
| if (ELEM(NULL, actframe, actframe->next)) { | if (ELEM(NULL, actframe, actframe->next)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); | BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* cannot interpolate in extremes */ | /* cannot interpolate in extremes */ | ||||
| if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { | if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); | BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* need editable strokes */ | /* need editable strokes */ | ||||
| if (!gp_interpolate_check_todo(C, gpd)) { | if (!gp_interpolate_check_todo(C, gpd)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes"); | BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| Show All 16 Lines | static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | ||||
| tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL); | 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); | 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 */ | /* set cursor to indicate modal */ | ||||
| WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); | WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); | ||||
| /* update shift indicator in header */ | /* update shift indicator in header */ | ||||
| gpencil_interpolate_status_indicators(C, tgpi); | gpencil_interpolate_status_indicators(C, tgpi); | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); | ||||
| /* add a modal handler for this operator */ | /* add a modal handler for this operator */ | ||||
| WM_event_add_modal_handler(C, op); | WM_event_add_modal_handler(C, op); | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| Show All 26 Lines | case RETKEY: | ||||
| for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { | for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { | ||||
| if (gps_src->totpoints == 0) { | if (gps_src->totpoints == 0) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* make copy of source stroke, then adjust pointer to points too */ | /* make copy of source stroke, then adjust pointer to points too */ | ||||
| gps_dst = MEM_dupallocN(gps_src); | gps_dst = MEM_dupallocN(gps_src); | ||||
| gps_dst->points = MEM_dupallocN(gps_src->points); | gps_dst->points = MEM_dupallocN(gps_src->points); | ||||
| gps_dst->dvert = MEM_dupallocN(gps_src->dvert); | |||||
| BKE_gpencil_stroke_weights_duplicate(gps_src, gps_dst); | |||||
| gps_dst->triangles = MEM_dupallocN(gps_src->triangles); | gps_dst->triangles = MEM_dupallocN(gps_src->triangles); | ||||
| gps_dst->flag |= GP_STROKE_RECALC_CACHES; | gps_dst->flag |= GP_STROKE_RECALC_CACHES; | ||||
| BLI_addtail(&gpf_dst->strokes, gps_dst); | BLI_addtail(&gpf_dst->strokes, gps_dst); | ||||
| } | } | ||||
| } | } | ||||
| /* clean up temp data */ | /* clean up temp data */ | ||||
| gpencil_interpolate_exit(C, op); | gpencil_interpolate_exit(C, op); | ||||
| ▲ Show 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) | static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | bGPdata *gpd = CTX_data_gpencil_data(C); | ||||
| bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); | bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); | ||||
| bGPDframe *actframe = active_gpl->actframe; | bGPDframe *actframe = active_gpl->actframe; | ||||
| Scene *scene = CTX_data_scene(C); | Object *ob = CTX_data_active_object(C); | ||||
| ToolSettings *ts = CTX_data_tool_settings(C); | ToolSettings *ts = CTX_data_tool_settings(C); | ||||
| Depsgraph *depsgraph = CTX_data_depsgraph(C); | |||||
| int cfra_eval = (int)DEG_get_ctime(depsgraph); | |||||
| GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; | GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; | ||||
| eGP_Interpolate_SettingsFlag flag = ipo_settings->flag; | eGP_Interpolate_SettingsFlag flag = ipo_settings->flag; | ||||
| /* cannot interpolate if not between 2 frames */ | /* cannot interpolate if not between 2 frames */ | ||||
| if (ELEM(NULL, actframe, actframe->next)) { | if (ELEM(NULL, actframe, actframe->next)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); | BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* cannot interpolate in extremes */ | /* cannot interpolate in extremes */ | ||||
| if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { | if (ELEM(cfra_eval, actframe->framenum, actframe->next->framenum)) { | ||||
| BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); | BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| /* loop all layer to check if need interpolation */ | /* loop all layer to check if need interpolation */ | ||||
| for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| bGPDframe *prevFrame, *nextFrame; | bGPDframe *prevFrame, *nextFrame; | ||||
| bGPDstroke *gps_from, *gps_to; | bGPDstroke *gps_from, *gps_to; | ||||
| Show All 31 Lines | for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { | ||||
| } | } | ||||
| else if (ipo_settings->type >= GP_IPO_BACK) { | else if (ipo_settings->type >= GP_IPO_BACK) { | ||||
| /* easing equation... */ | /* easing equation... */ | ||||
| factor = gp_interpolate_seq_easing_calc(ipo_settings, factor); | factor = gp_interpolate_seq_easing_calc(ipo_settings, factor); | ||||
| } | } | ||||
| /* create new strokes data with interpolated points reading original stroke */ | /* create new strokes data with interpolated points reading original stroke */ | ||||
| for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { | for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { | ||||
| bGPDstroke *new_stroke; | bGPDstroke *new_stroke = NULL; | ||||
| /* only selected */ | /* only selected */ | ||||
| if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* skip strokes that are invalid for current view */ | /* skip strokes that are invalid for current view */ | ||||
| if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | if (ED_gpencil_stroke_can_use(C, gps_from) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* check if the color is editable */ | /* check if the color is editable */ | ||||
| if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { | if (ED_gpencil_stroke_color_use(ob, gpl, gps_from) == false) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* get final stroke to interpolate */ | /* get final stroke to interpolate */ | ||||
| fFrame = BLI_findindex(&prevFrame->strokes, gps_from); | fFrame = BLI_findindex(&prevFrame->strokes, gps_from); | ||||
| gps_to = BLI_findlink(&nextFrame->strokes, fFrame); | gps_to = BLI_findlink(&nextFrame->strokes, fFrame); | ||||
| if (gps_to == NULL) { | if (gps_to == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* create a new frame if needed */ | /* create a new frame if needed */ | ||||
| if (interFrame == NULL) { | if (interFrame == NULL) { | ||||
| interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); | interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); | ||||
| interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; | interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; | ||||
| } | } | ||||
| /* create new stroke */ | /* create new stroke */ | ||||
| new_stroke = MEM_dupallocN(gps_from); | new_stroke = BKE_gpencil_stroke_duplicate(gps_from); | ||||
| new_stroke->points = MEM_dupallocN(gps_from->points); | |||||
| new_stroke->triangles = MEM_dupallocN(gps_from->triangles); | |||||
| new_stroke->tot_triangles = 0; | |||||
| new_stroke->flag |= GP_STROKE_RECALC_CACHES; | |||||
| /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ | /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ | ||||
| if (gps_from->totpoints > gps_to->totpoints) { | if (gps_from->totpoints > gps_to->totpoints) { | ||||
| /* free weights of removed points */ | |||||
| BKE_defvert_array_free_elems(gps_from->dvert + gps_to->totpoints, gps_from->totpoints - gps_to->totpoints); | |||||
| new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); | new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); | ||||
| new_stroke->dvert = MEM_recallocN(new_stroke->dvert, sizeof(*new_stroke->dvert) * gps_to->totpoints); | |||||
| new_stroke->totpoints = gps_to->totpoints; | new_stroke->totpoints = gps_to->totpoints; | ||||
| new_stroke->tot_triangles = 0; | new_stroke->tot_triangles = 0; | ||||
| new_stroke->flag |= GP_STROKE_RECALC_CACHES; | new_stroke->flag |= GP_STROKE_RECALC_CACHES; | ||||
| } | } | ||||
| /* update points position */ | /* update points position */ | ||||
| gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); | gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); | ||||
| /* add to strokes */ | /* add to strokes */ | ||||
| BLI_addtail(&interFrame->strokes, new_stroke); | BLI_addtail(&interFrame->strokes, new_stroke); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* notifiers */ | /* notifiers */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) | void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| Show All 25 Lines | if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) | static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| bGPdata *gpd = ED_gpencil_data_get_active(C); | |||||
| /* Go through each layer, deleting the breakdowns around the current frame, | /* Go through each layer, deleting the breakdowns around the current frame, | ||||
| * but only if there is a keyframe nearby to stop at | * but only if there is a keyframe nearby to stop at | ||||
| */ | */ | ||||
| CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) | ||||
| { | { | ||||
| bGPDframe *start_key = NULL; | bGPDframe *start_key = NULL; | ||||
| bGPDframe *end_key = NULL; | bGPDframe *end_key = NULL; | ||||
| bGPDframe *gpf, *gpfn; | bGPDframe *gpf, *gpfn; | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if ((start_key && end_key) && | ||||
| /* Now free the last one... */ | /* Now free the last one... */ | ||||
| BKE_gpencil_free_strokes(end_key); | BKE_gpencil_free_strokes(end_key); | ||||
| BLI_freelinkN(&gpl->frames, end_key); | BLI_freelinkN(&gpl->frames, end_key); | ||||
| } | } | ||||
| } | } | ||||
| CTX_DATA_END; | CTX_DATA_END; | ||||
| /* notifiers */ | /* notifiers */ | ||||
| DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); | |||||
| WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot) | void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot) | ||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| Show All 13 Lines | |||||