Blender  V2.93
editaction_gpencil.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) 2008, Blender Foundation
17  * This is a new part of Blender
18  */
19 
24 #include <math.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "MEM_guardedalloc.h"
31 
32 #include "BLI_blenlib.h"
33 #include "BLI_utildefines.h"
34 
35 #include "DNA_gpencil_types.h"
36 #include "DNA_scene_types.h"
37 
38 #include "BKE_fcurve.h"
39 #include "BKE_gpencil.h"
40 #include "BKE_report.h"
41 
42 #include "ED_anim_api.h"
43 #include "ED_gpencil.h"
44 #include "ED_keyframes_edit.h"
45 #include "ED_markers.h"
46 
47 #include "WM_api.h"
48 
49 #include "DEG_depsgraph.h"
50 
51 /* ***************************************** */
52 /* NOTE ABOUT THIS FILE:
53  * This file contains code for editing Grease Pencil data in the Action Editor
54  * as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
55  * Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
56  */
57 /* ***************************************** */
58 /* Generics - Loopers */
59 
60 /* Loops over the gp-frames for a gp-layer, and applies the given callback */
62  Scene *scene,
63  bool (*gpf_cb)(bGPDframe *, Scene *))
64 {
65  /* error checker */
66  if (gpl == NULL) {
67  return false;
68  }
69 
70  /* do loop */
71  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
72  /* execute callback */
73  if (gpf_cb(gpf, scene)) {
74  return true;
75  }
76  }
77 
78  /* nothing to return */
79  return false;
80 }
81 
82 /* ****************************************** */
83 /* Data Conversion Tools */
84 
85 /* make a listing all the gp-frames in a layer as cfraelems */
86 void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
87 {
88  CfraElem *ce;
89 
90  /* error checking */
91  if (ELEM(NULL, gpl, elems)) {
92  return;
93  }
94 
95  /* loop through gp-frames, adding */
96  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
97  if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
98  ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
99 
100  ce->cfra = (float)gpf->framenum;
101  ce->sel = (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
102 
103  BLI_addtail(elems, ce);
104  }
105  }
106 }
107 
108 /* ***************************************** */
109 /* Selection Tools */
110 
111 /* check if one of the frames in this layer is selected */
113 {
114  /* error checking */
115  if (gpl == NULL) {
116  return false;
117  }
118 
119  /* stop at the first one found */
120  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
121  if (gpf->flag & GP_FRAME_SELECT) {
122  return true;
123  }
124  }
125 
126  /* not found */
127  return false;
128 }
129 
130 /* helper function - select gp-frame based on SELECT_* mode */
131 static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
132 {
133  if (gpf == NULL) {
134  return;
135  }
136 
137  switch (select_mode) {
138  case SELECT_ADD:
139  gpf->flag |= GP_FRAME_SELECT;
140  break;
141  case SELECT_SUBTRACT:
142  gpf->flag &= ~GP_FRAME_SELECT;
143  break;
144  case SELECT_INVERT:
145  gpf->flag ^= GP_FRAME_SELECT;
146  break;
147  }
148 }
149 
150 /* set all/none/invert select (like above, but with SELECT_* modes) */
151 void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
152 {
153  /* error checking */
154  if (gpl == NULL) {
155  return;
156  }
157 
158  /* handle according to mode */
159  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
160  gpencil_frame_select(gpf, select_mode);
161  }
162 }
163 
164 /* set all/none/invert select */
166 {
167  /* error checking */
168  if (gpl == NULL) {
169  return;
170  }
171 
172  /* now call the standard function */
173  ED_gpencil_select_frames(gpl, mode);
174 }
175 
176 /* select the frame in this layer that occurs on this frame (there should only be one at most) */
177 void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
178 {
179  bGPDframe *gpf;
180 
181  if (gpl == NULL) {
182  return;
183  }
184 
185  gpf = BKE_gpencil_layer_frame_find(gpl, selx);
186 
187  if (gpf) {
188  gpencil_frame_select(gpf, select_mode);
189  }
190 }
191 
192 /* select the frames in this layer that occur within the bounds specified */
193 void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
194 {
195  if (gpl == NULL) {
196  return;
197  }
198 
199  /* only select those frames which are in bounds */
200  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
201  if (IN_RANGE(gpf->framenum, min, max)) {
202  gpencil_frame_select(gpf, select_mode);
203  }
204  }
205 }
206 
207 /* select the frames in this layer that occur within the lasso/circle region specified */
209  bGPDlayer *gpl,
210  short tool,
211  short select_mode)
212 {
213  if (gpl == NULL) {
214  return;
215  }
216 
217  /* only select frames which are within the region */
218  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
219  /* construct a dummy point coordinate to do this testing with */
220  float pt[2] = {0};
221 
222  pt[0] = gpf->framenum;
223  pt[1] = ked->channel_y;
224 
225  /* check the necessary regions */
226  if (tool == BEZT_OK_CHANNEL_LASSO) {
227  /* Lasso */
228  if (keyframe_region_lasso_test(ked->data, pt)) {
229  gpencil_frame_select(gpf, select_mode);
230  }
231  }
232  else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
233  /* Circle */
234  if (keyframe_region_circle_test(ked->data, pt)) {
235  gpencil_frame_select(gpf, select_mode);
236  }
237  }
238  }
239 }
240 
241 /* ***************************************** */
242 /* Frame Editing Tools */
243 
244 /* Delete selected frames */
246 {
247  bool changed = false;
248 
249  /* error checking */
250  if (gpl == NULL) {
251  return false;
252  }
253 
254  /* check for frames to delete */
255  LISTBASE_FOREACH_MUTABLE (bGPDframe *, gpf, &gpl->frames) {
256  if (gpf->flag & GP_FRAME_SELECT) {
258  changed = true;
259  }
260  }
261 
262  return changed;
263 }
264 
265 /* Duplicate selected frames from given gp-layer */
267 {
268  /* error checking */
269  if (gpl == NULL) {
270  return;
271  }
272 
273  /* duplicate selected frames */
274  LISTBASE_FOREACH_MUTABLE (bGPDframe *, gpf, &gpl->frames) {
275 
276  /* duplicate this frame */
277  if (gpf->flag & GP_FRAME_SELECT) {
278  bGPDframe *gpfd;
279 
280  /* duplicate frame, and deselect self */
281  gpfd = BKE_gpencil_frame_duplicate(gpf, true);
282  gpf->flag &= ~GP_FRAME_SELECT;
283 
284  BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
285  }
286  }
287 }
288 
295 {
296  if (gpl == NULL) {
297  return;
298  }
299 
300  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
301  if (gpf->flag & GP_FRAME_SELECT) {
302  gpf->key_type = type;
303  }
304  }
305 }
306 
307 /* -------------------------------------- */
308 /* Copy and Paste Tools:
309  * - The copy/paste buffer currently stores a set of GP_Layers, with temporary
310  * GP_Frames with the necessary strokes
311  * - Unless there is only one element in the buffer,
312  * names are also tested to check for compatibility.
313  * - All pasted frames are offset by the same amount.
314  * This is calculated as the difference in the times of the current frame and the
315  * 'first keyframe' (i.e. the earliest one in all channels).
316  * - The earliest frame is calculated per copy operation.
317  */
318 
319 /* globals for copy/paste data (like for other copy/paste buffers) */
321 static int gpencil_anim_copy_firstframe = 999999999;
322 static int gpencil_anim_copy_lastframe = -999999999;
323 static int gpencil_anim_copy_cfra = 0;
324 
325 /* This function frees any MEM_calloc'ed copy/paste buffer data */
327 {
330 
331  gpencil_anim_copy_firstframe = 999999999;
332  gpencil_anim_copy_lastframe = -999999999;
334 }
335 
336 /* This function adds data to the copy/paste buffer, freeing existing data first
337  * Only the selected GP-layers get their selected keyframes copied.
338  *
339  * Returns whether the copy operation was successful or not
340  */
342 {
343  ListBase anim_data = {NULL, NULL};
344  bAnimListElem *ale;
345  int filter;
346 
347  Scene *scene = ac->scene;
348 
349  /* clear buffer first */
351 
352  /* filter data */
354  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
355 
356  /* assume that each of these is a GP layer */
357  for (ale = anim_data.first; ale; ale = ale->next) {
358  ListBase copied_frames = {NULL, NULL};
359  bGPDlayer *gpl = (bGPDlayer *)ale->data;
360 
361  /* loop over frames, and copy only selected frames */
362  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
363  /* if frame is selected, make duplicate it and its strokes */
364  if (gpf->flag & GP_FRAME_SELECT) {
365  /* make a copy of this frame */
366  bGPDframe *new_frame = BKE_gpencil_frame_duplicate(gpf, true);
367  BLI_addtail(&copied_frames, new_frame);
368 
369  /* extend extents for keyframes encountered */
370  if (gpf->framenum < gpencil_anim_copy_firstframe) {
371  gpencil_anim_copy_firstframe = gpf->framenum;
372  }
373  if (gpf->framenum > gpencil_anim_copy_lastframe) {
374  gpencil_anim_copy_lastframe = gpf->framenum;
375  }
376  }
377  }
378 
379  /* create a new layer in buffer if there were keyframes here */
380  if (BLI_listbase_is_empty(&copied_frames) == false) {
381  bGPDlayer *new_layer = MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
382  BLI_addtail(&gpencil_anim_copybuf, new_layer);
383 
384  /* move over copied frames */
385  BLI_movelisttolist(&new_layer->frames, &copied_frames);
386  BLI_assert(copied_frames.first == NULL);
387 
388  /* make a copy of the layer's name - for name-based matching later... */
389  BLI_strncpy(new_layer->info, gpl->info, sizeof(new_layer->info));
390  }
391  }
392 
393  /* in case 'relative' paste method is used */
395 
396  /* clean up */
397  ANIM_animdata_freelist(&anim_data);
398 
399  /* check if anything ended up in the buffer */
401  BKE_report(ac->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
402  return false;
403  }
404 
405  /* report success */
406  return true;
407 }
408 
409 /* Pastes keyframes from buffer, and reports success */
410 bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
411 {
412  ListBase anim_data = {NULL, NULL};
413  bAnimListElem *ale;
414  int filter;
415 
416  Scene *scene = ac->scene;
417  bool no_name = false;
418  int offset = 0;
419 
420  /* check if buffer is empty */
422  BKE_report(ac->reports, RPT_ERROR, "No data in buffer to paste");
423  return false;
424  }
425 
426  /* check if single channel in buffer (disregard names if so) */
428  no_name = true;
429  }
430 
431  /* methods of offset (eKeyPasteOffset) */
432  switch (offset_mode) {
434  offset = (CFRA - gpencil_anim_copy_firstframe);
435  break;
437  offset = (CFRA - gpencil_anim_copy_lastframe);
438  break;
440  offset = (CFRA - gpencil_anim_copy_cfra);
441  break;
443  offset = 0;
444  break;
445  }
446 
447  /* filter data */
448  /* TODO: try doing it with selection, then without selection limits. */
451  ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
452 
453  /* from selected channels */
454  for (ale = anim_data.first; ale; ale = ale->next) {
455  bGPDlayer *gpld = (bGPDlayer *)ale->data;
456  bGPDlayer *gpls = NULL;
457  bGPDframe *gpfs, *gpf;
458 
459  /* find suitable layer from buffer to use to paste from */
460  for (gpls = gpencil_anim_copybuf.first; gpls; gpls = gpls->next) {
461  /* check if layer name matches */
462  if ((no_name) || STREQ(gpls->info, gpld->info)) {
463  break;
464  }
465  }
466 
467  /* this situation might occur! */
468  if (gpls == NULL) {
469  continue;
470  }
471 
472  /* add frames from buffer */
473  for (gpfs = gpls->frames.first; gpfs; gpfs = gpfs->next) {
474  /* temporarily apply offset to buffer-frame while copying */
475  gpfs->framenum += offset;
476 
477  /* get frame to copy data into (if no frame returned, then just ignore) */
478  gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW);
479  if (gpf) {
480  /* Ensure to use same keyframe type. */
481  gpf->key_type = gpfs->key_type;
482 
483  bGPDstroke *gps, *gpsn;
484 
485  /* This should be the right frame... as it may be a pre-existing frame,
486  * must make sure that only compatible stroke types get copied over
487  * - We cannot just add a duplicate frame, as that would cause errors
488  * - For now, we don't check if the types will be compatible since we
489  * don't have enough info to do so. Instead, we simply just paste,
490  * if it works, it will show up.
491  */
492  for (gps = gpfs->strokes.first; gps; gps = gps->next) {
493  /* make a copy of stroke, then of its points array */
494  gpsn = BKE_gpencil_stroke_duplicate(gps, true, true);
495 
496  /* append stroke to frame */
497  BLI_addtail(&gpf->strokes, gpsn);
498  }
499 
500  /* if no strokes (i.e. new frame) added, free gpf */
501  if (BLI_listbase_is_empty(&gpf->strokes)) {
503  }
504  }
505 
506  /* unapply offset from buffer-frame */
507  gpfs->framenum -= offset;
508  }
509 
510  /* Tag destination datablock. */
512  }
513 
514  /* clean up */
515  ANIM_animdata_freelist(&anim_data);
516  return true;
517 }
518 
519 /* -------------------------------------- */
520 /* Snap Tools */
521 
523 {
524 #if 0 /* note: gpf->framenum is already an int! */
525  if (gpf->flag & GP_FRAME_SELECT) {
526  gpf->framenum = (int)(floor(gpf->framenum + 0.5));
527  }
528 #endif
529  return false;
530 }
531 
533 {
534  float secf = (float)FPS;
535  if (gpf->flag & GP_FRAME_SELECT) {
536  gpf->framenum = (int)(floorf(gpf->framenum / secf + 0.5f) * secf);
537  }
538  return false;
539 }
540 
542 {
543  if (gpf->flag & GP_FRAME_SELECT) {
544  gpf->framenum = (int)CFRA;
545  }
546  return false;
547 }
548 
550 {
551  if (gpf->flag & GP_FRAME_SELECT) {
553  (float)gpf->framenum);
554  }
555  return false;
556 }
557 
558 /* snap selected frames to ... */
560 {
561  switch (mode) {
562  case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
564  break;
565  case SNAP_KEYS_CURFRAME: /* snap to current frame */
567  break;
568  case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
570  break;
571  case SNAP_KEYS_NEARSEC: /* snap to nearest second */
573  break;
574  default: /* just in case */
575  break;
576  }
577 }
578 
579 /* -------------------------------------- */
580 /* Mirror Tools */
581 
583 {
584  int diff;
585 
586  if (gpf->flag & GP_FRAME_SELECT) {
587  diff = CFRA - gpf->framenum;
588  gpf->framenum = CFRA + diff;
589  }
590 
591  return false;
592 }
593 
595 {
596  int diff;
597 
598  if (gpf->flag & GP_FRAME_SELECT) {
599  diff = -gpf->framenum;
600  gpf->framenum = diff;
601  }
602 
603  return false;
604 }
605 
607 {
608  int diff;
609 
610  /* NOTE: since we can't really do this, we just do the same as for yaxis... */
611  if (gpf->flag & GP_FRAME_SELECT) {
612  diff = -gpf->framenum;
613  gpf->framenum = diff;
614  }
615 
616  return false;
617 }
618 
620 {
621  static TimeMarker *marker;
622  static short initialized = 0;
623  int diff;
624 
625  /* In order for this mirror function to work without
626  * any extra arguments being added, we use the case
627  * of gpf==NULL to denote that we should find the
628  * marker to mirror over. The static pointer is safe
629  * to use this way, as it will be set to null after
630  * each cycle in which this is called.
631  */
632 
633  if (gpf != NULL) {
634  /* mirroring time */
635  if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
636  diff = (marker->frame - gpf->framenum);
637  gpf->framenum = (marker->frame + diff);
638  }
639  }
640  else {
641  /* initialization time */
642  if (initialized) {
643  /* reset everything for safety */
644  marker = NULL;
645  initialized = 0;
646  }
647  else {
648  /* try to find a marker */
650  if (marker) {
651  initialized = 1;
652  }
653  }
654  }
655 
656  return false;
657 }
658 
659 /* mirror selected gp-frames on... */
660 /* TODO: mirror over a specific time */
662 {
663  switch (mode) {
664  case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
666  break;
667  case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
669  break;
670  case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
672  break;
673  case MIRROR_KEYS_MARKER: /* mirror over marker */
677  break;
678  default: /* just in case */
680  break;
681  }
682 }
683 
684 /* ***************************************** */
typedef float(TangentPoint)[2]
bool BKE_gpencil_layer_frame_delete(struct bGPDlayer *gpl, struct bGPDframe *gpf)
Definition: gpencil.c:1467
struct bGPDframe * BKE_gpencil_layer_frame_find(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:1281
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1307
struct bGPDframe * BKE_gpencil_frame_duplicate(const struct bGPDframe *gpf_src, const bool dup_strokes)
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
void BKE_gpencil_free_layers(struct ListBase *list)
Definition: gpencil.c:469
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:190
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:188
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:352
void void void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define IN_RANGE(a, b, c)
#define UNUSED(x)
#define ELEM(...)
#define STREQ(a, b)
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
@ GP_FRAME_SELECT
#define CFRA
#define FPS
@ ANIMFILTER_FOREDIT
Definition: ED_anim_api.h:315
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:295
@ ANIMFILTER_LIST_VISIBLE
Definition: ED_anim_api.h:298
@ ANIMFILTER_NODUPLIS
Definition: ED_anim_api.h:328
@ ANIMFILTER_SEL
Definition: ED_anim_api.h:311
@ MIRROR_KEYS_YAXIS
@ MIRROR_KEYS_MARKER
@ MIRROR_KEYS_CURFRAME
@ MIRROR_KEYS_XAXIS
@ KEYFRAME_PASTE_OFFSET_NONE
@ KEYFRAME_PASTE_OFFSET_CFRA_END
@ KEYFRAME_PASTE_OFFSET_CFRA_RELATIVE
@ KEYFRAME_PASTE_OFFSET_CFRA_START
@ BEZT_OK_CHANNEL_CIRCLE
@ BEZT_OK_CHANNEL_LASSO
@ SNAP_KEYS_CURFRAME
@ SNAP_KEYS_NEARFRAME
@ SNAP_KEYS_NEARMARKER
@ SNAP_KEYS_NEARSEC
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_ADD
_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
Read Guarded memory(de)allocation.
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:425
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3442
TimeMarker * ED_markers_get_first_selected(ListBase *markers)
Definition: anim_markers.c:379
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
Definition: anim_markers.c:193
Scene scene
static bool gpencil_frame_snap_nearestsec(bGPDframe *gpf, Scene *scene)
static bool gpencil_frame_mirror_marker(bGPDframe *gpf, Scene *scene)
static bool gpencil_frame_snap_nearmarker(bGPDframe *gpf, Scene *scene)
void ED_gpencil_layer_frame_select_set(bGPDlayer *gpl, short mode)
void ED_gpencil_layer_frames_keytype_set(bGPDlayer *gpl, short type)
void ED_gpencil_layer_frames_duplicate(bGPDlayer *gpl)
static bool gpencil_frame_snap_nearest(bGPDframe *UNUSED(gpf), Scene *UNUSED(scene))
static void gpencil_frame_select(bGPDframe *gpf, short select_mode)
static bool gpencil_frame_mirror_xaxis(bGPDframe *gpf, Scene *UNUSED(scene))
bool ED_gpencil_layer_frames_delete(bGPDlayer *gpl)
bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode)
void ED_gpencil_select_frames(bGPDlayer *gpl, short select_mode)
void ED_gpencil_layer_mirror_frames(bGPDlayer *gpl, Scene *scene, short mode)
static int gpencil_anim_copy_lastframe
void ED_gpencil_select_frame(bGPDlayer *gpl, int selx, short select_mode)
static int gpencil_anim_copy_cfra
static bool gpencil_frame_mirror_yaxis(bGPDframe *gpf, Scene *UNUSED(scene))
bool ED_gpencil_layer_frames_looper(bGPDlayer *gpl, Scene *scene, bool(*gpf_cb)(bGPDframe *, Scene *))
void ED_gpencil_layer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode)
static bool gpencil_frame_mirror_cframe(bGPDframe *gpf, Scene *scene)
void ED_gpencil_layer_frames_select_box(bGPDlayer *gpl, float min, float max, short select_mode)
void ED_gpencil_layer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
bool ED_gpencil_layer_frame_select_check(bGPDlayer *gpl)
void ED_gpencil_layer_snap_frames(bGPDlayer *gpl, Scene *scene, short mode)
static int gpencil_anim_copy_firstframe
bool ED_gpencil_anim_copybuf_copy(bAnimContext *ac)
static bool gpencil_frame_snap_cframe(bGPDframe *gpf, Scene *scene)
void ED_gpencil_anim_copybuf_free(void)
static ListBase gpencil_anim_copybuf
static bool initialized
Definition: gpu_init_exit.c:41
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#define floorf(x)
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt=1)
#define min(a, b)
Definition: sort.c:51
float cfra
Definition: BKE_fcurve.h:56
int sel
Definition: BKE_fcurve.h:57
void * last
Definition: DNA_listBase.h:47
void * first
Definition: DNA_listBase.h:47
ListBase markers
struct Scene * scene
Definition: ED_anim_api.h:97
short datatype
Definition: ED_anim_api.h:75
void * data
Definition: ED_anim_api.h:73
struct ReportList * reports
Definition: ED_anim_api.h:108
struct bAnimListElem * next
Definition: ED_anim_api.h:135
struct ID * id
Definition: ED_anim_api.h:168
char info[128]
ListBase frames
struct bGPDstroke * next
float max
ccl_device_inline float2 floor(const float2 &a)