[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [16931] trunk/blender/source/blender: Grease Pencil:

Joshua Leung aligorith at gmail.com
Sun Oct 5 13:49:09 CEST 2008


Revision: 16931
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=16931
Author:   aligorith
Date:     2008-10-05 13:49:09 +0200 (Sun, 05 Oct 2008)

Log Message:
-----------
Grease Pencil:

* Separated duplicate methods out into several functions

* Added copy/paste for gp-frames in Action Editor. Only strokes that are appropriate for the spacetype that the destination layer belongs to will be added to avoid wasted memory usage. Otherwise, was impossible to move sketches between views/layers (which was intended for PyAPI access that didn't get done).

Note: there will currently still be an extra gp-frame created, even if the current no strokes got pasted. There's commented out code which would delete it, but somehow that causes errors, so better to be safe for now.

Modified Paths:
--------------
    trunk/blender/source/blender/include/BDR_gpencil.h
    trunk/blender/source/blender/include/BIF_editaction.h
    trunk/blender/source/blender/src/editaction_gpencil.c
    trunk/blender/source/blender/src/gpencil.c
    trunk/blender/source/blender/src/header_action.c
    trunk/blender/source/blender/src/usiblender.c

Modified: trunk/blender/source/blender/include/BDR_gpencil.h
===================================================================
--- trunk/blender/source/blender/include/BDR_gpencil.h	2008-10-05 10:48:07 UTC (rev 16930)
+++ trunk/blender/source/blender/include/BDR_gpencil.h	2008-10-05 11:49:09 UTC (rev 16931)
@@ -57,10 +57,13 @@
 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_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 */

Modified: trunk/blender/source/blender/include/BIF_editaction.h
===================================================================
--- trunk/blender/source/blender/include/BIF_editaction.h	2008-10-05 10:48:07 UTC (rev 16930)
+++ trunk/blender/source/blender/include/BIF_editaction.h	2008-10-05 11:49:09 UTC (rev 16931)
@@ -201,6 +201,10 @@
 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);
 

Modified: trunk/blender/source/blender/src/editaction_gpencil.c
===================================================================
--- trunk/blender/source/blender/src/editaction_gpencil.c	2008-10-05 10:48:07 UTC (rev 16930)
+++ trunk/blender/source/blender/src/editaction_gpencil.c	2008-10-05 11:49:09 UTC (rev 16931)
@@ -362,23 +362,225 @@
 		/* 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);
+					}
+					else {
+						// TODO: should remove this frame if it is new, as it doesn't have any strokes...
+						//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");
 }
 
 /* -------------------------------------- */

Modified: trunk/blender/source/blender/src/gpencil.c
===================================================================
--- trunk/blender/source/blender/src/gpencil.c	2008-10-05 10:48:07 UTC (rev 16930)
+++ trunk/blender/source/blender/src/gpencil.c	2008-10-05 11:49:09 UTC (rev 16931)
@@ -112,7 +112,7 @@
 		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 @@
 	}
 }
 
-/* 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 @@
 
 /* -------- Data Duplication ---------- */
 
+/* make a copy of a given gpencil frame */
+bGPDframe *gpencil_frame_duplicate (bGPDframe *src)
+{
+	bGPDstroke *gps, *gpsd;
+	bGPDframe *dst;
+	
+	/* error checking */

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list