== Grease Pencil Eraser - Tweaks ==

Improved accuracy of the eraser a bit. Now it does a boundbox test first before trying to erase strokes, which means that other (rather unrelated) strokes are less likely to be affected as well.
This commit is contained in:
Joshua Leung 2008-07-31 12:23:29 +00:00
parent db82e15e6f
commit d66449996c
3 changed files with 97 additions and 78 deletions

@ -34,8 +34,10 @@ struct Base;
struct Object; struct Object;
struct Camera; struct Camera;
struct View3D; struct View3D;
struct rcti;
void arrows_move_cursor(unsigned short event); 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(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 lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1);
void borderselect(void); void borderselect(void);

@ -371,7 +371,7 @@ static void do_lasso_select_objects(short mcords[][2], short moves, short select
} }
} }
static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves) void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
{ {
short a; short a;

@ -48,6 +48,7 @@
#include "DNA_screen_types.h" #include "DNA_screen_types.h"
#include "DNA_space_types.h" #include "DNA_space_types.h"
#include "DNA_userdef_types.h" #include "DNA_userdef_types.h"
#include "DNA_vec_types.h"
#include "DNA_view3d_types.h" #include "DNA_view3d_types.h"
#include "BKE_global.h" #include "BKE_global.h"
@ -920,7 +921,6 @@ static short gp_stroke_addpoint (tGPsdata *p, short mval[2], float pressure)
if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX) if (gpd->sbuffer_size >= GP_STROKE_BUFFER_MAX)
return GP_STROKEADD_OVERFLOW; return GP_STROKEADD_OVERFLOW;
/* get pointer to destination point */ /* get pointer to destination point */
pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size); pt= ((tGPspoint *)(gpd->sbuffer) + gpd->sbuffer_size);
@ -1012,8 +1012,76 @@ static short (*gp_stroke_eraser_2mco (bGPdata *gpd))[2]
return mcoords; return mcoords;
} }
/* eraser tool evaluation per curve */ /* eraser tool - remove segment from stroke/split stroke (after lasso inside) */
static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, bGPDframe *gpf, bGPDstroke *gps) static short gp_stroke_eraser_splitdel (bGPDframe *gpf, bGPDstroke *gps, int i)
{
bGPDspoint *pt_tmp= gps->points;
bGPDstroke *gsn = NULL;
/* if stroke only had two points, get rid of stroke */
if (gps->totpoints == 2) {
/* free stroke points, then stroke */
MEM_freeN(pt_tmp);
BLI_freelinkN(&gpf->strokes, gps);
/* nothing left in stroke, so stop */
return 1;
}
/* if last segment, just remove segment from the stroke */
else if (i == gps->totpoints - 2) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* nothing left in stroke, so stop */
return 1;
}
/* if first segment, just remove segment from the stroke */
else if (i == 0) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* no break here, as there might still be stuff to remove in this stroke */
return 0;
}
/* segment occurs in 'middle' of stroke, so split */
else {
/* duplicate stroke, and assign 'later' data to that stroke */
gsn= MEM_dupallocN(gps);
gsn->prev= gsn->next= NULL;
BLI_insertlinkafter(&gpf->strokes, gps, gsn);
gsn->totpoints= gps->totpoints - i;
gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
/* adjust existing stroke */
gps->totpoints= i;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* nothing left in stroke, so stop */
return 1;
}
}
/* eraser tool - evaluation per stroke */
static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short moves, rcti *rect, bGPDframe *gpf, bGPDstroke *gps)
{ {
bGPDspoint *pt1, *pt2; bGPDspoint *pt1, *pt2;
short x0=0, y0=0, x1=0, y1=0; short x0=0, y0=0, x1=0, y1=0;
@ -1044,11 +1112,14 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo
y0= (gps->points->y / 1000 * p->sa->winy); y0= (gps->points->y / 1000 * p->sa->winy);
} }
/* only check if point is inside */ /* do boundbox check first */
if (lasso_inside(mcoords, moves, x0, y0)) { if (BLI_in_rcti(rect, x0, y0)) {
/* free stroke */ /* only check if point is inside */
MEM_freeN(gps->points); if (lasso_inside(mcoords, moves, x0, y0)) {
BLI_freelinkN(&gpf->strokes, gps); /* free stroke */
MEM_freeN(gps->points);
BLI_freelinkN(&gpf->strokes, gps);
}
} }
} }
else { else {
@ -1083,73 +1154,17 @@ static void gp_stroke_eraser_dostroke (tGPsdata *p, short mcoords[][2], short mo
y1= (pt2->y / 1000 * p->sa->winy); y1= (pt2->y / 1000 * p->sa->winy);
} }
/* check if point segment of stroke had anything to do with /* check that point segment of the boundbox of the eraser stroke */
* eraser region (either within stroke painted, or on its lines) if (BLI_in_rcti(rect, x0, y0) || BLI_in_rcti(rect, x1, y1)) {
* - this assumes that linewidth is irrelevant /* check if point segment of stroke had anything to do with
* - handled using the lasso-select checking code * eraser region (either within stroke painted, or on its lines)
*/ * - this assumes that linewidth is irrelevant
if (lasso_inside_edge(mcoords, moves, x0, y0, x1, x1)) { * - handled using the lasso-select checking code
bGPDspoint *pt_tmp= gps->points; */
bGPDstroke *gsn = NULL; if (lasso_inside_edge(mcoords, moves, x0, y0, x1, x1)) {
/* if function returns true, break this loop (as no more point to check) */
/* if stroke only had two points, get rid of stroke */ if (gp_stroke_eraser_splitdel(gpf, gps, i))
if (gps->totpoints == 2) { break;
/* free stroke points, then stroke */
MEM_freeN(pt_tmp);
BLI_freelinkN(&gpf->strokes, gps);
/* nothing left in stroke, so stop */
break;
}
/* if last segment, just remove segment from the stroke */
else if (i == gps->totpoints - 2) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*gps->totpoints);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* nothing left in stroke, so stop */
break;
}
/* if first segment, just remove segment from the stroke */
else if (i == 0) {
/* allocate new points array, and assign most of the old stroke there */
gps->totpoints--;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp + 1, sizeof(bGPDspoint)*gps->totpoints);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* no break here, as there might still be stuff to remove in this stroke */
}
/* segment occurs in 'middle' of stroke, so split */
else {
/* duplicate stroke, and assign 'later' data to that stroke */
gsn= MEM_dupallocN(gps);
gsn->prev= gsn->next= NULL;
BLI_insertlinkafter(&gpf->strokes, gps, gsn);
gsn->totpoints= gps->totpoints - i;
gsn->points= MEM_callocN(sizeof(bGPDspoint)*gsn->totpoints, "gp_stroke_points");
memcpy(gsn->points, pt_tmp + i, sizeof(bGPDspoint)*gsn->totpoints);
/* adjust existing stroke */
gps->totpoints= i;
gps->points= MEM_callocN(sizeof(bGPDspoint)*gps->totpoints, "gp_stroke_points");
memcpy(gps->points, pt_tmp, sizeof(bGPDspoint)*i);
/* free temp buffer */
MEM_freeN(pt_tmp);
/* nothing left in stroke, so stop */
break;
} }
} }
} }
@ -1165,14 +1180,16 @@ static void gp_stroke_doeraser (tGPsdata *p)
bGPDframe *gpf= p->gpf; bGPDframe *gpf= p->gpf;
bGPDstroke *gps, *gpn; bGPDstroke *gps, *gpn;
short (*mcoords)[2]; short (*mcoords)[2];
rcti rect;
/* get buffer-stroke coordinates as shorts array */ /* get buffer-stroke coordinates as shorts array, and then get bounding box */
mcoords= gp_stroke_eraser_2mco(gpd); mcoords= gp_stroke_eraser_2mco(gpd);
lasso_select_boundbox(&rect, mcoords, gpd->sbuffer_size);
/* loop over strokes, checking segments for intersections */ /* loop over strokes, checking segments for intersections */
for (gps= gpf->strokes.first; gps; gps= gpn) { for (gps= gpf->strokes.first; gps; gps= gpn) {
gpn= gps->next; gpn= gps->next;
gp_stroke_eraser_dostroke(p, mcoords, gpd->sbuffer_size, gpf, gps); gp_stroke_eraser_dostroke(p, mcoords, gpd->sbuffer_size, &rect, gpf, gps);
} }
/* free mcoords array */ /* free mcoords array */