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