diff options
author | Joshua Leung <aligorith@gmail.com> | 2008-08-25 10:22:21 +0400 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2008-08-25 10:22:21 +0400 |
commit | 1ed408e8c6f835571cbe8176b50500d146a143b2 (patch) | |
tree | 8ebe2f6c1d24dba1f5a51c3726fda4a15e38ed03 /source/blender | |
parent | 5e130558498d7001dc9d93731d1567ec56d253fb (diff) |
== Grease Pencil - Drawing + Eraser Improvements ==
Drawing Improvements:
* Single 'dots' now draw rounded
* Strokes being drawn are drawn 'solid' instead of as dotted lines
Eraser:
* Now operates interactively, so no more wait to see if stuff was erased
* An influence circle is now drawn - the radius of this is defined as the thickness^2
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/include/BIF_editview.h | 1 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_gpencil_types.h | 2 | ||||
-rw-r--r-- | source/blender/src/drawgpencil.c | 67 | ||||
-rw-r--r-- | source/blender/src/editview.c | 2 | ||||
-rw-r--r-- | source/blender/src/gpencil.c | 121 |
5 files changed, 107 insertions, 86 deletions
diff --git a/source/blender/include/BIF_editview.h b/source/blender/include/BIF_editview.h index d2c6c56d01a..204733a19d6 100644 --- a/source/blender/include/BIF_editview.h +++ b/source/blender/include/BIF_editview.h @@ -40,6 +40,7 @@ void arrows_move_cursor(unsigned short event); void lasso_select_boundbox(struct rcti *rect, short mcords[][2], short moves); int lasso_inside(short mcords[][2], short moves, short sx, short sy); int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1); +int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2); void borderselect(void); void circle_select(void); void deselectall(void); diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 13d412c2c42..cc0c9912057 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -61,7 +61,7 @@ typedef struct bGPDstroke { #define GP_STROKE_2DSPACE (1<<1) /* stroke is in 2d-space (but with special 'image' scaling) */ #define GP_STROKE_2DIMAGE (1<<2) - /* stroke is an "eraser" stroke */ + /* only for use with stroke-buffer (while drawing eraser) */ #define GP_STROKE_ERASER (1<<15) diff --git a/source/blender/src/drawgpencil.c b/source/blender/src/drawgpencil.c index f60d53a9c5d..dc9a880086f 100644 --- a/source/blender/src/drawgpencil.c +++ b/source/blender/src/drawgpencil.c @@ -323,6 +323,9 @@ enum { GP_DRAWDATA_ONLYI2D = (1<<3), /* only draw 'image' strokes */ }; +/* thickness above which we should use special drawing */ +#define GP_DRAWTHICKNESS_SPECIAL 3 + /* ----- Tool Buffer Drawing ------ */ /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ @@ -347,23 +350,13 @@ static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thick glEnd(); } else if (sflag & GP_STROKE_ERASER) { - /* draw stroke curve - just standard thickness */ - setlinestyle(4); - glLineWidth(1.0f); - - glBegin(GL_LINE_STRIP); - for (i=0, pt=points; i < totpoints && pt; i++, pt++) { - glVertex2f(pt->x, pt->y); - } - glEnd(); - - setlinestyle(0); + /* don't draw stroke at all! */ } else { float oldpressure = 0.0f; /* draw stroke curve */ - setlinestyle(2); + if (G.f & G_DEBUG) setlinestyle(2); glBegin(GL_LINE_STRIP); for (i=0, pt=points; i < totpoints && pt; i++, pt++) { @@ -381,14 +374,14 @@ static void gp_draw_stroke_buffer (tGPspoint *points, int totpoints, short thick } glEnd(); - setlinestyle(0); + if (G.f & G_DEBUG) setlinestyle(0); } } /* ----- Existing Strokes Drawing (3D and Point) ------ */ /* draw a given stroke - just a single dot (only one point) */ -static void gp_draw_stroke_point (bGPDspoint *points, short sflag, int winx, int winy) +static void gp_draw_stroke_point (bGPDspoint *points, short thickness, short sflag, int winx, int winy) { /* draw point */ if (sflag & GP_STROKE_3DSPACE) { @@ -396,18 +389,38 @@ static void gp_draw_stroke_point (bGPDspoint *points, short sflag, int winx, int glVertex3f(points->x, points->y, points->z); glEnd(); } - else if (sflag & GP_STROKE_2DSPACE) { - glBegin(GL_POINTS); - glVertex2f(points->x, points->y); - glEnd(); - } else { - const float x= (points->x / 1000 * winx); - const float y= (points->y / 1000 * winy); + float co[2]; - glBegin(GL_POINTS); - glVertex2f(x, y); - glEnd(); + /* get coordinates of point */ + if (sflag & GP_STROKE_2DSPACE) { + co[0]= points->x; + co[1]= points->y; + } + else { + co[0]= (points->x / 1000 * winx); + co[1]= (points->y / 1000 * winy); + } + + /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, simple opengl point will do */ + if (thickness < GP_DRAWTHICKNESS_SPECIAL) { + glBegin(GL_POINTS); + glVertex2fv(co); + glEnd(); + } + else { + /* draw filled circle as is done in circf (but without the matrix push/pops which screwed things up) */ + GLUquadricObj *qobj = gluNewQuadric(); + + gluQuadricDrawStyle(qobj, GLU_FILL); + + /* need to translate drawing position, but must reset after too! */ + glTranslatef(co[0], co[1], 0.); + gluDisk( qobj, 0.0, thickness, 32, 1); + glTranslatef(-co[0], -co[1], 0.); + + gluDeleteQuadric(qobj); + } } } @@ -449,8 +462,8 @@ static void gp_draw_stroke_3d (bGPDspoint *points, int totpoints, short thicknes /* draw a given stroke in 2d */ static void gp_draw_stroke (bGPDspoint *points, int totpoints, short thickness, short dflag, short sflag, short debug, int winx, int winy) { - /* if thickness is less than 3, 'smooth' opengl lines look better */ - if (thickness < 3) { + /* if thickness is less than GP_DRAWTHICKNESS_SPECIAL, 'smooth' opengl lines look better */ + if (thickness < GP_DRAWTHICKNESS_SPECIAL) { bGPDspoint *pt; int i; @@ -671,7 +684,7 @@ static void gp_draw_strokes (bGPDframe *gpf, int winx, int winy, int dflag, shor /* check which stroke-drawer to use */ if (gps->totpoints == 1) - gp_draw_stroke_point(gps->points, gps->flag, winx, winy); + gp_draw_stroke_point(gps->points, lthick, gps->flag, winx, winy); else if (dflag & GP_DRAWDATA_ONLY3D) gp_draw_stroke_3d(gps->points, gps->totpoints, lthick, dflag, gps->flag, debug, winx, winy); else if (gps->totpoints > 1) diff --git a/source/blender/src/editview.c b/source/blender/src/editview.c index a3fcad7885c..d2e59ae676d 100644 --- a/source/blender/src/editview.c +++ b/source/blender/src/editview.c @@ -1631,7 +1631,7 @@ void mouse_select(void) /* ------------------------------------------------------------------------- */ -static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2) +int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2) { int radsq= rad*rad; float v1[2], v2[2], v3[2]; diff --git a/source/blender/src/gpencil.c b/source/blender/src/gpencil.c index 9b250fc3ec0..2ea806cf0f9 100644 --- a/source/blender/src/gpencil.c +++ b/source/blender/src/gpencil.c @@ -707,6 +707,10 @@ typedef struct tGPsdata { short status; /* current status of painting */ short paintmode; /* mode for painting */ + + short mval[2]; /* current mouse-position */ + short mvalo[2]; /* previous recorded mouse-position */ + short radius; /* radius of influence for eraser */ } tGPsdata; /* values for tGPsdata->status */ @@ -1037,30 +1041,6 @@ static void gp_stroke_newfrombuffer (tGPsdata *p) } /* --- 'Eraser' for 'Paint' Tool ------ */ -/* User should draw 'circles' around the parts of the sketches they wish to - * delete instead of drawing squiggles over existing lines. This should be - * easier to manage than if it was done otherwise. - */ - -/* convert gp-buffer stroke into mouse-coordinates array */ -static short (*gp_stroke_eraser_2mco (bGPdata *gpd))[2] -{ - tGPspoint *pt; - short (*mcoords)[2]; - int i; - - /* allocate memory for coordinates array */ - mcoords= MEM_mallocN(sizeof(*mcoords)*gpd->sbuffer_size,"gp_buf_mcords"); - - /* copy coordinates */ - for (pt=gpd->sbuffer, i=0; i < gpd->sbuffer_size; i++, pt++) { - mcoords[i][0]= pt->x; - mcoords[i][1]= pt->y; - } - - /* return */ - return mcoords; -} /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */ static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i) @@ -1130,8 +1110,20 @@ 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 */ + 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 */ + return 0; +} + /* eraser tool - evaluation per stroke */ -static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, rcti *rect, bGPDframe *gpf, bGPDstroke *gps) +static void gp_stroke_eraser_dostroke (tGPsdata *p, short mval[], short mvalo[], short rad, rcti *rect, bGPDframe *gpf, bGPDstroke *gps) { bGPDspoint *pt1, *pt2; short x0=0, y0=0, x1=0, y1=0; @@ -1147,10 +1139,9 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo else if (gps->totpoints == 1) { /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - // FIXME: this may not be the correct correction project_short(&gps->points->x, xyval); x0= xyval[0]; - x1= xyval[1]; + y0= xyval[1]; } else if (gps->flag & GP_STROKE_2DSPACE) { ipoco_to_areaco_noclip(p->v2d, &gps->points->x, xyval); @@ -1165,7 +1156,7 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* do boundbox check first */ if (BLI_in_rcti(rect, x0, y0)) { /* only check if point is inside */ - if (lasso_inside(mcoords, moves, x0, y0)) { + if ( ((x0-mval[0])*(x0-mval[0]) + (y0-mval[1])*(y0-mval[1])) <= rad*rad ) { /* free stroke */ MEM_freeN(gps->points); BLI_freelinkN(&gpf->strokes, gps); @@ -1183,10 +1174,9 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* get coordinates */ if (gps->flag & GP_STROKE_3DSPACE) { - // FIXME: may not be correct correction project_short(&gps->points->x, xyval); x0= xyval[0]; - x1= xyval[1]; + y0= xyval[1]; } else if (gps->flag & GP_STROKE_2DSPACE) { ipoco_to_areaco_noclip(p->v2d, &pt1->x, xyval); @@ -1211,7 +1201,7 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo * - this assumes that linewidth is irrelevant * - handled using the lasso-select checking code */ - if (lasso_inside_edge(mcoords, moves, x0, y0, x1, x1)) { + 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) */ if (gp_stroke_eraser_splitdel(gpf, gps, i)) break; @@ -1226,24 +1216,21 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo /* erase strokes which fall under the eraser strokes */ static void gp_stroke_doeraser (tGPsdata *p) { - bGPdata *gpd= p->gpd; bGPDframe *gpf= p->gpf; bGPDstroke *gps, *gpn; - short (*mcoords)[2]; rcti rect; - /* get buffer-stroke coordinates as shorts array, and then get bounding box */ - mcoords= gp_stroke_eraser_2mco(gpd); - lasso_select_boundbox(&rect, mcoords, gpd->sbuffer_size); + /* rect is rectangle of eraser */ + rect.xmin= p->mval[0] - p->radius; + rect.ymin= p->mval[1] - p->radius; + rect.xmax= p->mval[0] + p->radius; + rect.ymax= p->mval[1] + p->radius; /* loop over strokes, checking segments for intersections */ for (gps= gpf->strokes.first; gps; gps= gpn) { gpn= gps->next; - gp_stroke_eraser_dostroke(p, mcoords, gpd->sbuffer_size, &rect, gpf, gps); + gp_stroke_eraser_dostroke(p, p->mval, p->mvalo, p->radius, &rect, gpf, gps); } - - /* free mcoords array */ - MEM_freeN(mcoords); } /* ---------- 'Paint' Tool ------------ */ @@ -1308,8 +1295,7 @@ static void gp_paint_strokeend (tGPsdata *p) { /* check if doing eraser or not */ if (p->gpd->sbuffer_sflag & GP_STROKE_ERASER) { - /* get rid of relevant sections of strokes */ - gp_stroke_doeraser(p); + /* don't do anything */ } else { /* transfer stroke to frame */ @@ -1345,7 +1331,6 @@ static void gp_paint_cleanup (tGPsdata *p) short gpencil_paint (short mousebutton, short paintmode) { tGPsdata p; - short prevmval[2], mval[2]; float opressure, pressure; short ok = GP_STROKEADD_NORMAL; @@ -1365,31 +1350,51 @@ short gpencil_paint (short mousebutton, short paintmode) setcursor_space(p.sa->spacetype, CURSOR_VPAINT); /* init drawing-device settings */ - getmouseco_areawin(mval); + getmouseco_areawin(p.mval); pressure = get_pressure(); - prevmval[0]= mval[0]; - prevmval[1]= mval[1]; + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; opressure= pressure; + /* radius for eraser circle is thickness^2 */ + p.radius= p.gpl->thickness * p.gpl->thickness; + + /* start drawing eraser-circle (if applicable) */ + if (paintmode == GP_PAINTMODE_ERASER) + draw_sel_circle(p.mval, NULL, p.radius, p.radius, 0); // draws frontbuffer, but sets backbuf again + /* only allow painting of single 'dots' if: * - pressure is not excessive (as it can be on some windows tablets) * - draw-mode for active datablock is turned on + * - not erasing */ - if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { - gp_stroke_addpoint(&p, mval, pressure); + if (paintmode != GP_PAINTMODE_ERASER) { + if (!(pressure >= 0.99f) || (p.gpd->flag & GP_DATA_EDITPAINT)) { + gp_stroke_addpoint(&p, p.mval, pressure); + } } /* paint loop */ do { /* get current user input */ - getmouseco_areawin(mval); + getmouseco_areawin(p.mval); pressure = get_pressure(); /* only add current point to buffer if mouse moved (otherwise wait until it does) */ - if (gp_stroke_filtermval(&p, mval, prevmval)) { + if (paintmode == GP_PAINTMODE_ERASER) { + /* do 'live' erasing now */ + gp_stroke_doeraser(&p); + + draw_sel_circle(p.mval, p.mvalo, p.radius, p.radius, 0); + force_draw(0); + + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; + } + else if (gp_stroke_filtermval(&p, p.mval, p.mvalo)) { /* try to add point */ - ok= gp_stroke_addpoint(&p, mval, pressure); + ok= gp_stroke_addpoint(&p, p.mval, pressure); /* handle errors while adding point */ if ((ok == GP_STROKEADD_FULL) || (ok == GP_STROKEADD_OVERFLOW)) { @@ -1397,8 +1402,8 @@ short gpencil_paint (short mousebutton, short paintmode) gp_paint_strokeend(&p); /* start a new stroke, starting from previous point */ - gp_stroke_addpoint(&p, prevmval, opressure); - ok= gp_stroke_addpoint(&p, mval, pressure); + gp_stroke_addpoint(&p, p.mvalo, opressure); + ok= gp_stroke_addpoint(&p, p.mval, pressure); } else if (ok == GP_STROKEADD_INVALID) { /* the painting operation cannot continue... */ @@ -1411,8 +1416,8 @@ short gpencil_paint (short mousebutton, short paintmode) } force_draw(0); - prevmval[0]= mval[0]; - prevmval[1]= mval[1]; + p.mvalo[0]= p.mval[0]; + p.mvalo[1]= p.mval[1]; opressure= pressure; } else @@ -1430,8 +1435,10 @@ short gpencil_paint (short mousebutton, short paintmode) setcursor_space(p.sa->spacetype, CURSOR_STD); /* check size of buffer before cleanup, to determine if anything happened here */ - if (paintmode == GP_PAINTMODE_ERASER) - ok= (p.gpd->sbuffer_size > 1); + if (paintmode == GP_PAINTMODE_ERASER) { + ok= 1; // fixme + draw_sel_circle(NULL, p.mvalo, 0, p.radius, 0); + } else ok= p.gpd->sbuffer_size; |