== Grease Pencil - Conversions + Bugfixes ==
authorJoshua Leung <aligorith@gmail.com>
Wed, 27 Aug 2008 13:02:44 +0000 (13:02 +0000)
committerJoshua Leung <aligorith@gmail.com>
Wed, 27 Aug 2008 13:02:44 +0000 (13:02 +0000)
* New stuff: Grease Pencil strokes on the active layer can now be converted to 3d curves (geometry). More work is still needed to make the result look be more optimal (i.e. extruded curve)

* Bugfix: Spacing between collapsed layers is more compact now

source/blender/include/BDR_gpencil.h
source/blender/include/BSE_drawipo.h
source/blender/src/drawgpencil.c
source/blender/src/drawipo.c
source/blender/src/editobject.c
source/blender/src/gpencil.c

index 7340a2e44e0d43bf23790e4859727b41fb20efe6..9b9294b0343fab9c34db32b5cf04c0fe4661b7a7 100644 (file)
@@ -76,6 +76,9 @@ void gpencil_delete_laststroke(struct bGPdata *gpd);
 void gpencil_delete_operation(short mode);
 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);
 
index 932f103a579b755c7ac67e967bbd99030a2682c5..b8388b2172af960bb27f2a2cb47c78a457132d0e 100644 (file)
@@ -42,6 +42,7 @@ struct ScrArea;
 struct EditIpo;
 struct View2D;
 struct rctf;
+struct SpaceLink;
 
 void calc_ipogrid(void);
 void draw_ipogrid(void);
@@ -50,6 +51,8 @@ void areamouseco_to_ipoco     (struct View2D *v2d, short *mval, float *x, float *y);
 void ipoco_to_areaco           (struct View2D *v2d, float *vec, short *mval);
 void ipoco_to_areaco_noclip    (struct View2D *v2d, float *vec, short *mval);
 
+struct View2D *spacelink_get_view2d(struct SpaceLink *sl);
+
 void view2d_do_locks           (struct ScrArea *cursa, int flag);
 void view2d_zoom                       (struct View2D *v2d, float factor, int winx, int winy);
 void view2d_getscale           (struct View2D *v2d, float *x, float *y);
index dc9a880086fb518ab3e65206f07003a0a861f9fa..4b6b5ab26c8d757c5962c42625e8c6ddb16c5b3b 100644 (file)
@@ -177,7 +177,7 @@ static void gp_drawui_layer (uiBlock *block, bGPdata *gpd, bGPDlayer *gpl, short
        if (gpl->flag & (GP_LAYER_LOCKED|GP_LAYER_HIDE)) {
                char name[256]; /* gpl->info is 128, but we need space for 'locked/hidden' as well */
                
-               height= 26;
+               height= 0;
                
                /* visibility button (only if hidden but not locked!) */
                if ((gpl->flag & GP_LAYER_HIDE) && !(gpl->flag & GP_LAYER_LOCKED))
index 71854570c8c0c3ab325303e73de0d13ba8ba188b..9b5be04eac114d11da2ea3872e57be33b7ce2e62 100644 (file)
@@ -442,7 +442,7 @@ int in_ipo_buttons(void)
        else return 1;
 }
 
-static View2D *spacelink_get_view2d(SpaceLink *sl)
+View2D *spacelink_get_view2d(SpaceLink *sl)
 {
        if(sl->spacetype==SPACE_IPO) 
                return &((SpaceIpo *)sl)->v2d;
index fee967bcd9ad5faf45c85c1dc8807a75d15382f9..b1205668faae2badc18a645edeca5b50a4477d5e 100644 (file)
 #include "BDR_drawobject.h"
 #include "BDR_editcurve.h"
 #include "BDR_unwrapper.h"
+#include "BDR_gpencil.h"
 
 #include <time.h>
 #include "mydevice.h"
@@ -2827,7 +2828,10 @@ void convertmenu(void)
        if(G.scene->id.lib) return;
 
        obact= OBACT;
-       if(obact==0) return;
+       if(obact==0) {
+               gpencil_convert_menu();
+               return;
+       }
        if(!obact->flag & SELECT) return;
        if(G.obedit) return;
        
index 0b28e778f6272c12c6c839a96ea62113c6b07d8f..d1599d765b5216e95c9ac47bf4afd3de917655c1 100644 (file)
@@ -46,7 +46,9 @@
 #include "BLI_blenlib.h"
 
 #include "DNA_listBase.h"
+#include "DNA_curve_types.h"
 #include "DNA_gpencil_types.h"
+#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
@@ -57,6 +59,7 @@
 #include "BKE_global.h"
 #include "BKE_utildefines.h"
 #include "BKE_blender.h"
+#include "BKE_curve.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
@@ -74,6 +77,8 @@
 #include "BDR_gpencil.h"
 #include "BIF_drawgpencil.h"
 
+#include "BDR_editobject.h"
+
 #include "BSE_drawipo.h"
 #include "BSE_headerbuttons.h"
 #include "BSE_view.h"
@@ -678,6 +683,152 @@ void gpencil_delete_menu (void)
        gpencil_delete_operation(mode);
 }
 
+/* --------- Data Conversion ---------- */
+
+/* convert the coordinates from the given stroke point into 3d-coordinates */
+static void gp_strokepoint_convertcoords (bGPDstroke *gps, bGPDspoint *pt, float p3d[3])
+{
+       if (gps->flag & GP_STROKE_3DSPACE) {
+               /* directly use 3d-coordinates */
+               // FIXME: maybe we need to counterotate this for object rotation?
+               VecCopyf(p3d, &pt->x);
+       }
+       else {
+               short mval[2], mx, my;
+               float *fp= give_cursor();
+               float dvec[3];
+               
+               /* get screen coordinate */
+               if (gps->flag & GP_STROKE_2DSPACE) {
+                       View2D *v2d= spacelink_get_view2d(curarea->spacedata.first);
+                       ipoco_to_areaco_noclip(v2d, &pt->x, mval);
+               }
+               else {
+                       mval[0]= (pt->x / 1000 * curarea->winx);
+                       mval[1]= (pt->y / 1000 * curarea->winy);
+               }
+               mx= mval[0]; 
+               my= mval[1];
+               
+               /* convert screen coordinate to 3d coordinates 
+                *      - method taken from editview.c - mouse_cursor() 
+                */
+               project_short_noclip(fp, mval);
+               window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+               VecSubf(p3d, fp, dvec);
+       }
+}
+
+/* convert a given grease-pencil layer to a 3d-curve representation (using current view if appropriate) */
+static void gp_layer_to_curve (bGPdata *gpd, bGPDlayer *gpl)
+{
+       bGPDframe *gpf= gpencil_layer_getframe(gpl, CFRA, 0);
+       bGPDstroke *gps;
+       Object *ob;
+       Curve *cu;
+       float *fp= give_cursor();
+       char name[140];
+       
+       /* error checking */
+       if (ELEM3(NULL, gpd, gpl, gpf))
+               return;
+               
+       /* only convert if there are any strokes on this layer's frame to convert */
+       if (gpf->strokes.first == NULL)
+               return;
+               
+       /* initialise the curve */      
+       sprintf(name, "GP_%s", gpl->info);
+       cu= add_curve(name, 1);
+       cu->flag |= CU_3D;
+       
+       /* init the curve object (remove rotation and assign curve data to it) */
+       add_object_draw(OB_CURVE);
+       ob= OBACT;
+       ob->rot[0]= ob->rot[1]= ob->rot[2]= 0;
+       ob->data= cu;
+       
+       /* initialise 3d-cursor correction globals */
+       initgrabz(fp[0], fp[1], fp[2]);
+       
+       /* add points to curve */
+       for (gps= gpf->strokes.first; gps; gps= gps->next) {
+               bGPDspoint *pt;
+               Nurb *nu;
+               BPoint *bp;
+               int i;
+               
+               /* create new 'nurb' within the curve */
+               nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_curve(nurb)");
+               
+               nu->pntsu= gps->totpoints;
+               nu->pntsv= 1;
+               nu->orderu= gps->totpoints;
+               nu->flagu= 2;   /* endpoint */
+               nu->resolu= 32;
+               
+               nu->bp= MEM_callocN(sizeof(BPoint)*gps->totpoints, "bezts");
+               
+               /* add points */
+               for (i=0, pt=gps->points, bp=nu->bp; i < gps->totpoints; i++, pt++, bp++) {
+                       float p3d[3];
+                       
+                       /* get coordinates to add at */
+                       gp_strokepoint_convertcoords(gps, pt, p3d);
+                       VecCopyf(bp->vec, p3d);
+                       
+                       /* set settings */
+                       bp->f1= SELECT;
+                       bp->radius = bp->weight = pt->pressure * gpl->thickness;
+               }
+               
+               /* add nurb to curve */
+               BLI_addtail(&cu->nurb, nu);
+       }
+}
+
+/* convert grease-pencil strokes to another representation 
+ *     mode:   1 - Active layer to curve
+ */
+void gpencil_convert_operation (short mode)
+{
+       bGPdata *gpd;   
+       
+       /* get datablock to work on */
+       gpd= gpencil_data_getactive(NULL);
+       if (gpd == NULL) return;
+       
+       /* handle selection modes */
+       switch (mode) {
+               case 1: /* active layer only */
+               {
+                       bGPDlayer *gpl= gpencil_layer_getactive(gpd);
+                       gp_layer_to_curve(gpd, gpl);
+               }
+                       break;
+       }
+       
+       /* redraw and undo-push */
+       BIF_undo_push("GPencil Convert");
+       allqueue(REDRAWVIEW3D, 0);
+       allqueue(REDRAWOOPS, 0);
+}
+
+/* display a menu for converting grease-pencil strokes */
+void gpencil_convert_menu (void)
+{
+       bGPdata *gpd= gpencil_data_getactive(NULL);
+       short mode;
+       
+       /* only show menu if it will be relevant */
+       if (gpd == NULL) return;
+       
+       mode= pupmenu("Grease Pencil Convert %t|Active Layer To Curve%x1");
+       if (mode <= 0) return;
+       
+       gpencil_convert_operation(mode);
+}
+
 /* ************************************************** */
 /* GREASE-PENCIL EDITING MODE - Painting */
 
@@ -1113,12 +1264,11 @@ static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
 /* eraser tool - check if part of stroke occurs within last segment drawn by eraser */
 static short gp_stroke_eraser_strokeinside (short mval[], short mvalo[], short rad, short x0, short y0, short x1, short y1)
 {
-       /* step 1: check if within the radius for the new one */
-               /* simple within-radius check */
+       /* simple within-radius check for now */
        if (edge_inside_circle(mval[0], mval[1], rad, x0, y0, x1, y1))
                return 1;
        
-       /* step 2: check if within the quad formed between the two eraser coords */
+       /* not inside */
        return 0;
 } 
 
@@ -1203,7 +1353,6 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[],
                                /* check if point segment of stroke had anything to do with
                                 * eraser region  (either within stroke painted, or on its lines)
                                 *      - this assumes that linewidth is irrelevant
-                                *      - handled using the lasso-select checking code
                                 */
                                if (gp_stroke_eraser_strokeinside(mval, mvalo, rad, x0, y0, x1, y1)) {
                                        /* if function returns true, break this loop (as no more point to check) */
@@ -1288,6 +1437,12 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
                        case SPACE_SEQ:
                        {
                                /* for now, this is not applicable here... */
+                               //p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
+                       }
+                               break;
+                       case SPACE_IMAGE:
+                       {
+                               p->gpd->sbuffer_sflag |= GP_STROKE_2DIMAGE;
                        }
                                break;
                }
@@ -1298,10 +1453,7 @@ static void gp_paint_initstroke (tGPsdata *p, short paintmode)
 static void gp_paint_strokeend (tGPsdata *p)
 {
        /* check if doing eraser or not */
-       if (p->gpd->sbuffer_sflag & GP_STROKE_ERASER) {
-               /* don't do anything */
-       }
-       else {
+       if ((p->gpd->sbuffer_sflag & GP_STROKE_ERASER) == 0) {
                /* transfer stroke to frame */
                gp_stroke_newfrombuffer(p);
        }