2
* $Id: editaction_gpencil.c 17126 2008-10-20 06:39:08Z aligorith $
4
* ***** BEGIN GPL LICENSE BLOCK *****
6
* This program is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU General Public License
8
* as published by the Free Software Foundation; either version 2
9
* of the License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software Foundation,
18
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
* The Original Code is Copyright (C) 2008, Blender Foundation
21
* This is a new part of Blender
23
* Contributor(s): Joshua Leung
25
* ***** END GPL LICENSE BLOCK *****
38
#include "MEM_guardedalloc.h"
42
#include "BLI_arithb.h"
43
#include "BLI_blenlib.h"
45
#include "DNA_listBase.h"
46
#include "DNA_action_types.h"
47
#include "DNA_gpencil_types.h"
48
#include "DNA_scene_types.h"
49
#include "DNA_screen_types.h"
50
#include "DNA_space_types.h"
51
#include "DNA_userdef_types.h"
52
#include "DNA_view3d_types.h"
53
#include "DNA_view2d_types.h"
55
#include "BKE_global.h"
56
#include "BKE_utildefines.h"
57
#include "BKE_blender.h"
61
#include "BIF_glutil.h"
62
#include "BIF_butspace.h"
63
#include "BIF_graphics.h"
64
#include "BIF_interface.h"
65
#include "BIF_mywindow.h"
66
#include "BIF_resources.h"
67
#include "BIF_space.h"
68
#include "BIF_screen.h"
69
#include "BIF_toolbox.h"
70
#include "BIF_toets.h"
72
#include "BIF_editaction.h"
73
#include "BSE_editaction_types.h"
75
#include "BDR_gpencil.h"
76
#include "BIF_drawgpencil.h"
78
#include "BSE_drawipo.h"
79
#include "BSE_headerbuttons.h"
89
/* ***************************************** */
90
/* NOTE ABOUT THIS FILE:
91
* This file contains code for editing Grease Pencil data in the Action Editor
92
* as a 'keyframes', so that a user can adjust the timing of Grease Pencil drawings.
93
* Therefore, this file mostly contains functions for selecting Grease-Pencil frames.
95
/* ***************************************** */
96
/* Generics - Loopers */
98
/* Loops over the gp-frames for a gp-layer, and applies the given callback */
99
short gplayer_frames_looper (bGPDlayer *gpl, short (*gpf_cb)(bGPDframe *))
108
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
109
/* execute callback */
114
/* nothing to return */
118
/* ****************************************** */
119
/* Data Conversion Tools */
121
/* make a listing all the gp-frames in a layer as cfraelems */
122
void gplayer_make_cfra_list (bGPDlayer *gpl, ListBase *elems, short onlysel)
128
if (ELEM(NULL, gpl, elems))
131
/* loop through gp-frames, adding */
132
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
133
if ((onlysel == 0) || (gpf->flag & GP_FRAME_SELECT)) {
134
ce= MEM_callocN(sizeof(CfraElem), "CfraElem");
136
ce->cfra= (float)gpf->framenum;
137
ce->sel= (gpf->flag & GP_FRAME_SELECT) ? 1 : 0;
139
BLI_addtail(elems, ce);
144
/* ***************************************** */
145
/* Selection Tools */
147
/* check if one of the frames in this layer is selected */
148
short is_gplayer_frame_selected (bGPDlayer *gpl)
156
/* stop at the first one found */
157
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
158
if (gpf->flag & GP_FRAME_SELECT)
166
/* helper function - select gp-frame based on SELECT_* mode */
167
static void gpframe_select (bGPDframe *gpf, short select_mode)
169
switch (select_mode) {
171
gpf->flag |= GP_FRAME_SELECT;
173
case SELECT_SUBTRACT:
174
gpf->flag &= ~GP_FRAME_SELECT;
177
gpf->flag ^= GP_FRAME_SELECT;
182
/* set all/none/invert select (like above, but with SELECT_* modes) */
183
void select_gpencil_frames (bGPDlayer *gpl, short select_mode)
191
/* handle according to mode */
192
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
193
gpframe_select(gpf, select_mode);
197
/* set all/none/invert select */
198
void set_gplayer_frame_selection (bGPDlayer *gpl, short mode)
204
/* convert mode to select_mode */
213
mode= SELECT_SUBTRACT;
219
/* now call the standard function */
220
select_gpencil_frames (gpl, mode);
223
/* select the frame in this layer that occurs on this frame (there should only be one at most) */
224
void select_gpencil_frame (bGPDlayer *gpl, int selx, short select_mode)
228
/* search through frames for a match */
229
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
230
/* there should only be one frame with this frame-number */
231
if (gpf->framenum == selx) {
232
gpframe_select(gpf, select_mode);
238
/* select the frames in this layer that occur within the bounds specified */
239
void borderselect_gplayer_frames (bGPDlayer *gpl, float min, float max, short select_mode)
243
/* only select those frames which are in bounds */
244
for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
245
if (IN_RANGE(gpf->framenum, min, max))
246
gpframe_select(gpf, select_mode);
251
/* De-selects or inverts the selection of Layers for a grease-pencil block
252
* mode: 0 = default behaviour (select all), 1 = test if (de)select all, 2 = invert all
254
void deselect_gpencil_layers (void *data, short mode)
256
ListBase act_data = {NULL, NULL};
261
filter= ACTFILTER_VISIBLE;
262
actdata_filter(&act_data, filter, data, ACTCONT_GPENCIL);
264
/* See if we should be selecting or deselecting */
266
for (ale= act_data.first; ale; ale= ale->next) {
270
if (ale->flag & GP_LAYER_SELECT)
277
/* Now set the flags */
278
for (ale= act_data.first; ale; ale= ale->next) {
279
bGPDlayer *gpl= (bGPDlayer *)ale->data;
282
gpl->flag ^= GP_LAYER_SELECT;
284
gpl->flag |= GP_LAYER_SELECT;
286
gpl->flag &= ~GP_LAYER_SELECT;
288
gpl->flag &= ~GP_LAYER_ACTIVE;
292
BLI_freelistN(&act_data);
295
/* ***************************************** */
296
/* Frame Editing Tools */
298
/* Delete selected grease-pencil layers */
299
void delete_gpencil_layers (void)
301
ListBase act_data = {NULL, NULL};
302
bActListElem *ale, *next;
307
/* determine what type of data we are operating on */
308
data = get_action_context(&datatype);
309
if (data == NULL) return;
310
if (datatype != ACTCONT_GPENCIL) return;
313
filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
314
actdata_filter(&act_data, filter, data, datatype);
316
/* clean up grease-pencil layers */
317
for (ale= act_data.first; ale; ale= next) {
318
bGPdata *gpd= (bGPdata *)ale->owner;
319
bGPDlayer *gpl= (bGPDlayer *)ale->data;
322
/* free layer and its data */
324
free_gpencil_frames(gpl);
325
BLI_freelinkN(&gpd->layers, gpl);
328
/* free temp memory */
329
BLI_freelinkN(&act_data, ale);
332
BIF_undo_push("Delete GPencil Layers");
333
allspace(REDRAWVIEW3D, 0);
334
allqueue(REDRAWACTION, 0);
337
/* Delete selected frames */
338
void delete_gplayer_frames (bGPDlayer *gpl)
340
bGPDframe *gpf, *gpfn;
346
/* check for frames to delete */
347
for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
350
if (gpf->flag & GP_FRAME_SELECT)
351
gpencil_layer_delframe(gpl, gpf);
355
/* Duplicate selected frames from given gp-layer */
356
void duplicate_gplayer_frames (bGPDlayer *gpl)
358
bGPDframe *gpf, *gpfn;
364
/* duplicate selected frames */
365
for (gpf= gpl->frames.first; gpf; gpf= gpfn) {
368
/* duplicate this frame */
369
if (gpf->flag & GP_FRAME_SELECT) {
372
/* duplicate frame, and deselect self */
373
gpfd= gpencil_frame_duplicate(gpf);
374
gpf->flag &= ~GP_FRAME_SELECT;
376
BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
381
/* -------------------------------------- */
382
/* Copy and Paste Tools */
383
/* - The copy/paste buffer currently stores a set of GP_Layers, with temporary
384
* GP_Frames with the necessary strokes
385
* - Unless there is only one element in the buffer, names are also tested to check for compatability.
386
* - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
387
* the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
388
* - The earliest frame is calculated per copy operation.
391
/* globals for copy/paste data (like for other copy/paste buffers) */
392
ListBase gpcopybuf = {NULL, NULL};
393
static int gpcopy_firstframe= 999999999;
395
/* This function frees any MEM_calloc'ed copy/paste buffer data */
396
void free_gpcopybuf ()
398
free_gpencil_layers(&gpcopybuf);
400
gpcopybuf.first= gpcopybuf.last= NULL;
401
gpcopy_firstframe= 999999999;
404
/* This function adds data to the copy/paste buffer, freeing existing data first
405
* Only the selected GP-layers get their selected keyframes copied.
409
ListBase act_data = {NULL, NULL};
415
/* clear buffer first */
419
data= get_action_context(&datatype);
420
if (data == NULL) return;
421
if (datatype != ACTCONT_GPENCIL) return;
424
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL);
425
actdata_filter(&act_data, filter, data, datatype);
427
/* assume that each of these is an ipo-block */
428
for (ale= act_data.first; ale; ale= ale->next) {
429
bGPDlayer *gpls, *gpln;
430
bGPDframe *gpf, *gpfn;
432
/* get new layer to put into buffer */
433
gpls= (bGPDlayer *)ale->data;
434
gpln= MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
436
gpln->frames.first= gpln->frames.last= NULL;
437
strcpy(gpln->info, gpls->info);
439
BLI_addtail(&gpcopybuf, gpln);
441
/* loop over frames, and copy only selected frames */
442
for (gpf= gpls->frames.first; gpf; gpf= gpf->next) {
443
/* if frame is selected, make duplicate it and its strokes */
444
if (gpf->flag & GP_FRAME_SELECT) {
445
/* add frame to buffer */
446
gpfn= gpencil_frame_duplicate(gpf);
447
BLI_addtail(&gpln->frames, gpfn);
449
/* check if this is the earliest frame encountered so far */
450
if (gpf->framenum < gpcopy_firstframe)
451
gpcopy_firstframe= gpf->framenum;
456
/* check if anything ended up in the buffer */
457
if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last))
458
error("Nothing copied to buffer");
460
/* free temp memory */
461
BLI_freelistN(&act_data);
466
ListBase act_data = {NULL, NULL};
472
const int offset = (CFRA - gpcopy_firstframe);
475
/* check if buffer is empty */
476
if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) {
477
error("No data in buffer to paste");
480
/* check if single channel in buffer (disregard names if so) */
481
if (gpcopybuf.first == gpcopybuf.last)
485
data= get_action_context(&datatype);
486
if (data == NULL) return;
487
if (datatype != ACTCONT_GPENCIL) return;
490
filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT);
491
actdata_filter(&act_data, filter, data, datatype);
493
/* from selected channels */
494
for (ale= act_data.first; ale; ale= ale->next) {
495
bGPDlayer *gpld= (bGPDlayer *)ale->data;
496
bGPDlayer *gpls= NULL;
497
bGPDframe *gpfs, *gpf;
499
/* find suitable layer from buffer to use to paste from */
500
for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) {
501
/* check if layer name matches */
502
if ((no_name) || (strcmp(gpls->info, gpld->info)==0))
506
/* this situation might occur! */
510
/* add frames from buffer */
511
for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) {
512
/* temporarily apply offset to buffer-frame while copying */
513
gpfs->framenum += offset;
515
/* get frame to copy data into (if no frame returned, then just ignore) */
516
gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1);
518
bGPDstroke *gps, *gpsn;
521
/* get area that gp-data comes from */
522
sa= gpencil_data_findowner((bGPdata *)ale->owner);
524
/* this should be the right frame... as it may be a pre-existing frame,
525
* must make sure that only compatible stroke types get copied over
526
* - we cannot just add a duplicate frame, as that would cause errors
527
* - need to check for compatible types to minimise memory usage (copying 'junk' over)
529
for (gps= gpfs->strokes.first; gps; gps= gps->next) {
532
/* if there's an area, check that it supports this type of stroke */
536
/* check if spacetype supports this type of stroke
537
* - NOTE: must sync this with gp_paint_initstroke() in gpencil.c
539
switch (sa->spacetype) {
540
case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */
541
if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
545
case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
546
case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
547
if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
551
case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
552
if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
560
/* if stroke is ok, we make a copy of this stroke and add to frame */
562
/* make a copy of stroke, then of its points array */
563
gpsn= MEM_dupallocN(gps);
564
gpsn->points= MEM_dupallocN(gps->points);
566
/* append stroke to frame */
567
BLI_addtail(&gpf->strokes, gpsn);
571
/* if no strokes (i.e. new frame) added, free gpf */
572
if (gpf->strokes.first == NULL)
573
gpencil_layer_delframe(gpld, gpf);
576
/* unapply offset from buffer-frame */
577
gpfs->framenum -= offset;
581
/* free temp memory */
582
BLI_freelistN(&act_data);
584
/* undo and redraw stuff */
585
allqueue(REDRAWVIEW3D, 0);
586
//allqueue(REDRAWNODES, 0);
587
allqueue(REDRAWACTION, 0);
588
BIF_undo_push("Paste Grease Pencil Frames");
591
/* -------------------------------------- */
594
static short snap_gpf_nearest (bGPDframe *gpf)
596
if (gpf->flag & GP_FRAME_SELECT)
597
gpf->framenum= (int)(floor(gpf->framenum+0.5));
601
static short snap_gpf_nearestsec (bGPDframe *gpf)
603
float secf = (float)FPS;
604
if (gpf->flag & GP_FRAME_SELECT)
605
gpf->framenum= (int)(floor(gpf->framenum/secf + 0.5f) * secf);
609
static short snap_gpf_cframe (bGPDframe *gpf)
611
if (gpf->flag & GP_FRAME_SELECT)
612
gpf->framenum= (int)CFRA;
616
static short snap_gpf_nearmarker (bGPDframe *gpf)
618
if (gpf->flag & GP_FRAME_SELECT)
619
gpf->framenum= (int)find_nearest_marker_time((float)gpf->framenum);
624
/* snap selected frames to ... */
625
void snap_gplayer_frames (bGPDlayer *gpl, short mode)
628
case 1: /* snap to nearest frame */
629
gplayer_frames_looper(gpl, snap_gpf_nearest);
631
case 2: /* snap to current frame */
632
gplayer_frames_looper(gpl, snap_gpf_cframe);
634
case 3: /* snap to nearest marker */
635
gplayer_frames_looper(gpl, snap_gpf_nearmarker);
637
case 4: /* snap to nearest second */
638
gplayer_frames_looper(gpl, snap_gpf_nearestsec);
640
default: /* just in case */
641
gplayer_frames_looper(gpl, snap_gpf_nearest);
646
/* -------------------------------------- */
649
static short mirror_gpf_cframe (bGPDframe *gpf)
653
if (gpf->flag & GP_FRAME_SELECT) {
654
diff= CFRA - gpf->framenum;
661
static short mirror_gpf_yaxis (bGPDframe *gpf)
665
if (gpf->flag & GP_FRAME_SELECT) {
666
diff= -gpf->framenum;
673
static short mirror_gpf_xaxis (bGPDframe *gpf)
677
if (gpf->flag & GP_FRAME_SELECT) {
678
diff= -gpf->framenum;
685
static short mirror_gpf_marker (bGPDframe *gpf)
687
static TimeMarker *marker;
688
static short initialised = 0;
691
/* In order for this mirror function to work without
692
* any extra arguments being added, we use the case
693
* of bezt==NULL to denote that we should find the
694
* marker to mirror over. The static pointer is safe
695
* to use this way, as it will be set to null after
696
* each cycle in which this is called.
701
if ((gpf->flag & GP_FRAME_SELECT) && (marker)) {
702
diff= (marker->frame - gpf->framenum);
703
gpf->framenum= (marker->frame + diff);
707
/* initialisation time */
709
/* reset everything for safety */
714
/* try to find a marker */
715
for (marker= G.scene->markers.first; marker; marker=marker->next) {
716
if (marker->flag & SELECT) {
722
if (initialised == 0)
731
/* mirror selected gp-frames on... */
732
void mirror_gplayer_frames (bGPDlayer *gpl, short mode)
735
case 1: /* mirror over current frame */
736
gplayer_frames_looper(gpl, mirror_gpf_cframe);
738
case 2: /* mirror over frame 0 */
739
gplayer_frames_looper(gpl, mirror_gpf_yaxis);
741
case 3: /* mirror over value 0 */
742
gplayer_frames_looper(gpl, mirror_gpf_xaxis);
744
case 4: /* mirror over marker */
745
mirror_gpf_marker(NULL);
746
gplayer_frames_looper(gpl, mirror_gpf_marker);
747
mirror_gpf_marker(NULL);
749
default: /* just in case */
750
gplayer_frames_looper(gpl, mirror_gpf_yaxis);
755
/* ***************************************** */