Blender  V2.93
gpencil_interpolate.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2016, Blender Foundation
17  * This is a new part of Blender
18  * Operators for interpolating new Grease Pencil frames from existing strokes
19  */
20 
25 #include <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_blenlib.h"
34 #include "BLI_easing.h"
35 #include "BLI_ghash.h"
36 #include "BLI_math.h"
37 #include "BLI_utildefines.h"
38 
39 #include "BLT_translation.h"
40 
41 #include "DNA_color_types.h"
42 #include "DNA_gpencil_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_screen_types.h"
47 #include "DNA_space_types.h"
48 #include "DNA_view3d_types.h"
49 
50 #include "BKE_colortools.h"
51 #include "BKE_context.h"
52 #include "BKE_gpencil.h"
53 #include "BKE_gpencil_geom.h"
54 #include "BKE_report.h"
55 
56 #include "UI_interface.h"
57 #include "UI_resources.h"
58 
59 #include "WM_api.h"
60 #include "WM_types.h"
61 
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 
65 #include "ED_gpencil.h"
66 #include "ED_screen.h"
67 
68 #include "DEG_depsgraph.h"
69 
70 #include "gpencil_intern.h"
71 
72 /* Temporary interpolate operation data */
73 typedef struct tGPDinterpolate_layer {
75 
77  struct bGPDlayer *gpl;
85  float factor;
86 
87  /* List of strokes and Hash tablets to create temp relationship between strokes. */
91 
93 
94 typedef struct tGPDinterpolate {
98  struct Scene *scene;
100  struct ScrArea *area;
102  struct ARegion *region;
104  struct Object *ob;
106  struct bGPdata *gpd;
108  struct Material *mat;
109  /* Space Conversion Data */
110  struct GP_SpaceConversion gsc;
111 
113  int cframe;
117  float shift;
119  float init_factor;
121  float low_limit;
123  float high_limit;
125  int flag;
127  int flipmode;
132 
133  NumInput num; /* numeric input */
135 
137  /* No flip. */
139  /* Flip always. */
141  /* Flip if needed. */
144 
145 /* ************************************************ */
146 /* Core/Shared Utilities */
147 
148 /* Poll callback for interpolation operators */
150 {
153 
154  /* only 3D view */
156  if (area && area->spacetype != SPACE_VIEW3D) {
157  return false;
158  }
159 
160  /* need data to interpolate */
161  if (ELEM(NULL, gpd, gpl)) {
162  return false;
163  }
164 
165  return true;
166 }
167 
168 /* Return if the stroke must be flipped or not. The logic of the calculation
169  * is to check if the lines from extremes crossed. All is done in 2D. */
171  Object *ob,
172  bGPDlayer *gpl,
173  GP_SpaceConversion *gsc,
174  bGPDstroke *gps_from,
175  bGPDstroke *gps_to)
176 {
177  float diff_mat[4][4];
178  /* calculate parent matrix */
180  bGPDspoint *pt, pt_dummy_ps;
181  float v_from_start[2], v_to_start[2], v_from_end[2], v_to_end[2];
182 
183  /* Line from start of strokes. */
184  pt = &gps_from->points[0];
185  gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
186  gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_start[0], &v_from_start[1]);
187 
188  pt = &gps_to->points[0];
189  gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
190  gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_start[0], &v_to_start[1]);
191 
192  /* Line from end of strokes. */
193  pt = &gps_from->points[gps_from->totpoints - 1];
194  gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
195  gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_from_end[0], &v_from_end[1]);
196 
197  pt = &gps_to->points[gps_to->totpoints - 1];
198  gpencil_point_to_parent_space(pt, diff_mat, &pt_dummy_ps);
199  gpencil_point_to_xy_fl(gsc, gps_from, &pt_dummy_ps, &v_to_end[0], &v_to_end[1]);
200 
201  const bool isect_lines = (isect_seg_seg_v2(v_from_start, v_to_start, v_from_end, v_to_end) ==
203 
204  /* If the vectors intersect. */
205  if (isect_lines) {
206  /* For sharp angles, check distance between extremes. */
207  float v1[2], v2[2];
208  sub_v2_v2v2(v1, v_to_start, v_from_start);
209  sub_v2_v2v2(v2, v_to_end, v_from_end);
210  float angle = angle_v2v2(v1, v2);
211  if (angle < DEG2RADF(15.0f)) {
212  /* Check the original stroke orientation using a point of destination stroke
213  * `(S)<--??-->(E) <--->`. */
214  float dist_start = len_squared_v2v2(v_from_start, v_to_start);
215  float dist_end = len_squared_v2v2(v_from_end, v_to_start);
216  /* Oriented with end nearer of destination stroke.
217  * `(S)--->(E) <--->` */
218  if (dist_start >= dist_end) {
219  dist_start = len_squared_v2v2(v_from_end, v_to_start);
220  dist_end = len_squared_v2v2(v_from_end, v_to_end);
221  /* `(S)--->(E) (E)<---(S)` */
222  return (dist_start >= dist_end);
223  }
224 
225  /* Oriented inversed with original stroke start near of destination stroke.
226  * `(E)<----(S) <--->` */
227  dist_start = len_squared_v2v2(v_from_start, v_to_start);
228  dist_end = len_squared_v2v2(v_from_start, v_to_end);
229  /* `(E)<---(S) (S)--->(E)` */
230  return (dist_start < dist_end);
231  }
232 
233  return true;
234  }
235 
236  /* Check that both vectors have the same direction. */
237  float v1[2], v2[2];
238  sub_v2_v2v2(v1, v_from_end, v_from_start);
239  sub_v2_v2v2(v2, v_to_end, v_to_start);
240  mul_v2_v2v2(v1, v1, v2);
241  if ((v1[0] < 0.0f) && (v1[1] < 0.0f)) {
242  return true;
243  }
244 
245  return false;
246 }
247 
248 /* Return the stroke related to the selection index, returning the stroke with
249  * the smallest selection index greater than reference index. */
251  bGPDframe *gpf,
252  const int reference_index)
253 {
254  bGPDstroke *gps_found = NULL;
255  int lower_index = INT_MAX;
256  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
257  if (gps->select_index > reference_index) {
258  if (!BLI_ghash_haskey(used_strokes, gps)) {
259  if (gps->select_index < lower_index) {
260  lower_index = gps->select_index;
261  gps_found = gps;
262  }
263  }
264  }
265  }
266 
267  /* Set as used. */
268  if (gps_found) {
269  BLI_ghash_insert(used_strokes, gps_found, gps_found);
270  }
271 
272  return gps_found;
273 }
274 
275 /* Load a Hash with the relationship between strokes. */
277  tGPDinterpolate *tgpi,
278  tGPDinterpolate_layer *tgpil)
279 {
280  bGPdata *gpd = tgpi->gpd;
281  const bool only_selected = ((GPENCIL_EDIT_MODE(gpd)) &&
283  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
284 
285  /* Create hash tablets with relationship between strokes. */
287  tgpil->used_strokes = BLI_ghash_ptr_new(__func__);
288  tgpil->pair_strokes = BLI_ghash_ptr_new(__func__);
289 
290  /* Create a table with source and target pair of strokes. */
291  LISTBASE_FOREACH (bGPDstroke *, gps_from, &tgpil->prevFrame->strokes) {
292  bGPDstroke *gps_to = NULL;
293  /* only selected */
294  if ((GPENCIL_EDIT_MODE(gpd)) && (only_selected) &&
295  ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
296  continue;
297  }
298  /* skip strokes that are invalid for current view */
299  if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
300  continue;
301  }
302  /* Check if the material is editable. */
303  if (ED_gpencil_stroke_material_editable(tgpi->ob, tgpil->gpl, gps_from) == false) {
304  continue;
305  }
306  /* Try to get the related stroke. */
307  if ((is_multiedit) && (gps_from->select_index > 0)) {
309  tgpil->used_strokes, tgpil->nextFrame, gps_from->select_index);
310  }
311  /* If not found, get final stroke to interpolate using position in the array. */
312  if (gps_to == NULL) {
313  int fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
314  gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
315  }
316 
317  if (ELEM(NULL, gps_from, gps_to)) {
318  continue;
319  }
320  if ((gps_from->totpoints == 0) || (gps_to->totpoints == 0)) {
321  continue;
322  }
323  /* Insert the pair entry in the hash table and the list of strokes to keep order. */
324  BLI_addtail(&tgpil->selected_strokes, BLI_genericNodeN(gps_from));
325  BLI_ghash_insert(tgpil->pair_strokes, gps_from, gps_to);
326  }
327 }
328 
330  float smooth_factor,
331  int smooth_steps)
332 {
333  if (smooth_factor == 0.0f) {
334  return;
335  }
336 
337  float reduce = 0.0f;
338  for (int r = 0; r < smooth_steps; r++) {
339  for (int i = 0; i < gps->totpoints - 1; i++) {
340  BKE_gpencil_stroke_smooth(gps, i, smooth_factor - reduce);
341  BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
342  }
343  reduce += 0.25f; /* reduce the factor */
344  }
345 }
346 /* Perform interpolation */
347 static void gpencil_interpolate_update_points(const bGPDstroke *gps_from,
348  const bGPDstroke *gps_to,
349  bGPDstroke *new_stroke,
350  float factor)
351 {
352  /* update points */
353  for (int i = 0; i < new_stroke->totpoints; i++) {
354  const bGPDspoint *prev = &gps_from->points[i];
355  const bGPDspoint *next = &gps_to->points[i];
356  bGPDspoint *pt = &new_stroke->points[i];
357 
358  /* Interpolate all values */
359  interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
360  pt->pressure = interpf(prev->pressure, next->pressure, 1.0f - factor);
361  pt->strength = interpf(prev->strength, next->strength, 1.0f - factor);
362  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
363  }
364 }
365 
366 /* ****************** Interpolate Interactive *********************** */
367 /* Helper: free all temp strokes for display. */
369 {
370  if (gpf == NULL) {
371  return;
372  }
373 
375  if (gps->flag & GP_STROKE_TAG) {
376  BLI_remlink(&gpf->strokes, gps);
378  }
379  }
380 }
381 
382 /* Helper: Untag all strokes. */
384 {
385  if (gpl == NULL) {
386  return;
387  }
388 
389  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
390  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
391  if (gps->flag & GP_STROKE_TAG) {
392  gps->flag &= ~GP_STROKE_TAG;
393  }
394  }
395  }
396 }
397 
398 /* Helper: Update all strokes interpolated */
400 {
401  bGPdata *gpd = tgpi->gpd;
402  const float shift = tgpi->shift;
403 
404  LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
405  const float factor = tgpil->factor + shift;
406 
407  bGPDframe *gpf = tgpil->gpl->actframe;
408  /* Free temp strokes used for display. */
410 
411  /* Clear previous interpolations. */
412  gpencil_interpolate_free_tagged_strokes(tgpil->interFrame);
413 
414  LISTBASE_FOREACH (LinkData *, link, &tgpil->selected_strokes) {
415  bGPDstroke *gps_from = link->data;
416  if (!BLI_ghash_haskey(tgpil->pair_strokes, gps_from)) {
417  continue;
418  }
419  bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(tgpil->pair_strokes, gps_from);
420 
421  /* Create new stroke. */
422  bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
423  new_stroke->flag |= GP_STROKE_TAG;
424  new_stroke->select_index = 0;
425 
426  /* Update points position. */
427  gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
428 
429  /* Calc geometry data. */
431  /* Add to strokes. */
432  BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
433 
434  /* Add temp strokes to display. */
435  if (gpf) {
436  bGPDstroke *gps_eval = BKE_gpencil_stroke_duplicate(new_stroke, true, true);
437  gps_eval->flag |= GP_STROKE_TAG;
438  BLI_addtail(&gpf->strokes, gps_eval);
439  }
440  }
441  }
442 
445 }
446 
447 /* Helper: Get previous keyframe (exclude breakdown type). */
449 {
450  if (gpl->actframe != NULL && gpl->actframe->framenum < cfra &&
452  return gpl->actframe;
453  }
454 
456  if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
457  continue;
458  }
459  if (gpf->framenum >= cfra) {
460  continue;
461  }
462  return gpf;
463  }
464 
465  return NULL;
466 }
467 
468 /* Helper: Get next keyframe (exclude breakdown type). */
470 {
471  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
472  if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
473  continue;
474  }
475  if (gpf->framenum <= cfra) {
476  continue;
477  }
478  return gpf;
479  }
480 
481  return NULL;
482 }
483 
484 /* Helper: Create internal strokes interpolated */
486 {
487  Scene *scene = tgpi->scene;
488  bGPdata *gpd = tgpi->gpd;
490  bGPDframe *actframe = active_gpl->actframe;
491 
492  /* save initial factor for active layer to define shift limits */
493  tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) /
494  (actframe->next->framenum - actframe->framenum + 1);
495 
496  /* limits are 100% below 0 and 100% over the 100% */
497  tgpi->low_limit = -1.0f - tgpi->init_factor;
498  tgpi->high_limit = 2.0f - tgpi->init_factor;
499 
500  /* set layers */
502  tGPDinterpolate_layer *tgpil;
503  /* all layers or only active */
504  if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) {
505  continue;
506  }
507  /* only editable and visible layers are considered */
509  continue;
510  }
511  if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
512  continue;
513  }
514 
515  /* create temp data for each layer */
516  tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
517 
518  tgpil->gpl = gpl;
520  tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpf, true);
521 
523  tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpf, true);
524 
525  BLI_addtail(&tgpi->ilayers, tgpil);
526 
527  /* Create a new temporary frame. */
528  tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
529  tgpil->interFrame->framenum = tgpi->cframe;
530 
531  /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */
532  tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) /
533  (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
534 
535  /* Load the relationship between frames. */
536  gpencil_stroke_pair_table(C, tgpi, tgpil);
537 
538  /* Create new strokes data with interpolated points reading original stroke. */
539  LISTBASE_FOREACH (LinkData *, link, &tgpil->selected_strokes) {
540  bGPDstroke *gps_from = link->data;
541  if (!BLI_ghash_haskey(tgpil->pair_strokes, gps_from)) {
542  continue;
543  }
544  bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(tgpil->pair_strokes, gps_from);
545 
546  /* If destination stroke is smaller, resize new_stroke to size of gps_to stroke. */
547  if (gps_from->totpoints > gps_to->totpoints) {
548  BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
549  }
550  if (gps_to->totpoints > gps_from->totpoints) {
551  BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
552  }
553 
554  /* Flip stroke. */
555  if (tgpi->flipmode == GP_INTERPOLATE_FLIP) {
556  BKE_gpencil_stroke_flip(gps_to);
557  }
558  else if (tgpi->flipmode == GP_INTERPOLATE_FLIPAUTO) {
560  tgpi->depsgraph, tgpi->ob, gpl, &tgpi->gsc, gps_from, gps_to)) {
561  BKE_gpencil_stroke_flip(gps_to);
562  }
563  }
564 
565  /* Create new stroke. */
566  bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
567  new_stroke->flag |= GP_STROKE_TAG;
568  new_stroke->select_index = 0;
569 
570  /* Update points position. */
571  gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
573 
574  /* Calc geometry data. */
576  /* add to strokes */
577  BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
578  }
579  }
580 }
581 
582 /* ----------------------- */
583 
584 /* Helper: calculate shift based on position of mouse (we only use x-axis for now.
585  * since this is more convenient for users to do), and store new shift value
586  */
587 static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
588 {
589  float mid = (float)(tgpi->region->winx - tgpi->region->winrct.xmin) / 2.0f;
590  float mpos = event->x - tgpi->region->winrct.xmin;
591 
592  if (mpos >= mid) {
593  tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid;
594  }
595  else {
596  tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid);
597  }
598 
599  CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
600  RNA_float_set(op->ptr, "shift", tgpi->shift);
601 }
602 
603 /* Helper: Draw status message while the user is running the operator */
605 {
606  Scene *scene = p->scene;
607  char status_str[UI_MAX_DRAW_STR];
608  char msg_str[UI_MAX_DRAW_STR];
609 
610  BLI_strncpy(msg_str, TIP_("GPencil Interpolation: "), UI_MAX_DRAW_STR);
611 
612  if (hasNumInput(&p->num)) {
613  char str_ofs[NUM_STR_REP_LEN];
614 
615  outputNumInput(&p->num, str_ofs, &scene->unit);
616  BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_ofs);
617  }
618  else {
619  BLI_snprintf(status_str,
620  sizeof(status_str),
621  "%s%d %%",
622  msg_str,
623  (int)((p->init_factor + p->shift) * 100.0f));
624  }
625 
626  ED_area_status_text(p->area, status_str);
628  C, TIP_("ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"));
629 }
630 
631 /* Update screen and stroke */
633 {
634  /* update shift indicator in header */
636  /* apply... */
637  tgpi->shift = RNA_float_get(op->ptr, "shift");
638  /* update points position */
640 }
641 
642 /* ----------------------- */
643 
644 /* Exit and free memory */
646 {
647  tGPDinterpolate *tgpi = op->customdata;
648  bGPdata *gpd = tgpi->gpd;
649 
650  /* don't assume that operator data exists at all */
651  if (tgpi) {
652  /* clear status message area */
653  ED_area_status_text(tgpi->area, NULL);
655 
656  /* Clear any temp stroke. */
658  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
660  }
661  }
662 
663  /* finally, free memory used by temp data */
664  LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
665  BKE_gpencil_free_strokes(tgpil->prevFrame);
666  BKE_gpencil_free_strokes(tgpil->nextFrame);
667  BKE_gpencil_free_strokes(tgpil->interFrame);
668  MEM_SAFE_FREE(tgpil->prevFrame);
669  MEM_SAFE_FREE(tgpil->nextFrame);
670  MEM_SAFE_FREE(tgpil->interFrame);
671 
672  /* Free list of strokes. */
673  BLI_freelistN(&tgpil->selected_strokes);
674 
675  /* Free Hash tablets. */
676  if (tgpil->used_strokes != NULL) {
677  BLI_ghash_free(tgpil->used_strokes, NULL, NULL);
678  }
679  if (tgpil->pair_strokes != NULL) {
680  BLI_ghash_free(tgpil->pair_strokes, NULL, NULL);
681  }
682  }
683 
684  BLI_freelistN(&tgpi->ilayers);
685 
686  MEM_SAFE_FREE(tgpi);
687  }
690 
691  /* clear pointer */
692  op->customdata = NULL;
693 }
694 
695 /* Init new temporary interpolation data */
697 {
698  /* set current scene and window */
700  tgpi->scene = CTX_data_scene(C);
701  tgpi->area = CTX_wm_area(C);
702  tgpi->region = CTX_wm_region(C);
703  tgpi->ob = CTX_data_active_object(C);
704  /* Setup space conversions. */
706 
707  /* set current frame number */
708  tgpi->cframe = tgpi->scene->r.cfra;
709 
710  /* set GP datablock */
711  tgpi->gpd = tgpi->ob->data;
712  /* set interpolation weight */
713  tgpi->shift = RNA_float_get(op->ptr, "shift");
715  tgpi->flag, (RNA_enum_get(op->ptr, "layers") == 1), GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS);
717  tgpi->flag,
718  ((GPENCIL_EDIT_MODE(tgpi->gpd)) && (RNA_boolean_get(op->ptr, "interpolate_selected_only"))),
720 
721  tgpi->flipmode = RNA_enum_get(op->ptr, "flip");
722 
723  tgpi->smooth_factor = RNA_float_get(op->ptr, "smooth_factor");
724  tgpi->smooth_steps = RNA_int_get(op->ptr, "smooth_steps");
725 
726  /* Untag strokes to be sure nothing is pending due any canceled process. */
727  LISTBASE_FOREACH (bGPDlayer *, gpl, &tgpi->gpd->layers) {
729  }
730 
731  /* Set layers */
733 
734  return 1;
735 }
736 
737 /* Allocate memory and initialize values */
739 {
740  tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
741 
742  /* define initial values */
744 
745  /* return context data for running operator */
746  return tgpi;
747 }
748 
749 /* Init interpolation: Allocate memory and set init values */
751 {
752  tGPDinterpolate *tgpi;
753 
754  /* check context */
756  if (tgpi == NULL) {
757  /* something wasn't set correctly in context */
759  return 0;
760  }
761 
762  /* everything is now setup ok */
763  return 1;
764 }
765 
766 /* ----------------------- */
767 
768 /* Invoke handler: Initialize the operator */
770 {
771  wmWindow *win = CTX_wm_window(C);
775  tGPDinterpolate *tgpi = NULL;
776 
777  /* Cannot interpolate if not between 2 frames. */
778  int cfra = CFRA;
779  bGPDframe *gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
780  bGPDframe *gpf_next = gpencil_get_next_keyframe(gpl, cfra);
781  if (ELEM(NULL, gpf_prv, gpf_next)) {
782  BKE_report(
783  op->reports,
784  RPT_ERROR,
785  "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)");
786  return OPERATOR_CANCELLED;
787  }
788 
790  BKE_report(op->reports, RPT_ERROR, "Cannot interpolate in curve edit mode");
791  return OPERATOR_CANCELLED;
792  }
793  /* try to initialize context data needed */
794  if (!gpencil_interpolate_init(C, op)) {
795  if (op->customdata) {
796  MEM_freeN(op->customdata);
797  }
798  return OPERATOR_CANCELLED;
799  }
800  tgpi = op->customdata;
801 
802  /* set cursor to indicate modal */
804 
805  /* update shift indicator in header */
809 
810  /* add a modal handler for this operator */
812 
813  return OPERATOR_RUNNING_MODAL;
814 }
815 
816 /* Modal handler: Events handling during interactive part */
817 static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
818 {
819  tGPDinterpolate *tgpi = op->customdata;
820  wmWindow *win = CTX_wm_window(C);
821  bGPDframe *gpf_dst;
822  bGPDstroke *gps_dst;
823  const bool has_numinput = hasNumInput(&tgpi->num);
824 
825  switch (event->type) {
826  case LEFTMOUSE: /* confirm */
827  case EVT_PADENTER:
828  case EVT_RETKEY: {
829  /* return to normal cursor and header status */
830  ED_area_status_text(tgpi->area, NULL);
833 
834  /* insert keyframes as required... */
835  LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) {
836  gpf_dst = BKE_gpencil_layer_frame_get(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
837  gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
838 
839  /* Copy strokes. */
840  LISTBASE_FOREACH (bGPDstroke *, gps_src, &tgpil->interFrame->strokes) {
841  if (gps_src->totpoints == 0) {
842  continue;
843  }
844 
845  /* make copy of source stroke, then adjust pointer to points too */
846  gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
847  gps_dst->flag &= ~GP_STROKE_TAG;
848 
849  /* Calc geometry data. */
850  BKE_gpencil_stroke_geometry_update(tgpi->gpd, gps_dst);
851 
852  BLI_addtail(&gpf_dst->strokes, gps_dst);
853  }
854  }
855 
856  /* clean up temp data */
858 
859  /* done! */
860  return OPERATOR_FINISHED;
861  }
862 
863  case EVT_ESCKEY: /* cancel */
864  case RIGHTMOUSE: {
865  /* return to normal cursor and header status */
866  ED_area_status_text(tgpi->area, NULL);
869 
870  /* clean up temp data */
872 
873  /* canceled! */
874  return OPERATOR_CANCELLED;
875  }
876 
877  case WHEELUPMOUSE: {
878  tgpi->shift = tgpi->shift + 0.01f;
879  CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
880  RNA_float_set(op->ptr, "shift", tgpi->shift);
881 
882  /* update screen */
883  gpencil_interpolate_update(C, op, tgpi);
884  break;
885  }
886  case WHEELDOWNMOUSE: {
887  tgpi->shift = tgpi->shift - 0.01f;
888  CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
889  RNA_float_set(op->ptr, "shift", tgpi->shift);
890 
891  /* update screen */
892  gpencil_interpolate_update(C, op, tgpi);
893  break;
894  }
895  case MOUSEMOVE: /* calculate new position */
896  {
897  /* only handle mousemove if not doing numinput */
898  if (has_numinput == false) {
899  /* update shift based on position of mouse */
900  gpencil_mouse_update_shift(tgpi, op, event);
901 
902  /* update screen */
903  gpencil_interpolate_update(C, op, tgpi);
904  }
905  break;
906  }
907  default: {
908  if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
909  const float factor = tgpi->init_factor;
910  float value;
911 
912  /* Grab shift from numeric input, and store this new value (the user see an int) */
913  value = (factor + tgpi->shift) * 100.0f;
914  applyNumInput(&tgpi->num, &value);
915  tgpi->shift = value / 100.0f;
916 
917  /* recalculate the shift to get the right value in the frame scale */
918  tgpi->shift = tgpi->shift - factor;
919 
920  CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit);
921  RNA_float_set(op->ptr, "shift", tgpi->shift);
922 
923  /* update screen */
924  gpencil_interpolate_update(C, op, tgpi);
925 
926  break;
927  }
928  /* unhandled event - allow to pass through */
930  }
931  }
932 
933  /* still running... */
934  return OPERATOR_RUNNING_MODAL;
935 }
936 
937 /* Cancel handler */
939 {
940  /* this is just a wrapper around exit() */
942 }
943 
945 {
946  static const EnumPropertyItem flip_modes[] = {
947  {GP_INTERPOLATE_NOFLIP, "NOFLIP", 0, "No Flip", ""},
948  {GP_INTERPOLATE_FLIP, "FLIP", 0, "Flip", ""},
949  {GP_INTERPOLATE_FLIPAUTO, "AUTO", 0, "Automatic", ""},
950  {0, NULL, 0, NULL, NULL},
951  };
952 
953  PropertyRNA *prop;
954 
955  /* identifiers */
956  ot->name = "Grease Pencil Interpolation";
957  ot->idname = "GPENCIL_OT_interpolate";
958  ot->description = "Interpolate grease pencil strokes between frames";
959 
960  /* callbacks */
965 
966  /* flags */
968 
969  static const EnumPropertyItem gpencil_interpolation_layer_items[] = {
970  {0, "ACTIVE", 0, "Active", ""},
971  {1, "ALL", 0, "All Layers", ""},
972  {0, NULL, 0, NULL, NULL},
973  };
974 
975  /* properties */
977  ot->srna,
978  "shift",
979  0.0f,
980  -1.0f,
981  1.0f,
982  "Shift",
983  "Bias factor for which frame has more influence on the interpolated strokes",
984  -0.9f,
985  0.9f);
986 
988  "layers",
989  gpencil_interpolation_layer_items,
990  0,
991  "Layer",
992  "Layers included in the interpolation");
993 
995  "interpolate_selected_only",
996  0,
997  "Only Selected",
998  "Interpolate only selected strokes");
999 
1000  RNA_def_enum(ot->srna,
1001  "flip",
1002  flip_modes,
1004  "Flip Mode",
1005  "Invert destination stroke to match start and end with source stroke");
1006 
1007  RNA_def_int(ot->srna,
1008  "smooth_steps",
1009  1,
1010  1,
1011  3,
1012  "Iterations",
1013  "Number of times to smooth newly created strokes",
1014  1,
1015  3);
1016 
1018  "smooth_factor",
1019  0.0f,
1020  0.0f,
1021  2.0f,
1022  "Smooth",
1023  "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
1024  0.0f,
1025  2.0f);
1026 
1027  prop = RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "");
1029 }
1030 
1031 /* ****************** Interpolate Sequence *********************** */
1032 
1033 /* Helper: Perform easing equation calculations for GP interpolation operator */
1035 {
1036  const float begin = 0.0f;
1037  const float change = 1.0f;
1038  const float duration = 1.0f;
1039 
1040  const float back = RNA_float_get(op->ptr, "back");
1041  const float amplitude = RNA_float_get(op->ptr, "amplitude");
1042  const float period = RNA_float_get(op->ptr, "period");
1043  const eBezTriple_Easing easing = RNA_enum_get(op->ptr, "easing");
1044  const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type");
1045  float result = time;
1046 
1047  switch (type) {
1048  case GP_IPO_BACK:
1049  switch (easing) {
1050  case BEZT_IPO_EASE_IN:
1051  result = BLI_easing_back_ease_in(time, begin, change, duration, back);
1052  break;
1053  case BEZT_IPO_EASE_OUT:
1054  result = BLI_easing_back_ease_out(time, begin, change, duration, back);
1055  break;
1056  case BEZT_IPO_EASE_IN_OUT:
1057  result = BLI_easing_back_ease_in_out(time, begin, change, duration, back);
1058  break;
1059 
1060  default: /* default/auto: same as ease out */
1061  result = BLI_easing_back_ease_out(time, begin, change, duration, back);
1062  break;
1063  }
1064  break;
1065 
1066  case GP_IPO_BOUNCE:
1067  switch (easing) {
1068  case BEZT_IPO_EASE_IN:
1069  result = BLI_easing_bounce_ease_in(time, begin, change, duration);
1070  break;
1071  case BEZT_IPO_EASE_OUT:
1072  result = BLI_easing_bounce_ease_out(time, begin, change, duration);
1073  break;
1074  case BEZT_IPO_EASE_IN_OUT:
1075  result = BLI_easing_bounce_ease_in_out(time, begin, change, duration);
1076  break;
1077 
1078  default: /* default/auto: same as ease out */
1079  result = BLI_easing_bounce_ease_out(time, begin, change, duration);
1080  break;
1081  }
1082  break;
1083 
1084  case GP_IPO_CIRC:
1085  switch (easing) {
1086  case BEZT_IPO_EASE_IN:
1087  result = BLI_easing_circ_ease_in(time, begin, change, duration);
1088  break;
1089  case BEZT_IPO_EASE_OUT:
1090  result = BLI_easing_circ_ease_out(time, begin, change, duration);
1091  break;
1092  case BEZT_IPO_EASE_IN_OUT:
1093  result = BLI_easing_circ_ease_in_out(time, begin, change, duration);
1094  break;
1095 
1096  default: /* default/auto: same as ease in */
1097  result = BLI_easing_circ_ease_in(time, begin, change, duration);
1098  break;
1099  }
1100  break;
1101 
1102  case GP_IPO_CUBIC:
1103  switch (easing) {
1104  case BEZT_IPO_EASE_IN:
1105  result = BLI_easing_cubic_ease_in(time, begin, change, duration);
1106  break;
1107  case BEZT_IPO_EASE_OUT:
1108  result = BLI_easing_cubic_ease_out(time, begin, change, duration);
1109  break;
1110  case BEZT_IPO_EASE_IN_OUT:
1111  result = BLI_easing_cubic_ease_in_out(time, begin, change, duration);
1112  break;
1113 
1114  default: /* default/auto: same as ease in */
1115  result = BLI_easing_cubic_ease_in(time, begin, change, duration);
1116  break;
1117  }
1118  break;
1119 
1120  case GP_IPO_ELASTIC:
1121  switch (easing) {
1122  case BEZT_IPO_EASE_IN:
1123  result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period);
1124  break;
1125  case BEZT_IPO_EASE_OUT:
1126  result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1127  break;
1128  case BEZT_IPO_EASE_IN_OUT:
1130  time, begin, change, duration, amplitude, period);
1131  break;
1132 
1133  default: /* default/auto: same as ease out */
1134  result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period);
1135  break;
1136  }
1137  break;
1138 
1139  case GP_IPO_EXPO:
1140  switch (easing) {
1141  case BEZT_IPO_EASE_IN:
1142  result = BLI_easing_expo_ease_in(time, begin, change, duration);
1143  break;
1144  case BEZT_IPO_EASE_OUT:
1145  result = BLI_easing_expo_ease_out(time, begin, change, duration);
1146  break;
1147  case BEZT_IPO_EASE_IN_OUT:
1148  result = BLI_easing_expo_ease_in_out(time, begin, change, duration);
1149  break;
1150 
1151  default: /* default/auto: same as ease in */
1152  result = BLI_easing_expo_ease_in(time, begin, change, duration);
1153  break;
1154  }
1155  break;
1156 
1157  case GP_IPO_QUAD:
1158  switch (easing) {
1159  case BEZT_IPO_EASE_IN:
1160  result = BLI_easing_quad_ease_in(time, begin, change, duration);
1161  break;
1162  case BEZT_IPO_EASE_OUT:
1163  result = BLI_easing_quad_ease_out(time, begin, change, duration);
1164  break;
1165  case BEZT_IPO_EASE_IN_OUT:
1166  result = BLI_easing_quad_ease_in_out(time, begin, change, duration);
1167  break;
1168 
1169  default: /* default/auto: same as ease in */
1170  result = BLI_easing_quad_ease_in(time, begin, change, duration);
1171  break;
1172  }
1173  break;
1174 
1175  case GP_IPO_QUART:
1176  switch (easing) {
1177  case BEZT_IPO_EASE_IN:
1178  result = BLI_easing_quart_ease_in(time, begin, change, duration);
1179  break;
1180  case BEZT_IPO_EASE_OUT:
1181  result = BLI_easing_quart_ease_out(time, begin, change, duration);
1182  break;
1183  case BEZT_IPO_EASE_IN_OUT:
1184  result = BLI_easing_quart_ease_in_out(time, begin, change, duration);
1185  break;
1186 
1187  default: /* default/auto: same as ease in */
1188  result = BLI_easing_quart_ease_in(time, begin, change, duration);
1189  break;
1190  }
1191  break;
1192 
1193  case GP_IPO_QUINT:
1194  switch (easing) {
1195  case BEZT_IPO_EASE_IN:
1196  result = BLI_easing_quint_ease_in(time, begin, change, duration);
1197  break;
1198  case BEZT_IPO_EASE_OUT:
1199  result = BLI_easing_quint_ease_out(time, begin, change, duration);
1200  break;
1201  case BEZT_IPO_EASE_IN_OUT:
1202  result = BLI_easing_quint_ease_in_out(time, begin, change, duration);
1203  break;
1204 
1205  default: /* default/auto: same as ease in */
1206  result = BLI_easing_quint_ease_in(time, begin, change, duration);
1207  break;
1208  }
1209  break;
1210 
1211  case GP_IPO_SINE:
1212  switch (easing) {
1213  case BEZT_IPO_EASE_IN:
1214  result = BLI_easing_sine_ease_in(time, begin, change, duration);
1215  break;
1216  case BEZT_IPO_EASE_OUT:
1217  result = BLI_easing_sine_ease_out(time, begin, change, duration);
1218  break;
1219  case BEZT_IPO_EASE_IN_OUT:
1220  result = BLI_easing_sine_ease_in_out(time, begin, change, duration);
1221  break;
1222 
1223  default: /* default/auto: same as ease in */
1224  result = BLI_easing_sine_ease_in(time, begin, change, duration);
1225  break;
1226  }
1227  break;
1228 
1229  default:
1230  printf("%s: Unknown interpolation type\n", __func__);
1231  break;
1232  }
1233 
1234  return result;
1235 }
1236 
1238 {
1243  bGPdata *gpd = ob->data;
1244  bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
1245  /* Setup space conversions. */
1246  GP_SpaceConversion gsc;
1248 
1249  int cfra = CFRA;
1250 
1251  GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate;
1252  const int step = RNA_int_get(op->ptr, "step");
1253  const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
1254  const bool all_layers = (bool)(RNA_enum_get(op->ptr, "layers") == 1);
1255  const bool only_selected = ((GPENCIL_EDIT_MODE(gpd)) &&
1256  (RNA_boolean_get(op->ptr, "interpolate_selected_only") != 0));
1257 
1258  eGP_InterpolateFlipMode flipmode = RNA_enum_get(op->ptr, "flip");
1259 
1260  const float smooth_factor = RNA_float_get(op->ptr, "smooth_factor");
1261  const int smooth_steps = RNA_int_get(op->ptr, "smooth_steps");
1262 
1263  const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type");
1264 
1265  if (ipo_settings->custom_ipo == NULL) {
1266  ipo_settings->custom_ipo = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
1267  }
1268  BKE_curvemapping_init(ipo_settings->custom_ipo);
1269 
1270  /* Cannot interpolate if not between 2 frames. */
1271  bGPDframe *gpf_prv = gpencil_get_previous_keyframe(active_gpl, cfra);
1272  bGPDframe *gpf_next = gpencil_get_next_keyframe(active_gpl, cfra);
1273  if (ELEM(NULL, gpf_prv, gpf_next)) {
1274  BKE_report(
1275  op->reports,
1276  RPT_ERROR,
1277  "Cannot find valid keyframes to interpolate (Breakdowns keyframes are not allowed)");
1278  return OPERATOR_CANCELLED;
1279  }
1280 
1282  BKE_report(op->reports, RPT_ERROR, "Cannot interpolate in curve edit mode");
1283  return OPERATOR_CANCELLED;
1284  }
1285 
1286  /* loop all layer to check if need interpolation */
1288  /* all layers or only active */
1289  if ((!all_layers) && (gpl != active_gpl)) {
1290  continue;
1291  }
1292  /* only editable and visible layers are considered */
1294  continue;
1295  }
1296  gpf_prv = gpencil_get_previous_keyframe(gpl, cfra);
1297  gpf_next = gpencil_get_next_keyframe(gpl, cfra);
1298 
1299  /* Need a set of frames to interpolate. */
1300  if ((gpf_prv == NULL) || (gpf_next == NULL)) {
1301  continue;
1302  }
1303 
1304  /* Store extremes. */
1305  bGPDframe *prevFrame = BKE_gpencil_frame_duplicate(gpf_prv, true);
1306  bGPDframe *nextFrame = BKE_gpencil_frame_duplicate(gpf_next, true);
1307 
1308  /* Create a table with source and target pair of strokes. */
1309  ListBase selected_strokes = {NULL};
1310  GHash *used_strokes = BLI_ghash_ptr_new(__func__);
1311  GHash *pair_strokes = BLI_ghash_ptr_new(__func__);
1312  LISTBASE_FOREACH (bGPDstroke *, gps_from, &prevFrame->strokes) {
1313  bGPDstroke *gps_to = NULL;
1314  /* Only selected. */
1315  if ((GPENCIL_EDIT_MODE(gpd)) && (only_selected) &&
1316  ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
1317  continue;
1318  }
1319  /* Skip strokes that are invalid for current view. */
1320  if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
1321  continue;
1322  }
1323  /* Check if the material is editable. */
1324  if (ED_gpencil_stroke_material_editable(ob, gpl, gps_from) == false) {
1325  continue;
1326  }
1327  /* Try to get the related stroke. */
1328  if ((is_multiedit) && (gps_from->select_index > 0)) {
1329  gps_to = gpencil_stroke_get_related(used_strokes, nextFrame, gps_from->select_index);
1330  }
1331  /* If not found, get final stroke to interpolate using position in the array. */
1332  if (gps_to == NULL) {
1333  int fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
1334  gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
1335  }
1336 
1337  if (ELEM(NULL, gps_from, gps_to)) {
1338  continue;
1339  }
1340  if ((gps_from->totpoints == 0) || (gps_to->totpoints == 0)) {
1341  continue;
1342  }
1343 
1344  /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
1345  if (gps_from->totpoints > gps_to->totpoints) {
1346  BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true);
1347  }
1348  if (gps_to->totpoints > gps_from->totpoints) {
1349  BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true);
1350  }
1351 
1352  /* Flip stroke. */
1353  if (flipmode == GP_INTERPOLATE_FLIP) {
1354  BKE_gpencil_stroke_flip(gps_to);
1355  }
1356  else if (flipmode == GP_INTERPOLATE_FLIPAUTO) {
1357  if (gpencil_stroke_need_flip(depsgraph, ob, gpl, &gsc, gps_from, gps_to)) {
1358  BKE_gpencil_stroke_flip(gps_to);
1359  }
1360  }
1361 
1362  /* Insert the pair entry in the hash table and in the list of strokes to keep same order.
1363  */
1364  BLI_addtail(&selected_strokes, BLI_genericNodeN(gps_from));
1365  BLI_ghash_insert(pair_strokes, gps_from, gps_to);
1366  }
1367 
1368  /* Loop over intermediary frames and create the interpolation. */
1369  for (int cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) {
1370  /* Get interpolation factor. */
1371  float framerange = nextFrame->framenum - prevFrame->framenum;
1372  CLAMP_MIN(framerange, 1.0f);
1373  float factor = (float)(cframe - prevFrame->framenum) / framerange;
1374 
1375  if (type == GP_IPO_CURVEMAP) {
1376  /* custom curvemap */
1377  if (ipo_settings->custom_ipo) {
1378  factor = BKE_curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor);
1379  }
1380  else {
1381  BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist");
1382  continue;
1383  }
1384  }
1385  else if (type >= GP_IPO_BACK) {
1386  /* easing equation... */
1387  factor = gpencil_interpolate_seq_easing_calc(op, factor);
1388  }
1389 
1390  /* Apply the factor to all pair of strokes. */
1391  LISTBASE_FOREACH (LinkData *, link, &selected_strokes) {
1392  bGPDstroke *gps_from = link->data;
1393  if (!BLI_ghash_haskey(pair_strokes, gps_from)) {
1394  continue;
1395  }
1396  bGPDstroke *gps_to = (bGPDstroke *)BLI_ghash_lookup(pair_strokes, gps_from);
1397  /* Create new stroke. */
1398  bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true);
1399  new_stroke->flag |= GP_STROKE_TAG;
1400  new_stroke->select_index = 0;
1401 
1402  /* Update points position. */
1403  gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
1404  gpencil_interpolate_smooth_stroke(new_stroke, smooth_factor, smooth_steps);
1405 
1406  /* Calc geometry data. */
1408 
1409  /* Add strokes to frame. */
1411  interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
1412 
1413  BLI_addtail(&interFrame->strokes, new_stroke);
1414  }
1415  }
1416 
1417  BLI_freelistN(&selected_strokes);
1418 
1419  /* Free Hash tablets. */
1420  if (used_strokes != NULL) {
1421  BLI_ghash_free(used_strokes, NULL, NULL);
1422  }
1423  if (pair_strokes != NULL) {
1424  BLI_ghash_free(pair_strokes, NULL, NULL);
1425  }
1426 
1427  BKE_gpencil_free_strokes(prevFrame);
1428  BKE_gpencil_free_strokes(nextFrame);
1429  MEM_SAFE_FREE(prevFrame);
1430  MEM_SAFE_FREE(nextFrame);
1431  }
1432 
1433  /* notifiers */
1436 
1437  return OPERATOR_FINISHED;
1438 }
1439 
1441 {
1442  uiLayout *layout = op->layout;
1444  uiLayout *col, *row;
1445  PointerRNA ptr;
1446 
1447  RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
1448 
1449  const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type");
1450 
1451  uiLayoutSetPropSep(layout, true);
1452  uiLayoutSetPropDecorate(layout, false);
1453  row = uiLayoutRow(layout, true);
1454  uiItemR(row, &ptr, "step", 0, NULL, ICON_NONE);
1455 
1456  row = uiLayoutRow(layout, true);
1457  uiItemR(row, &ptr, "layers", 0, NULL, ICON_NONE);
1458 
1460  row = uiLayoutRow(layout, true);
1461  uiItemR(row, &ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
1462  }
1463 
1464  row = uiLayoutRow(layout, true);
1465  uiItemR(row, &ptr, "flip", 0, NULL, ICON_NONE);
1466 
1467  col = uiLayoutColumn(layout, true);
1468  uiItemR(col, &ptr, "smooth_factor", 0, NULL, ICON_NONE);
1469  uiItemR(col, &ptr, "smooth_steps", 0, NULL, ICON_NONE);
1470 
1471  row = uiLayoutRow(layout, true);
1472  uiItemR(row, &ptr, "type", 0, NULL, ICON_NONE);
1473 
1474  if (type == GP_IPO_CURVEMAP) {
1475  /* Get an RNA pointer to ToolSettings to give to the custom curve. */
1478  PointerRNA gpsettings_ptr;
1480  &scene->id, &RNA_GPencilInterpolateSettings, &ts->gp_interpolate, &gpsettings_ptr);
1482  layout, &gpsettings_ptr, "interpolation_curve", 0, false, true, true, false);
1483  }
1484  else if (type != GP_IPO_LINEAR) {
1485  row = uiLayoutRow(layout, false);
1486  uiItemR(row, &ptr, "easing", 0, NULL, ICON_NONE);
1487  if (type == GP_IPO_BACK) {
1488  row = uiLayoutRow(layout, false);
1489  uiItemR(row, &ptr, "back", 0, NULL, ICON_NONE);
1490  }
1491  else if (type == GP_IPO_ELASTIC) {
1492  row = uiLayoutRow(layout, false);
1493  uiItemR(row, &ptr, "amplitude", 0, NULL, ICON_NONE);
1494  row = uiLayoutRow(layout, false);
1495  uiItemR(row, &ptr, "period", 0, NULL, ICON_NONE);
1496  }
1497  }
1498 }
1499 
1501 {
1502  static const EnumPropertyItem gpencil_interpolation_layer_items[] = {
1503  {0, "ACTIVE", 0, "Active", ""},
1504  {1, "ALL", 0, "All Layers", ""},
1505  {0, NULL, 0, NULL, NULL},
1506  };
1507 
1512  static const EnumPropertyItem gpencil_interpolation_type_items[] = {
1513  /* interpolation */
1514  {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"},
1515  {GP_IPO_LINEAR,
1516  "LINEAR",
1517  ICON_IPO_LINEAR,
1518  "Linear",
1519  "Straight-line interpolation between A and B (i.e. no ease in/out)"},
1520  {GP_IPO_CURVEMAP,
1521  "CUSTOM",
1522  ICON_IPO_BEZIER,
1523  "Custom",
1524  "Custom interpolation defined using a curve map"},
1525 
1526  /* easing */
1527  {0,
1528  "",
1529  0,
1530  N_("Easing (by strength)"),
1531  "Predefined inertial transitions, useful for motion graphics (from least to most "
1532  "''dramatic'')"},
1533  {GP_IPO_SINE,
1534  "SINE",
1535  ICON_IPO_SINE,
1536  "Sinusoidal",
1537  "Sinusoidal easing (weakest, almost linear but with a slight curvature)"},
1538  {GP_IPO_QUAD, "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"},
1539  {GP_IPO_CUBIC, "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"},
1540  {GP_IPO_QUART, "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"},
1541  {GP_IPO_QUINT, "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"},
1542  {GP_IPO_EXPO, "EXPO", ICON_IPO_EXPO, "Exponential", "Exponential easing (dramatic)"},
1543  {GP_IPO_CIRC,
1544  "CIRC",
1545  ICON_IPO_CIRC,
1546  "Circular",
1547  "Circular easing (strongest and most dynamic)"},
1548 
1549  {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"},
1550  {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"},
1551  {GP_IPO_BOUNCE,
1552  "BOUNCE",
1553  ICON_IPO_BOUNCE,
1554  "Bounce",
1555  "Exponentially decaying parabolic bounce, like when objects collide"},
1556  {GP_IPO_ELASTIC,
1557  "ELASTIC",
1558  ICON_IPO_ELASTIC,
1559  "Elastic",
1560  "Exponentially decaying sine wave, like an elastic band"},
1561 
1562  {0, NULL, 0, NULL, NULL},
1563  };
1564 
1565  static const EnumPropertyItem gpencil_interpolation_easing_items[] = {
1567  "AUTO",
1568  ICON_IPO_EASE_IN_OUT,
1569  "Automatic Easing",
1570  "Easing type is chosen automatically based on what the type of interpolation used "
1571  "(e.g. 'Ease In' for transitional types, and 'Ease Out' for dynamic effects)"},
1572 
1574  "EASE_IN",
1575  ICON_IPO_EASE_IN,
1576  "Ease In",
1577  "Only on the end closest to the next keyframe"},
1579  "EASE_OUT",
1580  ICON_IPO_EASE_OUT,
1581  "Ease Out",
1582  "Only on the end closest to the first keyframe"},
1584  "EASE_IN_OUT",
1585  ICON_IPO_EASE_IN_OUT,
1586  "Ease In and Out",
1587  "Segment between both keyframes"},
1588  {0, NULL, 0, NULL, NULL},
1589  };
1590 
1591  static const EnumPropertyItem flip_modes[] = {
1592  {GP_INTERPOLATE_NOFLIP, "NOFLIP", 0, "No Flip", ""},
1593  {GP_INTERPOLATE_FLIP, "FLIP", 0, "Flip", ""},
1594  {GP_INTERPOLATE_FLIPAUTO, "AUTO", 0, "Automatic", ""},
1595  {0, NULL, 0, NULL, NULL},
1596  };
1597 
1598  /* identifiers */
1599  ot->name = "Interpolate Sequence";
1600  ot->idname = "GPENCIL_OT_interpolate_sequence";
1601  ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames";
1602 
1603  /* api callbacks */
1607 
1608  RNA_def_int(ot->srna,
1609  "step",
1610  1,
1611  1,
1612  MAXFRAME,
1613  "Step",
1614  "Number of frames between generated interpolated frames",
1615  1,
1616  MAXFRAME);
1617 
1618  RNA_def_enum(ot->srna,
1619  "layers",
1620  gpencil_interpolation_layer_items,
1621  0,
1622  "Layer",
1623  "Layers included in the interpolation");
1624 
1626  "interpolate_selected_only",
1627  0,
1628  "Only Selected",
1629  "Interpolate only selected strokes");
1630 
1631  RNA_def_enum(ot->srna,
1632  "flip",
1633  flip_modes,
1635  "Flip Mode",
1636  "Invert destination stroke to match start and end with source stroke");
1637 
1638  RNA_def_int(ot->srna,
1639  "smooth_steps",
1640  1,
1641  1,
1642  3,
1643  "Iterations",
1644  "Number of times to smooth newly created strokes",
1645  1,
1646  3);
1647 
1649  "smooth_factor",
1650  0.0f,
1651  0.0f,
1652  2.0f,
1653  "Smooth",
1654  "Amount of smoothing to apply to interpolated strokes, to reduce jitter/noise",
1655  0.0f,
1656  2.0f);
1657 
1658  RNA_def_enum(ot->srna,
1659  "type",
1660  gpencil_interpolation_type_items,
1661  0,
1662  "Type",
1663  "Interpolation method to use the next time 'Interpolate Sequence' is run");
1664 
1665  RNA_def_enum(
1666  ot->srna,
1667  "easing",
1668  gpencil_interpolation_easing_items,
1669  0,
1670  "Easing",
1671  "Which ends of the segment between the preceding and following grease pencil frames "
1672  "easing interpolation is applied to");
1673 
1675  "back",
1676  1.702f,
1677  0.0f,
1678  FLT_MAX,
1679  "Back",
1680  "Amount of overshoot for 'back' easing",
1681  0.0f,
1682  FLT_MAX);
1683 
1685  "amplitude",
1686  0.15f,
1687  0.0f,
1688  FLT_MAX,
1689  "Amplitude",
1690  "Amount to boost elastic bounces for 'elastic' easing",
1691  0.0f,
1692  FLT_MAX);
1693 
1695  "period",
1696  0.15f,
1697  -FLT_MAX,
1698  FLT_MAX,
1699  "Period",
1700  "Time between bounces for elastic easing",
1701  -FLT_MAX,
1702  FLT_MAX);
1703 
1704  /* flags */
1706 }
1707 
1708 /* ******************** Remove Breakdowns ************************ */
1709 
1711 {
1712  ScrArea *area = CTX_wm_area(C);
1713  if (area == NULL) {
1714  return false;
1715  }
1716  if (!ELEM(area->spacetype, SPACE_VIEW3D, SPACE_ACTION)) {
1717  return false;
1718  }
1719 
1721  if (gpd == NULL) {
1722  return false;
1723  }
1725  if (gpl == NULL) {
1726  return false;
1727  }
1728 
1729  /* need to be on a breakdown frame */
1731  CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown");
1732  return false;
1733  }
1734 
1735  return true;
1736 }
1737 
1739 {
1741 
1742  /* Go through each layer, deleting the breakdowns around the current frame,
1743  * but only if there is a keyframe nearby to stop at
1744  */
1746  /* only editable and visible layers are considered */
1748  continue;
1749  }
1750  bGPDframe *start_key = NULL;
1751  bGPDframe *end_key = NULL;
1752  bGPDframe *gpf, *gpfn;
1753 
1754  /* Only continue if we're currently on a breakdown keyframe */
1756  continue;
1757  }
1758 
1759  /* Search left for "start_key" (i.e. the first breakdown to remove) */
1760  gpf = gpl->actframe;
1761  while (gpf) {
1762  if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
1763  /* A breakdown... keep going left */
1764  start_key = gpf;
1765  gpf = gpf->prev;
1766  }
1767  else {
1768  /* Not a breakdown (may be a key, or an extreme,
1769  * or something else that wasn't generated)... stop */
1770  break;
1771  }
1772  }
1773 
1774  /* Search right for "end_key" (i.e. the last breakdown to remove) */
1775  gpf = gpl->actframe;
1776  while (gpf) {
1777  if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) {
1778  /* A breakdown... keep going right */
1779  end_key = gpf;
1780  gpf = gpf->next;
1781  }
1782  else {
1783  /* Not a breakdown... stop */
1784  break;
1785  }
1786  }
1787 
1788  /* Did we find anything? */
1789  /* NOTE: We should only proceed if there's something before/after these extents...
1790  * Otherwise, there's just an extent of breakdowns with no keys to interpolate between
1791  */
1792  if ((start_key && end_key) && ELEM(NULL, start_key->prev, end_key->next) == false) {
1793  /* Set actframe to the key before start_key, since the keys have been removed now */
1794  gpl->actframe = start_key->prev;
1795 
1796  /* Free each frame we're removing (except the last one) */
1797  for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) {
1798  gpfn = gpf->next;
1799 
1800  /* free strokes and their associated memory */
1802  BLI_freelinkN(&gpl->frames, gpf);
1803  }
1804 
1805  /* Now free the last one... */
1806  BKE_gpencil_free_strokes(end_key);
1807  BLI_freelinkN(&gpl->frames, end_key);
1808  }
1809  }
1810 
1811  /* notifiers */
1814 
1815  return OPERATOR_FINISHED;
1816 }
1817 
1819 {
1820  /* identifiers */
1821  ot->name = "Delete Breakdowns";
1822  ot->idname = "GPENCIL_OT_interpolate_reverse";
1823  ot->description =
1824  "Remove breakdown frames generated by interpolating between two Grease Pencil frames";
1825 
1826  /* callbacks */
1829 
1830  /* flags */
1832 }
typedef float(TangentPoint)[2]
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
float BKE_curvemapping_evaluateF(const struct CurveMapping *cumap, int cur, float value)
struct CurveMapping * BKE_curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
Definition: colortools.c:88
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
@ CTX_MODE_EDIT_GPENCIL
Definition: BKE_context.h:130
struct bGPDlayer * CTX_data_active_gpencil_layer(const bContext *C)
Definition: context.c:1376
struct bGPdata * CTX_data_gpencil_data(const bContext *C)
Definition: context.c:1371
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1424
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1006
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
Definition: context.c:1174
bool BKE_gpencil_free_strokes(struct bGPDframe *gpf)
Definition: gpencil.c:425
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1650
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
void BKE_gpencil_free_stroke(struct bGPDstroke *gps)
Definition: gpencil.c:401
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1307
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:178
struct bGPDframe * BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src, const bool dup_strokes)
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:190
void BKE_gpencil_stroke_flip(struct bGPDstroke *gps)
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence)
Definition: gpencil_geom.c:841
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
bool BKE_gpencil_stroke_smooth(struct bGPDstroke *gps, int i, float inf)
Definition: gpencil_geom.c:778
void BKE_gpencil_stroke_uniform_subdivide(struct bGPdata *gpd, struct bGPDstroke *gps, const uint32_t target_number, const bool select)
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
float BLI_easing_sine_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:374
float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
Definition: easing.c:51
float BLI_easing_bounce_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:92
float BLI_easing_quint_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:360
float BLI_easing_quart_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:346
float BLI_easing_circ_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:113
float BLI_easing_quart_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:340
float BLI_easing_bounce_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:87
float BLI_easing_circ_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:101
float BLI_easing_expo_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:281
float BLI_easing_expo_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:289
float BLI_easing_elastic_ease_in(float time, float begin, float change, float duration, float amplitude, float period)
Definition: easing.c:172
float BLI_easing_quad_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:325
float BLI_easing_elastic_ease_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition: easing.c:205
float BLI_easing_cubic_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:122
float BLI_easing_elastic_ease_in_out(float time, float begin, float change, float duration, float amplitude, float period)
Definition: easing.c:237
float BLI_easing_quint_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:355
float BLI_easing_sine_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:379
float BLI_easing_bounce_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:69
float BLI_easing_quad_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:313
float BLI_easing_quad_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:319
float BLI_easing_circ_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:107
float BLI_easing_cubic_ease_out(float time, float begin, float change, float duration)
Definition: easing.c:128
float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
Definition: easing.c:44
float BLI_easing_quint_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:365
float BLI_easing_expo_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:297
float BLI_easing_quart_ease_in(float time, float begin, float change, float duration)
Definition: easing.c:334
float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
Definition: easing.c:58
float BLI_easing_cubic_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:134
float BLI_easing_sine_ease_in_out(float time, float begin, float change, float duration)
Definition: easing.c:384
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:941
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:281
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
Definition: BLI_listbase.h:184
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
struct LinkData * BLI_genericNodeN(void *data)
Definition: listbase.c:923
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:547
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float interpf(float a, float b, float t)
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
Definition: math_geom.c:1151
#define ISECT_LINE_LINE_CROSS
#define DEG2RADF(_deg)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t)
Definition: math_vector.c:49
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:483
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define CLAMP_MIN(a, b)
#define TIP_(msgid)
#define N_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
eBezTriple_Easing
@ BEZT_IPO_EASE_OUT
@ BEZT_IPO_EASE_AUTO
@ BEZT_IPO_EASE_IN
@ BEZT_IPO_EASE_IN_OUT
@ BEZT_KEYTYPE_BREAKDOWN
#define GPENCIL_EDIT_MODE(gpd)
@ GP_STROKE_TAG
@ GP_STROKE_SELECT
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
#define GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)
Object is a sort of wrapper for general info.
#define CFRA
eGP_Interpolate_Type
@ GP_IPO_BOUNCE
@ GP_IPO_QUINT
@ GP_IPO_QUART
@ GP_IPO_LINEAR
@ GP_IPO_CUBIC
@ GP_IPO_ELASTIC
@ GP_IPO_QUAD
@ GP_IPO_BACK
@ GP_IPO_CURVEMAP
@ GP_IPO_CIRC
@ GP_IPO_SINE
@ GP_IPO_EXPO
@ GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED
@ GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS
#define MAXFRAME
@ SPACE_ACTION
@ SPACE_VIEW3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings)
Definition: numinput.c:102
#define NUM_STR_REP_LEN
Definition: ED_numinput.h:27
bool applyNumInput(NumInput *n, float *vec)
Definition: numinput.c:207
bool hasNumInput(const NumInput *n)
Definition: numinput.c:185
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event)
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:815
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:840
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group RGB to Bright Vector Camera CLAMP
StructRNA RNA_GPencilInterpolateSettings
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
@ PROP_HIDDEN
Definition: RNA_types.h:202
#define C
Definition: RandGen.cpp:39
void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define NA_EDITED
Definition: WM_types.h:462
#define KM_PRESS
Definition: WM_types.h:242
#define NC_GPENCIL
Definition: WM_types.h:300
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
double time
Scene scene
const Depsgraph * depsgraph
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc)
void gpencil_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
void gpencil_point_to_xy_fl(const GP_SpaceConversion *gsc, const bGPDstroke *gps, const bGPDspoint *pt, float *r_x, float *r_y)
static void gpencil_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
static bGPDstroke * gpencil_stroke_get_related(GHash *used_strokes, bGPDframe *gpf, const int reference_index)
static float gpencil_interpolate_seq_easing_calc(wmOperator *op, float time)
static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
static tGPDinterpolate * gpencil_session_init_interpolation(bContext *C, wmOperator *op)
static bGPDframe * gpencil_get_previous_keyframe(bGPDlayer *gpl, int cfra)
static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
void GPENCIL_OT_interpolate(wmOperatorType *ot)
static void gpencil_interpolate_untag_strokes(bGPDlayer *gpl)
static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
static bool gpencil_view3d_poll(bContext *C)
static void gpencil_interpolate_update_points(const bGPDstroke *gps_from, const bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
static bool gpencil_interpolate_reverse_poll(bContext *C)
static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op))
static bGPDframe * gpencil_get_next_keyframe(bGPDlayer *gpl, int cfra)
static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate *p)
static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps, float smooth_factor, int smooth_steps)
struct tGPDinterpolate tGPDinterpolate
static bool gpencil_stroke_need_flip(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, GP_SpaceConversion *gsc, bGPDstroke *gps_from, bGPDstroke *gps_to)
static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot)
struct tGPDinterpolate_layer tGPDinterpolate_layer
static int gpencil_interpolate_init(bContext *C, wmOperator *op)
static bool gpencil_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
static void gpencil_interpolate_free_tagged_strokes(bGPDframe *gpf)
static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
eGP_InterpolateFlipMode
@ GP_INTERPOLATE_FLIP
@ GP_INTERPOLATE_NOFLIP
@ GP_INTERPOLATE_FLIPAUTO
static void gpencil_stroke_pair_table(bContext *C, tGPDinterpolate *tgpi, tGPDinterpolate_layer *tgpil)
static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
uint col
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static ulong * next
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:146
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_float_factor(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4133
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3585
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
struct CurveMapping * custom_ipo
struct bGPDlayer * gpl
struct bGPdata * gpd
struct Object * ob
void * data
struct ToolSettings * toolsettings
struct RenderData r
struct UnitSettings unit
struct GP_Interpolate_Settings gp_interpolate
struct bGPDframe * next
ListBase strokes
struct bGPDframe * prev
bGPDframe * actframe
ListBase frames
bGPDspoint * points
ListBase layers
int xmin
Definition: DNA_vec_types.h:79
struct bGPDlayer * gpl
struct bGPDframe * prevFrame
struct bGPDframe * nextFrame
struct tGPDinterpolate_layer * prev
struct bGPDframe * interFrame
struct ListBase selected_strokes
struct tGPDinterpolate_layer * next
struct Scene * scene
struct bGPdata * gpd
struct Material * mat
struct Depsgraph * depsgraph
struct Object * ob
struct ScrArea * area
struct GP_SpaceConversion gsc
struct ARegion * region
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:787
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
IDProperty * properties
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:207
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:216
@ WM_CURSOR_EW_SCROLL
Definition: wm_cursors.h:69
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ WHEELUPMOUSE
@ EVT_PADENTER
@ WHEELDOWNMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ EVT_ESCKEY
@ EVT_RETKEY
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156