diff options
author | Charlie Jolly <mistajolly@gmail.com> | 2019-09-06 16:07:26 +0300 |
---|---|---|
committer | Charlie Jolly <mistajolly@gmail.com> | 2019-09-06 16:07:26 +0300 |
commit | a94bf0e1349b4ee39e308a565fe26a4bd7cb7543 (patch) | |
tree | a96bfdc616edba9546ce6dc613228b4d4ea4ec07 | |
parent | 4c20c53b8980535fd0d62a5285a1e27bbe6e829d (diff) |
GPencil: Guides: Refactor and add new ISO option
+ Simplify code, move into own function and run once rather than on every point
+ Improved snapping when a stroke is between increments
+ Added ISO grid option for lines specified by Angle under guide settings
+ Radial snapping mode uses Angle as an offset
Differential Revision: https://developer.blender.org/D5668
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d.py | 4 | ||||
-rw-r--r-- | source/blender/editors/gpencil/gpencil_paint.c | 304 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_scene_types.h | 1 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_sculpt_paint.c | 1 |
4 files changed, 189 insertions, 121 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 89de137df76..a86d09c55e6 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -6077,7 +6077,7 @@ class VIEW3D_PT_gpencil_guide(Panel): col.active = settings.use_guide col.prop(settings, "type", expand=True) - if settings.type == 'PARALLEL': + if settings.type in {'ISO', 'PARALLEL', 'RADIAL'}: col.prop(settings, "angle") row = col.row(align=True) @@ -6089,7 +6089,7 @@ class VIEW3D_PT_gpencil_guide(Panel): else: col.prop(settings, "spacing") - if settings.type in {'CIRCULAR', 'RADIAL'}: + if settings.type in {'CIRCULAR', 'RADIAL'} or settings.use_snapping: col.label(text="Reference Point") row = col.row(align=True) row.prop(settings, "reference_point", expand=True) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 3217c94eebd..a585d3b71fc 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -113,6 +113,28 @@ typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_REQ_VECTOR = (1 << 6), } eGPencil_PaintFlags; +/* Temporary Guide data */ +typedef struct tGPguide { + /** guide spacing */ + float spacing; + /** half guide spacing */ + float half_spacing; + /** origin */ + float origin[2]; + /** rotated point */ + float rot_point[2]; + /** rotated point */ + float rot_angle; + /** initial stroke direction */ + float stroke_angle; + /** initial origin direction */ + float origin_angle; + /** initial origin distance */ + float origin_distance; + /** initial line for guides */ + float unit[2]; +} tGPguide; + /* Temporary 'Stroke' Operation data * "p" = op->customdata */ @@ -224,12 +246,7 @@ typedef struct tGPsdata { float totpixlen; /* guide */ - /** guide spacing */ - float guide_spacing; - /** half guide spacing */ - float half_spacing; - /** origin */ - float origin[2]; + tGPguide guide; ReportList *reports; } tGPsdata; @@ -2642,19 +2659,26 @@ static void gp_rotate_v2_v2v2fl(float v[2], static float gp_snap_to_grid_fl(float v, const float offset, const float spacing) { if (spacing > 0.0f) { - return roundf(v / spacing) * spacing + fmodf(offset, spacing); + v -= spacing * 0.5f; + v -= offset; + v = roundf((v + spacing * 0.5f) / spacing) * spacing; + v += offset; + return v; } else { return v; } } -static void UNUSED_FUNCTION(gp_snap_to_grid_v2)(float v[2], - const float offset[2], - const float spacing) +/* Helper to snap value to grid */ +static void gp_snap_to_rotated_grid_fl(float v[2], + const float origin[2], + const float spacing, + const float angle) { - v[0] = gp_snap_to_grid_fl(v[0], offset[0], spacing); - v[1] = gp_snap_to_grid_fl(v[1], offset[1], spacing); + gp_rotate_v2_v2v2fl(v, v, origin, -angle); + v[1] = gp_snap_to_grid_fl(v[1], origin[1], spacing); + gp_rotate_v2_v2v2fl(v, v, origin, angle); } /* get reference point - screen coords to buffer coords */ @@ -2692,6 +2716,105 @@ static void gp_origin_get(tGPsdata *p, float origin[2]) gp_point_3d_to_xy(gsc, p->gpd->runtime.sbuffer_sflag, location, origin); } +/* speed guide initial values */ +static void gpencil_speed_guide_init(tGPsdata *p, GP_Sculpt_Guide *guide) +{ + /* calculate initial guide values */ + RegionView3D *rv3d = p->ar->regiondata; + float scale = 1.0f; + if (rv3d->is_persp) { + float vec[3]; + gp_get_3d_reference(p, vec); + mul_m4_v3(rv3d->persmat, vec); + scale = vec[2] * rv3d->pixsize; + } + else { + scale = rv3d->pixsize; + } + p->guide.spacing = guide->spacing / scale; + p->guide.half_spacing = p->guide.spacing * 0.5f; + gp_origin_get(p, p->guide.origin); + + /* reference for angled snap */ + copy_v2_v2(p->guide.unit, p->mvali); + p->guide.unit[0] += 1.0f; + + float xy[2]; + sub_v2_v2v2(xy, p->mvali, p->guide.origin); + p->guide.origin_angle = atan2f(xy[1], xy[0]) + (M_PI * 2.0f); + + p->guide.origin_distance = len_v2v2(p->mvali, p->guide.origin); + if (guide->use_snapping && (guide->spacing > 0.0f)) { + p->guide.origin_distance = gp_snap_to_grid_fl( + p->guide.origin_distance, 0.0f, p->guide.spacing); + } + + if (ELEM(guide->type, GP_GUIDE_RADIAL)) { + float angle; + float half_angle = guide->angle_snap * 0.5f; + angle = p->guide.origin_angle + guide->angle; + angle = fmodf(angle + half_angle, guide->angle_snap); + angle -= half_angle; + gp_rotate_v2_v2v2fl(p->guide.rot_point, p->mvali, p->guide.origin, -angle ); + } + else { + gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, guide->angle); + } +} + +/* apply speed guide */ +static void gpencil_speed_guide(tGPsdata *p, GP_Sculpt_Guide *guide) +{ + switch (guide->type) { + default: + case GP_GUIDE_CIRCULAR: { + dist_ensure_v2_v2fl(p->mval, p->guide.origin, p->guide.origin_distance); + break; + } + case GP_GUIDE_RADIAL: { + if (guide->use_snapping && (guide->angle_snap > 0.0f)) { + closest_to_line_v2(p->mval, p->mval, p->guide.rot_point, p->guide.origin); + } + else { + closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.origin); + } + break; + } + case GP_GUIDE_PARALLEL: { + closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point); + if (guide->use_snapping && (guide->spacing > 0.0f)) { + gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, guide->angle); + } + break; + } + case GP_GUIDE_ISO: { + closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point); + if (guide->use_snapping && (guide->spacing > 0.0f)) { + gp_snap_to_rotated_grid_fl(p->mval, p->guide.origin, p->guide.spacing, p->guide.rot_angle); + } + break; + } + case GP_GUIDE_GRID: { + if (guide->use_snapping && (guide->spacing > 0.0f)) { + closest_to_line_v2(p->mval, p->mval, p->mvali, p->guide.rot_point); + if (p->straight == STROKE_HORIZONTAL) { + p->mval[1] = gp_snap_to_grid_fl(p->mval[1], p->guide.origin[1], p->guide.spacing); + } + else { + p->mval[0] = gp_snap_to_grid_fl(p->mval[0], p->guide.origin[0], p->guide.spacing); + } + } + else if (p->straight == STROKE_HORIZONTAL) { + p->mval[1] = p->mvali[1]; /* replace y */ + } + else { + p->mval[0] = p->mvali[0]; /* replace x */ + } + break; + } + } +} + /* handle draw event */ static void gpencil_draw_apply_event( bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) @@ -2726,6 +2849,10 @@ static void gpencil_draw_apply_event( p->straight = STROKE_VERTICAL; } } + /* reset if a stroke angle is required */ + if ((p->flags & GP_PAINTFLAG_REQ_VECTOR) && ((dx == 0) || (dy == 0))) { + p->straight = 0; + } } } @@ -2773,6 +2900,14 @@ static void gpencil_draw_apply_event( /* special exception for start of strokes (i.e. maybe for just a dot) */ if (p->flags & GP_PAINTFLAG_FIRSTRUN) { + + /* special exception here for too high pressure values on first touch in + * windows for some tablets, then we just skip first touch... + */ + if (tablet && (p->pressure >= 0.99f)) { + return; + } + p->flags &= ~GP_PAINTFLAG_FIRSTRUN; /* set values */ @@ -2784,51 +2919,58 @@ static void gpencil_draw_apply_event( /* save initial mouse */ copy_v2_v2(p->mvali, p->mval); - /* calculate once and store snapping distance and origin */ - RegionView3D *rv3d = p->ar->regiondata; - float scale = 1.0f; - if (rv3d->is_persp) { - float vec[3]; - gp_get_3d_reference(p, vec); - mul_m4_v3(rv3d->persmat, vec); - scale = vec[2] * rv3d->pixsize; - } - else { - scale = rv3d->pixsize; - } - p->guide_spacing = guide->spacing / scale; - p->half_spacing = p->guide_spacing * 0.5f; - gp_origin_get(p, p->origin); - - /* special exception here for too high pressure values on first touch in - * windows for some tablets, then we just skip first touch... - */ - if (tablet && (p->pressure >= 0.99f)) { - return; + if (is_speed_guide && !ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) && + ((guide->use_snapping && (guide->type == GP_GUIDE_GRID)) || + (guide->type == GP_GUIDE_ISO))) + { + p->flags |= GP_PAINTFLAG_REQ_VECTOR; } - /* special exception for grid snapping - * it requires direction which needs at least two points - */ - if (!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP) && is_speed_guide && - guide->use_snapping && (guide->type == GP_GUIDE_GRID)) { - p->flags |= GP_PAINTFLAG_REQ_VECTOR; + /* calculate initial guide values */ + if (is_speed_guide) { + gpencil_speed_guide_init(p, guide); } } /* wait for vector then add initial point */ - if (p->flags & GP_PAINTFLAG_REQ_VECTOR) { + if (is_speed_guide && p->flags & GP_PAINTFLAG_REQ_VECTOR) { if (p->straight == 0) { return; } p->flags &= ~GP_PAINTFLAG_REQ_VECTOR; + /* get initial point */ + float pt[2]; + sub_v2_v2v2(pt, p->mval, p->mvali); + + /* get stroke angle for grids */ + if (ELEM(guide->type, GP_GUIDE_ISO)) { + p->guide.stroke_angle = atan2f(pt[1], pt[0]); + /* determine iso angle, less weight is given for vertical strokes */ + if (((p->guide.stroke_angle >= 0.0f) && (p->guide.stroke_angle < DEG2RAD(75))) || + (p->guide.stroke_angle < DEG2RAD(-105))) { + p->guide.rot_angle = guide->angle; + } + else if (((p->guide.stroke_angle < 0.0f) && (p->guide.stroke_angle > DEG2RAD(-75))) || + (p->guide.stroke_angle > DEG2RAD(105))) { + p->guide.rot_angle = -guide->angle; + } + else { + p->guide.rot_angle = DEG2RAD(90); + } + gp_rotate_v2_v2v2fl(p->guide.rot_point, p->guide.unit, p->mvali, p->guide.rot_angle); + } + else if (ELEM(guide->type, GP_GUIDE_GRID)) { + gp_rotate_v2_v2v2fl(p->guide.rot_point, + p->guide.unit, + p->mvali, + (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f); + } + /* create fake events */ float tmp[2]; - float pt[2]; copy_v2_v2(tmp, p->mval); - sub_v2_v2v2(pt, p->mval, p->mvali); gpencil_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); if (len_v2v2(p->mval, p->mvalo)) { sub_v2_v2v2(pt, p->mval, p->mvalo); @@ -2841,83 +2983,7 @@ static void gpencil_draw_apply_event( if ((p->paintmode != GP_PAINTMODE_ERASER) && ((p->straight) || (is_speed_guide))) { /* guided stroke */ if (is_speed_guide) { - switch (guide->type) { - default: - case GP_GUIDE_CIRCULAR: { - float distance; - distance = len_v2v2(p->mvali, p->origin); - - if (guide->use_snapping && (guide->spacing > 0.0f)) { - distance = gp_snap_to_grid_fl(distance, 0.0f, p->guide_spacing); - } - - dist_ensure_v2_v2fl(p->mval, p->origin, distance); - break; - } - case GP_GUIDE_RADIAL: { - if (guide->use_snapping && (guide->angle_snap > 0.0f)) { - float point[2]; - float xy[2]; - float angle; - float half_angle = guide->angle_snap * 0.5f; - sub_v2_v2v2(xy, p->mvali, p->origin); - angle = atan2f(xy[1], xy[0]); - angle += (M_PI * 2.0f); - angle = fmodf(angle + half_angle, guide->angle_snap); - angle -= half_angle; - gp_rotate_v2_v2v2fl(point, p->mvali, p->origin, -angle); - closest_to_line_v2(p->mval, p->mval, point, p->origin); - } - else { - closest_to_line_v2(p->mval, p->mval, p->mvali, p->origin); - } - break; - } - case GP_GUIDE_PARALLEL: { - float point[2]; - float unit[2]; - copy_v2_v2(unit, p->mvali); - unit[0] += 1.0f; /* start from horizontal */ - gp_rotate_v2_v2v2fl(point, unit, p->mvali, guide->angle); - closest_to_line_v2(p->mval, p->mval, p->mvali, point); - - if (guide->use_snapping && (guide->spacing > 0.0f)) { - gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, -guide->angle); - p->mval[1] = gp_snap_to_grid_fl( - p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing); - gp_rotate_v2_v2v2fl(p->mval, p->mval, p->origin, guide->angle); - } - break; - } - case GP_GUIDE_GRID: { - if (guide->use_snapping && (guide->spacing > 0.0f)) { - float point[2]; - float unit[2]; - float angle; - copy_v2_v2(unit, p->mvali); - unit[0] += 1.0f; /* start from horizontal */ - angle = (p->straight == STROKE_VERTICAL) ? M_PI_2 : 0.0f; - gp_rotate_v2_v2v2fl(point, unit, p->mvali, angle); - closest_to_line_v2(p->mval, p->mval, p->mvali, point); - - if (p->straight == STROKE_HORIZONTAL) { - p->mval[1] = gp_snap_to_grid_fl( - p->mval[1] - p->half_spacing, p->origin[1], p->guide_spacing); - } - else { - p->mval[0] = gp_snap_to_grid_fl( - p->mval[0] - p->half_spacing, p->origin[0], p->guide_spacing); - } - } - else if (p->straight == STROKE_HORIZONTAL) { - p->mval[1] = p->mvali[1]; /* replace y */ - } - else { - p->mval[0] = p->mvali[0]; /* replace x */ - } - break; - } - } + gpencil_speed_guide(p, guide); } else if (p->straight == STROKE_HORIZONTAL) { p->mval[1] = p->mvali[1]; /* replace y */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 58778bebf4a..aed78fe1a38 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2326,6 +2326,7 @@ typedef enum eGPencil_GuideTypes { GP_GUIDE_RADIAL, GP_GUIDE_PARALLEL, GP_GUIDE_GRID, + GP_GUIDE_ISO, } eGPencil_GuideTypes; /* ToolSettings.gpencil_guide_references */ diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 2e3f41d656b..7ec666ada1c 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -1299,6 +1299,7 @@ static void rna_def_gpencil_guides(BlenderRNA *brna) {GP_GUIDE_RADIAL, "RADIAL", 0, "Radial", "Use single point as direction"}, {GP_GUIDE_PARALLEL, "PARALLEL", 0, "Parallel", "Parallel lines"}, {GP_GUIDE_GRID, "GRID", 0, "Grid", "Grid allows horizontal and vertical lines"}, + {GP_GUIDE_ISO, "ISO", 0, "Isometric", "Grid allows isometric and vertical lines"}, {0, NULL, 0, NULL, NULL}, }; |