diff --git a/source/blender/include/BDR_gpencil.h b/source/blender/include/BDR_gpencil.h index 7340a2e44e0..9b9294b0343 100644 --- a/source/blender/include/BDR_gpencil.h +++ b/source/blender/include/BDR_gpencil.h @@ -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); diff --git a/source/blender/include/BSE_drawipo.h b/source/blender/include/BSE_drawipo.h index 932f103a579..b8388b2172a 100644 --- a/source/blender/include/BSE_drawipo.h +++ b/source/blender/include/BSE_drawipo.h @@ -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); diff --git a/source/blender/src/drawgpencil.c b/source/blender/src/drawgpencil.c index dc9a880086f..4b6b5ab26c8 100644 --- a/source/blender/src/drawgpencil.c +++ b/source/blender/src/drawgpencil.c @@ -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)) diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c index 71854570c8c..9b5be04eac1 100644 --- a/source/blender/src/drawipo.c +++ b/source/blender/src/drawipo.c @@ -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; diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c index fee967bcd9a..b1205668faa 100644 --- a/source/blender/src/editobject.c +++ b/source/blender/src/editobject.c @@ -172,6 +172,7 @@ #include "BDR_drawobject.h" #include "BDR_editcurve.h" #include "BDR_unwrapper.h" +#include "BDR_gpencil.h" #include #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; diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c index 0b28e778f62..d1599d765b5 100644 --- a/source/blender/src/gpencil.c +++ b/source/blender/src/gpencil.c @@ -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); }