Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/include/BDR_gpencil.h4
-rw-r--r--source/blender/include/BIF_editaction.h4
-rw-r--r--source/blender/src/editaction_gpencil.c217
-rw-r--r--source/blender/src/gpencil.c113
-rw-r--r--source/blender/src/header_action.c42
-rw-r--r--source/blender/src/usiblender.c1
6 files changed, 330 insertions, 51 deletions
diff --git a/source/blender/include/BDR_gpencil.h b/source/blender/include/BDR_gpencil.h
index 9b9294b0343..82263c8cda7 100644
--- a/source/blender/include/BDR_gpencil.h
+++ b/source/blender/include/BDR_gpencil.h
@@ -57,10 +57,13 @@ struct bGPDframe *gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe);
struct bGPDlayer *gpencil_layer_addnew(struct bGPdata *gpd);
struct bGPdata *gpencil_data_addnew(void);
+struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src);
+struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src);
struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd);
struct bGPdata *gpencil_data_getactive(struct ScrArea *sa);
short gpencil_data_setactive(struct ScrArea *sa, struct bGPdata *gpd);
+struct ScrArea *gpencil_data_findowner(struct bGPdata *gpd);
void gpencil_frame_delete_laststroke(struct bGPDframe *gpf);
@@ -79,7 +82,6 @@ void gpencil_delete_menu(void);
void gpencil_convert_operation(short mode);
void gpencil_convert_menu(void);
-//short gpencil_paint(short mousebutton);
short gpencil_do_paint(struct ScrArea *sa, short mousebutton);
#endif /* BDR_GPENCIL_H */
diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h
index 1425cf6a67c..ae330b30d81 100644
--- a/source/blender/include/BIF_editaction.h
+++ b/source/blender/include/BIF_editaction.h
@@ -201,6 +201,10 @@ void delete_gpencil_layers(void);
void delete_gplayer_frames(struct bGPDlayer *gpl);
void duplicate_gplayer_frames(struct bGPDlayer *gpd);
+void free_gpcopybuf(void);
+void copy_gpdata(void);
+void paste_gpdata(void);
+
void snap_gplayer_frames(struct bGPDlayer *gpl, short mode);
void mirror_gplayer_frames(struct bGPDlayer *gpl, short mode);
diff --git a/source/blender/src/editaction_gpencil.c b/source/blender/src/editaction_gpencil.c
index 14269080b1f..1f30b83c6b3 100644
--- a/source/blender/src/editaction_gpencil.c
+++ b/source/blender/src/editaction_gpencil.c
@@ -362,23 +362,224 @@ void duplicate_gplayer_frames (bGPDlayer *gpl)
/* duplicate this frame */
if (gpf->flag & GP_FRAME_SELECT) {
bGPDframe *gpfd;
- bGPDstroke *gps;
/* duplicate frame, and deselect self */
- gpfd= MEM_dupallocN(gpf);
+ gpfd= gpencil_frame_duplicate(gpf);
gpf->flag &= ~GP_FRAME_SELECT;
- /* duplicate list of strokes too */
- duplicatelist(&gpfd->strokes, &gpf->strokes);
+ BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
+ }
+ }
+}
+
+/* -------------------------------------- */
+/* Copy and Paste Tools */
+/* - The copy/paste buffer currently stores a set of GP_Layers, with temporary
+ * GP_Frames with the necessary strokes
+ * - Unless there is only one element in the buffer, names are also tested to check for compatability.
+ * - All pasted frames are offset by the same amount. This is calculated as the difference in the times of
+ * the current frame and the 'first keyframe' (i.e. the earliest one in all channels).
+ * - The earliest frame is calculated per copy operation.
+ */
+
+/* globals for copy/paste data (like for other copy/paste buffers) */
+ListBase gpcopybuf = {NULL, NULL};
+static float gpcopy_firstframe= 999999999.0f;
+
+/* This function frees any MEM_calloc'ed copy/paste buffer data */
+void free_gpcopybuf ()
+{
+ free_gpencil_layers(&gpcopybuf);
+
+ gpcopybuf.first= gpcopybuf.last= NULL;
+ gpcopy_firstframe= 999999999.0f;
+}
+
+/* This function adds data to the copy/paste buffer, freeing existing data first
+ * Only the selected action channels gets their selected keyframes copied.
+ */
+void copy_gpdata ()
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ /* clear buffer first */
+ free_gpcopybuf();
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+ if (datatype != ACTCONT_GPENCIL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* assume that each of these is an ipo-block */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ bGPDlayer *gpls, *gpln;
+ bGPDframe *gpf, *gpfn;
+
+ /* get new layer to put into buffer */
+ gpls= (bGPDlayer *)ale->data;
+ gpln= MEM_callocN(sizeof(bGPDlayer), "GPCopyPasteLayer");
+
+ gpln->frames.first= gpln->frames.last= NULL;
+ strcpy(gpln->info, gpls->info);
+
+ BLI_addtail(&gpcopybuf, gpln);
+
+ /* loop over frames, and copy only selected frames */
+ for (gpf= gpls->frames.first; gpf; gpf= gpf->next) {
+ /* if frame is selected, make duplicate it and its strokes */
+ if (gpf->flag & GP_FRAME_SELECT) {
+ /* add frame to buffer */
+ gpfn= gpencil_frame_duplicate(gpf);
+ BLI_addtail(&gpln->frames, gpfn);
+
+ /* check if this is the earliest frame encountered so far */
+ if (gpf->framenum < gpcopy_firstframe)
+ gpcopy_firstframe= gpf->framenum;
+ }
+ }
+ }
+
+ /* check if anything ended up in the buffer */
+ if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last))
+ error("Nothing copied to buffer");
+
+ /* free temp memory */
+ BLI_freelistN(&act_data);
+}
+
+void paste_gpdata ()
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ short no_name= 0;
+ float offset = CFRA - gpcopy_firstframe;
+
+ /* check if buffer is empty */
+ if (ELEM(NULL, gpcopybuf.first, gpcopybuf.last)) {
+ error("No data in buffer to paste");
+ return;
+ }
+ /* check if single channel in buffer (disregard names if so) */
+ if (gpcopybuf.first == gpcopybuf.last)
+ no_name= 1;
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+ if (datatype != ACTCONT_GPENCIL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* from selected channels */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ bGPDlayer *gpld= (bGPDlayer *)ale->data;
+ bGPDlayer *gpls= NULL;
+ bGPDframe *gpfs, *gpf;
+
+ /* find suitable layer from buffer to use to paste from */
+ for (gpls= gpcopybuf.first; gpls; gpls= gpls->next) {
+ /* check if layer name matches */
+ if ((no_name) || (strcmp(gpls->info, gpld->info)==0))
+ break;
+ }
+
+ /* this situation might occur! */
+ if (gpls == NULL)
+ continue;
+
+ /* add frames from buffer */
+ for (gpfs= gpls->frames.first; gpfs; gpfs= gpfs->next) {
+ /* temporarily apply offset to buffer-frame while copying */
+ gpfs->framenum += offset;
- /* dupalloc only makes another copy of mem, but doesn't adjust pointers */
- for (gps= gpfd->strokes.first; gps; gps= gps->next) {
- gps->points= MEM_dupallocN(gps->points);
+ /* get frame to copy data into (if no frame returned, then just ignore) */
+ gpf= gpencil_layer_getframe(gpld, gpfs->framenum, 1);
+ if (gpf) {
+ bGPDstroke *gps, *gpsn;
+ ScrArea *sa;
+
+ /* get area that gp-data comes from */
+ sa= gpencil_data_findowner((bGPdata *)ale->owner);
+
+ /* this should be the right frame... as it may be a pre-existing frame,
+ * must make sure that only compatible stroke types get copied over
+ * - we cannot just add a duplicate frame, as that would cause errors
+ * - need to check for compatible types to minimise memory usage (copying 'junk' over)
+ */
+ for (gps= gpfs->strokes.first; gps; gps= gps->next) {
+ short stroke_ok;
+
+ /* if there's an area, check that it supports this type of stroke */
+ if (sa) {
+ stroke_ok= 0;
+
+ /* check if spacetype supports this type of stroke
+ * - NOTE: must sync this with gp_paint_initstroke() in gpencil.c
+ */
+ switch (sa->spacetype) {
+ case SPACE_VIEW3D: /* 3D-View: either screen-aligned or 3d-space */
+ if ((gps->flag == 0) || (gps->flag & GP_STROKE_3DSPACE))
+ stroke_ok= 1;
+ break;
+
+ case SPACE_NODE: /* Nodes Editor: either screen-aligned or view-aligned */
+ case SPACE_IMAGE: /* Image Editor: either screen-aligned or view\image-aligned */
+ if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DSPACE))
+ stroke_ok= 1;
+ break;
+
+ case SPACE_SEQ: /* Sequence Editor: either screen-aligned or view-aligned */
+ if ((gps->flag == 0) || (gps->flag & GP_STROKE_2DIMAGE))
+ stroke_ok= 1;
+ break;
+ }
+ }
+ else
+ stroke_ok= 1;
+
+ /* if stroke is ok, we make a copy of this stroke and add to frame */
+ if (stroke_ok) {
+ /* make a copy of stroke, then of its points array */
+ gpsn= MEM_dupallocN(gps);
+ gpsn->points= MEM_dupallocN(gps->points);
+
+ /* append stroke to frame */
+ BLI_addtail(&gpf->strokes, gpsn);
+ }
+ }
+
+ /* if no strokes (i.e. new frame) added, free gpf */
+ if (gpf->strokes.first == NULL)
+ gpencil_layer_delframe(gpld, gpf);
}
- BLI_insertlinkafter(&gpl->frames, gpf, gpfd);
+ /* unapply offset from buffer-frame */
+ gpfs->framenum -= offset;
}
}
+
+ /* free temp memory */
+ BLI_freelistN(&act_data);
+
+ /* undo and redraw stuff */
+ allqueue(REDRAWVIEW3D, 0);
+ //allqueue(REDRAWNODES, 0);
+ allqueue(REDRAWACTION, 0);
+ BIF_undo_push("Paste Grease Pencil Frames");
}
/* -------------------------------------- */
diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c
index 57fd958a94e..f6703fbe66b 100644
--- a/source/blender/src/gpencil.c
+++ b/source/blender/src/gpencil.c
@@ -112,7 +112,7 @@ void free_gpencil_strokes (bGPDframe *gpf)
gpsn= gps->next;
/* free stroke memory arrays, then stroke itself */
- MEM_freeN(gps->points);
+ if (gps->points) MEM_freeN(gps->points);
BLI_freelinkN(&gpf->strokes, gps);
}
}
@@ -135,7 +135,7 @@ void free_gpencil_frames (bGPDlayer *gpl)
}
}
-/* Free all of the gp-layers for a viewport (list should be &G.vd->gpd or so) */
+/* Free all of the gp-layers for a viewport (list should be &gpd->layers or so) */
void free_gpencil_layers (ListBase *list)
{
bGPDlayer *gpl, *gpln;
@@ -255,13 +255,63 @@ bGPdata *gpencil_data_addnew (void)
/* -------- Data Duplication ---------- */
+/* make a copy of a given gpencil frame */
+bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
+{
+ bGPDstroke *gps, *gpsd;
+ bGPDframe *dst;
+
+ /* error checking */
+ if (src == NULL)
+ return NULL;
+
+ /* make a copy of the source frame */
+ dst= MEM_dupallocN(src);
+
+ /* copy strokes */
+ dst->strokes.first = dst->strokes.last= NULL;
+ for (gps= src->strokes.first; gps; gps= gps->next) {
+ /* make copy of source stroke, then adjust pointer to points too */
+ gpsd= MEM_dupallocN(gps);
+ gpsd->points= MEM_dupallocN(gps->points);
+
+ BLI_addtail(&dst->strokes, gpsd);
+ }
+
+ /* return new frame */
+ return dst;
+}
+
+/* make a copy of a given gpencil layer */
+bGPDlayer *gpencil_layer_duplicate (bGPDlayer *src)
+{
+ bGPDframe *gpf, *gpfd;
+ bGPDlayer *dst;
+
+ /* error checking */
+ if (src == NULL)
+ return NULL;
+
+ /* make a copy of source layer */
+ dst= MEM_dupallocN(src);
+
+ /* copy frames */
+ dst->frames.first= dst->frames.last= NULL;
+ for (gpf= src->frames.first; gpf; gpf= gpf->next) {
+ /* make a copy of source stroke */
+ gpfd= gpencil_frame_duplicate(gpf);
+ BLI_addtail(&dst->frames, gpfd);
+ }
+
+ /* return new layer */
+ return dst;
+}
+
/* make a copy of a given gpencil datablock */
bGPdata *gpencil_data_duplicate (bGPdata *src)
{
+ bGPDlayer *gpl, *gpld;
bGPdata *dst;
- bGPDlayer *gpld, *gpls;
- bGPDframe *gpfd, *gpfs;
- bGPDstroke *gps;
/* error checking */
if (src == NULL)
@@ -271,25 +321,11 @@ bGPdata *gpencil_data_duplicate (bGPdata *src)
dst= MEM_dupallocN(src);
/* copy layers */
- duplicatelist(&dst->layers, &src->layers);
-
- for (gpld=dst->layers.first, gpls=src->layers.first; gpld && gpls;
- gpld=gpld->next, gpls=gpls->next)
- {
- /* copy frames */
- duplicatelist(&gpld->frames, &gpls->frames);
-
- for (gpfd=gpld->frames.first, gpfs=gpls->frames.first; gpfd && gpfs;
- gpfd=gpfd->next, gpfs=gpfs->next)
- {
- /* copy strokes */
- duplicatelist(&gpfd->strokes, &gpfs->strokes);
-
- for (gps= gpfd->strokes.first; gps; gps= gps->next)
- {
- gps->points= MEM_dupallocN(gps->points);
- }
- }
+ dst->layers.first= dst->layers.last= NULL;
+ for (gpl= src->layers.first; gpl; gpl= gpl->next) {
+ /* make a copy of source layer and its data */
+ gpld= gpencil_layer_duplicate(gpl);
+ BLI_addtail(&dst->layers, gpld);
}
/* return new */
@@ -415,6 +451,30 @@ short gpencil_data_setactive (ScrArea *sa, bGPdata *gpd)
return 0;
}
+/* return the ScrArea that has the given GP-datablock
+ * - assumes that only searching in current screen
+ * - is based on GP-datablocks only being able to
+ * exist for one area at a time (i.e. not multiuser)
+ */
+ScrArea *gpencil_data_findowner (bGPdata *gpd)
+{
+ ScrArea *sa;
+
+ /* error checking */
+ if (gpd == NULL)
+ return NULL;
+
+ /* loop over all scrareas for current screen, and check if that area has this gpd */
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ /* use get-active func to see if match */
+ if (gpencil_data_getactive(sa) == gpd)
+ return sa;
+ }
+
+ /* not found */
+ return NULL;
+}
+
/* -------- GP-Frame API ---------- */
/* delete the last stroke of the given frame */
@@ -539,6 +599,7 @@ bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
else {
/* unresolved errogenous situation! */
printf("Error: cannot find appropriate gp-frame \n");
+ /* gpl->actframe should still be NULL */
}
}
else {
@@ -547,6 +608,7 @@ bGPDframe *gpencil_layer_getframe (bGPDlayer *gpl, int cframe, short addnew)
gpl->actframe= gpencil_frame_addnew(gpl, cframe);
else {
/* don't do anything... this may be when no frames yet! */
+ /* gpl->actframe should still be NULL */
}
}
@@ -792,7 +854,7 @@ static void gp_stroke_to_bezier (bGPDlayer *gpl, bGPDstroke *gps, Curve *cu)
/* set settings */
bezt->h1= bezt->h2= HD_FREE;
bezt->f1= bezt->f2= bezt->f3= SELECT;
- bezt->radius = bezt->weight = pt->pressure * gpl->thickness;
+ bezt->radius = bezt->weight = pt->pressure * gpl->thickness * 0.1;
}
/* must calculate handles or else we crash */
@@ -1717,7 +1779,6 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
break;
case SPACE_SEQ:
{
- /* for now, this is not applicable here... */
p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
}
break;
diff --git a/source/blender/src/header_action.c b/source/blender/src/header_action.c
index 2834a41e9ec..0cd5fcba271 100644
--- a/source/blender/src/header_action.c
+++ b/source/blender/src/header_action.c
@@ -285,10 +285,16 @@ void do_action_buttons(unsigned short event)
/* copy/paste buttons in Action Editor header */
case B_ACTCOPYKEYS:
- copy_actdata();
+ if (G.saction->mode == SACTCONT_GPENCIL)
+ copy_gpdata();
+ else
+ copy_actdata();
break;
case B_ACTPASTEKEYS:
- paste_actdata();
+ if (G.saction->mode == SACTCONT_GPENCIL)
+ paste_gpdata();
+ else
+ paste_actdata();
break;
case B_ACTPIN: /* __PINFAKE */
@@ -1735,20 +1741,24 @@ void action_buttons(void)
uiClearButLock();
xco += 8;
-
- /* COPY PASTE */
- uiBlockBeginAlign(block);
- if (curarea->headertype==HEADERTOP) {
- uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
- uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
- }
- else {
- uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
- uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
- }
- uiBlockEndAlign(block);
- xco += (XIC + 8);
-
+ }
+
+
+ /* COPY PASTE */
+ uiBlockBeginAlign(block);
+ if (curarea->headertype==HEADERTOP) {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ else {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ uiBlockEndAlign(block);
+ xco += (XIC + 8);
+
+
+ if (G.saction->mode != SACTCONT_GPENCIL) {
/* draw AUTOSNAP */
if (G.saction->flag & SACTION_DRAWTIME) {
uiDefButC(block, MENU, B_REDR,
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
index f6e4054379c..c4d22664b8e 100644
--- a/source/blender/src/usiblender.c
+++ b/source/blender/src/usiblender.c
@@ -1133,6 +1133,7 @@ void exit_usiblender(void)
free_matcopybuf();
free_ipocopybuf();
free_actcopybuf();
+ free_gpcopybuf();
free_vertexpaint();
free_texttools();