From 6577618d5bb93792c805e0c22e4de1a015ee25d5 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Sun, 17 Mar 2019 19:47:31 +0100 Subject: [PATCH] GPencil: Changes in Fill and new 3D Cursor View Plane This commit groups several options that were tested in grease pencil branch: - Changes to fill algorithms and improves, specially in small areas and stroke corners. New options has been added in order to define how the fill is working and internally there are optimizations in detect the small areas in the extremes. Kudos to @charlie for coding this fill improvements. - New 3D cursor view plane option. Now it's possible to lock the drawing plane to the 3D cursor and use the 3D cursor orientation. This allows more flexibility when you are drawing and reduce the need to create geometry to draw over surfaces. - Canvas Grid now can be locked to 3D cursor. - New option to reproject stroke using 3D cursor. - Small tweaks and fixes. Changes reviewed by @pepeland and @mendio --- .../startup/bl_ui/properties_paint_common.py | 25 +- release/scripts/startup/bl_ui/space_topbar.py | 32 +++ source/blender/blenkernel/intern/brush.c | 1 + .../engines/gpencil/gpencil_draw_cache_impl.c | 4 +- .../draw/engines/gpencil/gpencil_draw_utils.c | 4 +- .../draw/engines/gpencil/gpencil_engine.c | 38 ++- source/blender/editors/gpencil/drawgpencil.c | 24 +- .../blender/editors/gpencil/gpencil_brush.c | 56 +++- source/blender/editors/gpencil/gpencil_edit.c | 28 +- source/blender/editors/gpencil/gpencil_fill.c | 257 ++++++++++++++---- .../blender/editors/gpencil/gpencil_intern.h | 1 + .../blender/editors/gpencil/gpencil_paint.c | 8 +- .../editors/gpencil/gpencil_primitive.c | 9 +- .../blender/editors/gpencil/gpencil_utils.c | 67 ++++- source/blender/editors/include/ED_gpencil.h | 2 + .../gpu_shader_gpencil_stroke_geom.glsl | 30 +- .../gpu_shader_gpencil_stroke_vert.glsl | 2 +- source/blender/makesdna/DNA_brush_types.h | 16 +- source/blender/makesdna/DNA_scene_types.h | 1 + source/blender/makesrna/intern/rna_brush.c | 15 +- .../makesrna/intern/rna_sculpt_paint.c | 1 + 21 files changed, 485 insertions(+), 136 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 1a1f0fa3fb7..ac63948d18a 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -393,7 +393,7 @@ def brush_basic_sculpt_settings(layout, context, brush, *, compact=False): layout.row().prop(brush, "direction", expand=True, **({"text": ""} if compact else {})) -def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False): +def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=True): gp_settings = brush.gpencil_settings # Brush details @@ -412,24 +412,15 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False) row = layout.row(align=True) row.prop(gp_settings, "eraser_thickness_factor") elif brush.gpencil_tool == 'FILL': - row = layout.column(align=True) - row.prop(gp_settings, "fill_leak", text="Leak Size") - row.separator() - row = layout.column(align=True) - row.prop(brush, "size", text="Thickness") - row = layout.column(align=True) - row.prop(gp_settings, "fill_simplify_level", text="Simplify") - row = layout.row(align=True) - row.prop(gp_settings, "fill_draw_mode", text="Boundary Draw Mode") + row.prop(gp_settings, "fill_leak", text="Leak Size") + row = layout.row(align=True) + row.prop(brush, "size", text="Thickness") + row = layout.row(align=True) + row.prop(gp_settings, "fill_simplify_level", text="Simplify") + row = layout.row(align=True) + row.prop(gp_settings, "fill_draw_mode", text="Boundary") row.prop(gp_settings, "show_fill_boundary", text="", icon='GRID') - - row = layout.column(align=True) - row.enabled = gp_settings.fill_draw_mode != 'STROKE' - row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes") - sub = layout.row(align=True) - sub.enabled = not gp_settings.show_fill - sub.prop(gp_settings, "fill_threshold", text="Threshold") else: # brush.gpencil_tool == 'DRAW': row = layout.row(align=True) row.prop(brush, "size", text="Radius") diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 4cda2678e33..73aa59a2693 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -362,6 +362,15 @@ class _draw_left_context_mode: panel="TOPBAR_PT_gpencil_primitive", text="Thickness Profile" ) + + if brush.gpencil_tool == 'FILL': + settings = context.tool_settings.gpencil_sculpt + row = layout.row(align=True) + sub = row.row(align=True) + sub.popover( + panel="TOPBAR_PT_gpencil_fill", + text="Fill Options" + ) @staticmethod def SCULPT_GPENCIL(context, layout, tool): @@ -1036,6 +1045,28 @@ class TOPBAR_PT_gpencil_primitive(Panel): # Curve layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True) +# Grease Pencil Fill +class TOPBAR_PT_gpencil_fill(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Advanced" + + @staticmethod + def draw(self, context): + paint = context.tool_settings.gpencil_paint + brush = paint.brush + gp_settings = brush.gpencil_settings + + layout = self.layout + # Fill + row = layout.row(align=True) + row.prop(gp_settings, "fill_factor", text="Resolution") + if gp_settings.fill_draw_mode != 'STROKE': + row = layout.row(align=True) + row.prop(gp_settings, "show_fill", text="Ignore Transparent Strokes") + row = layout.row(align=True) + row.prop(gp_settings, "fill_threshold", text="Threshold") + classes = ( TOPBAR_HT_upper_bar, @@ -1058,6 +1089,7 @@ classes = ( TOPBAR_PT_active_tool, TOPBAR_PT_gpencil_layers, TOPBAR_PT_gpencil_primitive, + TOPBAR_PT_gpencil_fill, ) if __name__ == "__main__": # only for live edit. diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 2e68c88c5f7..c959504f84f 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -480,6 +480,7 @@ void BKE_brush_gpencil_presets(bContext *C) brush->gpencil_settings->fill_leak = 3; brush->gpencil_settings->fill_threshold = 0.1f; brush->gpencil_settings->fill_simplylvl = 1; + brush->gpencil_settings->fill_factor = 1; brush->gpencil_settings->icon_id = GP_BRUSH_ICON_FILL; brush->gpencil_tool = GPAINT_TOOL_FILL; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c index 1f3874e70ba..b72a6ebebbd 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c @@ -270,7 +270,7 @@ GPUBatch *DRW_gpencil_get_buffer_stroke_geom(bGPdata *gpd, short thickness) for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); - ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); + ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); /* first point for adjacency (not drawn) */ if (i == 0) { @@ -361,7 +361,7 @@ GPUBatch *DRW_gpencil_get_buffer_point_geom(bGPdata *gpd, short thickness) for (int i = 0; i < totpoints; i++, tpt++) { ED_gpencil_tpoint_to_point(ar, origin, tpt, &pt); - ED_gp_project_point_to_plane(ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); + ED_gp_project_point_to_plane(scene, ob, rv3d, origin, ts->gp_sculpt.lock_axis - 1, &pt); /* set point */ gpencil_set_stroke_point( diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index a50b4fac15c..2710ecc5e5b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -506,7 +506,7 @@ DRWShadingGroup *DRW_gpencil_shgroup_stroke_create( DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); /* avoid wrong values */ - if ((gpd) && (gpd->pixfactor == 0)) { + if ((gpd) && (gpd->pixfactor == 0.0f)) { gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; } @@ -627,7 +627,7 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create( DRW_shgroup_uniform_float(grp, "pixsize", stl->storage->pixsize, 1); /* avoid wrong values */ - if ((gpd) && (gpd->pixfactor == 0)) { + if ((gpd) && (gpd->pixfactor == 0.0f)) { gpd->pixfactor = GP_DEFAULT_PIX_FACTOR; } diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 5f2652b0bfb..7fbae5e98ea 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -582,6 +582,7 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; View3D *v3d = draw_ctx->v3d; + const View3DCursor *cursor = &scene->cursor; if (ob->type == OB_GPENCIL && ob->data) { bGPdata *gpd = (bGPdata *)ob->data; @@ -626,7 +627,9 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) if ((v3d) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->gp_flag & V3D_GP_SHOW_GRID) && - (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact)) + (ob->type == OB_GPENCIL) && (ob == draw_ctx->obact) && + ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0) && + ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) == 0)) { GPU_BATCH_DISCARD_SAFE(e_data.batch_grid); MEM_SAFE_FREE(e_data.batch_grid); @@ -634,13 +637,36 @@ void GPENCIL_cache_populate(void *vedata, Object *ob) e_data.batch_grid = DRW_gpencil_get_grid(ob); /* define grid orientation */ - if (ts->gp_sculpt.lock_axis != GP_LOCKAXIS_VIEW) { - copy_m4_m4(stl->storage->grid_matrix, ob->obmat); + switch (ts->gp_sculpt.lock_axis) { + case GP_LOCKAXIS_VIEW: + { + /* align always to view */ + invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat); + /* copy ob location */ + copy_v3_v3(stl->storage->grid_matrix[3], ob->obmat[3]); + break; + } + case GP_LOCKAXIS_CURSOR: + { + float scale[3] = { 1.0f, 1.0f, 1.0f }; + loc_eul_size_to_mat4(stl->storage->grid_matrix, + cursor->location, + cursor->rotation_euler, + scale); + break; + } + default: + { + copy_m4_m4(stl->storage->grid_matrix, ob->obmat); + break; + } + } + + /* Move the origin to Object or Cursor */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(stl->storage->grid_matrix[3], cursor->location); } else { - /* align always to view */ - invert_m4_m4(stl->storage->grid_matrix, draw_ctx->rv3d->viewmat); - /* copy ob location */ copy_v3_v3(stl->storage->grid_matrix[3], ob->obmat[3]); } diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 1ae3176d393..ebe0fa61b21 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -720,9 +720,12 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 immUniform1f("objscale", obj_scale); int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); immUniform1i("keep_size", keep_size); - immUniform1i("pixfactor", tgpw->gpd->pixfactor); + immUniform1f("pixfactor", tgpw->gpd->pixfactor); /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */ immUniform1i("xraymode", GP_XRAY_3DSPACE); + immUniform1i("caps_start", (int)tgpw->gps->caps[0]); + immUniform1i("caps_end", (int)tgpw->gps->caps[1]); + immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke); /* draw stroke curve */ GPU_line_width(max_ff(curpressure * thickness, 1.0f)); @@ -733,23 +736,22 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 /* first point for adjacency (not drawn) */ if (i == 0) { gp_set_point_varying_color(points, ink, attr_id.color); - immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f)); + if ((cyclic) && (totpoints > 2)) { + immAttr1f(attr_id.thickness, max_ff((points + totpoints - 1)->pressure * thickness, 1.0f)); mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 1)->x); } else { + immAttr1f(attr_id.thickness, max_ff((points + 1)->pressure * thickness, 1.0f)); mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + 1)->x); } - mul_v3_fl(fpt, -1.0f); immVertex3fv(attr_id.pos, fpt); } /* set point */ gp_set_point_varying_color(pt, ink, attr_id.color); - immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f)); + immAttr1f(attr_id.thickness, max_ff(pt->pressure * thickness, 1.0f)); mul_v3_m4v3(fpt, tgpw->diff_mat, &pt->x); immVertex3fv(attr_id.pos, fpt); - - curpressure = pt->pressure; } if (cyclic && totpoints > 2) { @@ -765,10 +767,9 @@ static void gp_draw_stroke_3d(tGPDdraw *tgpw, short thickness, const float ink[4 } /* last adjacency point (not drawn) */ else { - gp_set_point_varying_color(points + totpoints - 1, ink, attr_id.color); - immAttr1f(attr_id.thickness, max_ff(curpressure * thickness, 1.0f)); + gp_set_point_varying_color(points + totpoints - 2, ink, attr_id.color); + immAttr1f(attr_id.thickness, max_ff((points + totpoints - 2)->pressure * thickness, 1.0f)); mul_v3_m4v3(fpt, tgpw->diff_mat, &(points + totpoints - 2)->x); - mul_v3_fl(fpt, -1.0f); immVertex3fv(attr_id.pos, fpt); } @@ -1029,6 +1030,10 @@ static void gp_draw_strokes(tGPDdraw *tgpw) /* calculate thickness */ sthickness = gps->thickness + tgpw->lthick; + if (tgpw->is_fill_stroke) { + sthickness = (short)max_ii(1, sthickness / 2); + } + if (sthickness <= 0) { continue; } @@ -1427,6 +1432,7 @@ static void gp_draw_data_layers(RegionView3D *rv3d, tgpw.winx = winx; tgpw.winy = winy; tgpw.dflag = dflag; + tgpw.is_fill_stroke = false; for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* calculate parent position */ diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 0403a42a2c9..2df0edd3bf7 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -176,18 +176,54 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, c return; } - ToolSettings *ts = gso->scene->toolsettings; - int axis = ts->gp_sculpt.lock_axis; + const ToolSettings *ts = gso->scene->toolsettings; + const View3DCursor *cursor = &gso->scene->cursor; + const int axis = ts->gp_sculpt.lock_axis; /* lock axis control */ - if (axis == 1) { - pt->x = save_pt[0]; - } - if (axis == 2) { - pt->y = save_pt[1]; - } - if (axis == 3) { - pt->z = save_pt[2]; + switch (axis) { + case GP_LOCKAXIS_X: + { + pt->x = save_pt[0]; + break; + } + case GP_LOCKAXIS_Y: + { + pt->y = save_pt[1]; + break; + } + case GP_LOCKAXIS_Z: + { + pt->z = save_pt[2]; + break; + } + case GP_LOCKAXIS_CURSOR: + { + /* compute a plane with cursor normal and position of the point + before do the sculpt */ + const float scale[3] = { 1.0f, 1.0f, 1.0f }; + float plane_normal[3] = { 0.0f, 0.0f, 1.0f }; + float plane[4]; + float mat[4][4]; + float r_close[3]; + + loc_eul_size_to_mat4(mat, + cursor->location, + cursor->rotation_euler, + scale); + + mul_mat3_m4_v3(mat, plane_normal); + plane_from_point_normal_v3(plane, save_pt, plane_normal); + + /* find closest point to the plane with the new position */ + closest_to_plane_v3(r_close, plane, &pt->x); + copy_v3_v3(&pt->x, r_close); + break; + } + default: + { + break; + } } } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 1388beb0b20..f14ba3b4f27 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3280,6 +3280,8 @@ typedef enum eGP_ReprojectModes { GP_REPROJECT_VIEW, /* Reprojected on to the scene geometry */ GP_REPROJECT_SURFACE, + /* Reprojected on 3D cursor orientation */ + GP_REPROJECT_CURSOR, } eGP_ReprojectModes; static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) @@ -3334,10 +3336,17 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]); /* Project stroke in one axis */ - if (ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, GP_REPROJECT_TOP)) { - ED_gp_get_drawing_reference( - scene, ob, gpl, - ts->gpencil_v3d_align, origin); + if (ELEM(mode, GP_REPROJECT_FRONT, GP_REPROJECT_SIDE, + GP_REPROJECT_TOP, GP_REPROJECT_CURSOR)) + { + if (mode != GP_REPROJECT_CURSOR) { + ED_gp_get_drawing_reference( + scene, ob, gpl, + ts->gpencil_v3d_align, origin); + } + else { + copy_v3_v3(origin, scene->cursor.location); + } int axis = 0; switch (mode) { @@ -3356,6 +3365,11 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) axis = 2; break; } + case GP_REPROJECT_CURSOR: + { + axis = 3; + break; + } default: { axis = 1; @@ -3364,8 +3378,8 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) } ED_gp_project_point_to_plane( - ob, rv3d, origin, - axis, &pt2); + scene, ob, rv3d, origin, + axis, &pt2); copy_v3_v3(&pt->x, &pt2.x); @@ -3427,6 +3441,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) "using 'Cursor' Stroke Placement"}, {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface", "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"}, + {GP_REPROJECT_CURSOR, "CURSOR", 0, "Cursor", + "Reproject the strokes using the orienation of 3D cursor"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 7668b7cf5fd..36202bdac0a 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -132,6 +132,8 @@ typedef struct tGPDfill { int fill_simplylvl; /** boundary limits drawing mode */ int fill_draw_mode; + /* scaling factor */ + short fill_factor; /** number of elements currently in cache */ short sbuffer_size; @@ -146,6 +148,13 @@ typedef struct tGPDfill { BLI_Stack *stack; /** handle for drawing strokes while operator is running 3d stuff */ void *draw_handle_3d; + + /* tmp size x */ + int bwinx; + /* tmp size y */ + int bwiny; + rcti brect; + } tGPDfill; @@ -231,6 +240,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.dflag = 0; tgpw.disable_fill = 1; tgpw.dflag |= (GP_DRAWFILLS_ONLY3D | GP_DRAWFILLS_NOSTATUS); + glEnable(GL_BLEND); @@ -271,23 +281,27 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.t_gpf = gpf; /* reduce thickness to avoid gaps */ - tgpw.lthick = gpl->line_change - 4; + tgpw.is_fill_stroke = (tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) ? false : true ; + tgpw.lthick = gpl->line_change; tgpw.opacity = 1.0; copy_v4_v4(tgpw.tintcolor, ink); tgpw.onion = true; tgpw.custonion = true; + bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE); + /* normal strokes */ - if ((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || - (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) && + !textured_stroke) { ED_gp_draw_fill(&tgpw); - } /* 3D Lines with basic shapes and invisible lines */ if ((tgpf->fill_draw_mode == GP_FILL_DMODE_CONTROL) || - (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH)) + (tgpf->fill_draw_mode == GP_FILL_DMODE_BOTH) || + textured_stroke) { gp_draw_basic_stroke( tgpf, gps, tgpw.diff_mat, gps->flag & GP_STROKE_CYCLIC, ink, @@ -300,17 +314,45 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) } /* draw strokes in offscreen buffer */ -static void gp_render_offscreen(tGPDfill *tgpf) +static bool gp_render_offscreen(tGPDfill *tgpf) { bool is_ortho = false; float winmat[4][4]; if (!tgpf->gpd) { - return; + return false; } + + /* set temporary new size */ + tgpf->bwinx = tgpf->ar->winx; + tgpf->bwiny = tgpf->ar->winy; + tgpf->brect = tgpf->ar->winrct; + + /* resize ar */ + tgpf->ar->winrct.xmin = 0; + tgpf->ar->winrct.ymin = 0; + tgpf->ar->winrct.xmax = (int)tgpf->ar->winx * tgpf->fill_factor; + tgpf->ar->winrct.ymax = (int)tgpf->ar->winy * tgpf->fill_factor; + tgpf->ar->winx = (short)abs(tgpf->ar->winrct.xmax - tgpf->ar->winrct.xmin); + tgpf->ar->winy = (short)abs(tgpf->ar->winrct.ymax - tgpf->ar->winrct.ymin); + + /* save new size */ + tgpf->sizex = (int)tgpf->ar->winx; + tgpf->sizey = (int)tgpf->ar->winy; + + /* adjust center */ + float center[2]; + center[0] = (float)tgpf->center[0] * ((float)tgpf->ar->winx / (float)tgpf->bwinx); + center[1] = (float)tgpf->center[1] * ((float)tgpf->ar->winy / (float)tgpf->bwiny); + round_v2i_v2fl(tgpf->center, center); char err_out[256] = "unknown"; GPUOffScreen *offscreen = GPU_offscreen_create(tgpf->sizex, tgpf->sizey, 0, true, false, err_out); + if (offscreen == NULL) { + printf("GPencil - Fill - Unable to create fill buffer\n"); + return false; + } + GPU_offscreen_bind(offscreen, true); uint flag = IB_rect | IB_rectfloat; ImBuf *ibuf = IMB_allocImBuf(tgpf->sizex, tgpf->sizey, 32, flag); @@ -328,18 +370,6 @@ static void gp_render_offscreen(tGPDfill *tgpf) perspective_m4(winmat, viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clip_start, clip_end); } - /* set temporary new size */ - int bwinx = tgpf->ar->winx; - int bwiny = tgpf->ar->winy; - rcti brect = tgpf->ar->winrct; - - tgpf->ar->winx = (short)tgpf->sizex; - tgpf->ar->winy = (short)tgpf->sizey; - tgpf->ar->winrct.xmin = 0; - tgpf->ar->winrct.ymin = 0; - tgpf->ar->winrct.xmax = tgpf->sizex; - tgpf->ar->winrct.ymax = tgpf->sizey; - GPU_matrix_push_projection(); GPU_matrix_identity_set(); GPU_matrix_push(); @@ -359,11 +389,6 @@ static void gp_render_offscreen(tGPDfill *tgpf) float ink[4] = {1.0f, 0.0f, 0.0f, 1.0f}; gp_draw_datablock(tgpf, ink); - /* restore size */ - tgpf->ar->winx = (short)bwinx; - tgpf->ar->winy = (short)bwiny; - tgpf->ar->winrct = brect; - GPU_matrix_pop_projection(); GPU_matrix_pop(); @@ -386,6 +411,8 @@ static void gp_render_offscreen(tGPDfill *tgpf) /* switch back to window-system-provided framebuffer */ GPU_offscreen_unbind(offscreen, true); GPU_offscreen_free(offscreen); + + return true; } /* return pixel data (rgba) at index */ @@ -459,7 +486,8 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index } } else { - t_a = true; /* edge of image*/ + /* edge of image*/ + t_a = true; break; } } @@ -474,7 +502,8 @@ static bool is_leak_narrow(ImBuf *ibuf, const int maxpixel, int limit, int index } } else { - t_b = true; /* edge of image*/ + /* edge of image*/ + t_b = true; break; } } @@ -543,7 +572,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) /* calculate index of the seed point using the position of the mouse */ int index = (tgpf->sizex * tgpf->center[1]) + tgpf->center[0]; - if ((index >= 0) && (index < maxpixel)) { + if ((index >= 0) && (index <= maxpixel)) { BLI_stack_push(stack, &index); } @@ -561,6 +590,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) */ while (!BLI_stack_is_empty(stack)) { int v; + BLI_stack_pop(stack, &v); get_pixel(ibuf, v, rgba); @@ -568,7 +598,7 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) if (true) { /* Was: 'rgba' */ /* check if no border(red) or already filled color(green) */ if ((rgba[0] != 1.0f) && (rgba[1] != 1.0f)) { - /* fill current pixel */ + /* fill current pixel with green */ set_pixel(ibuf, v, fill_col); /* add contact pixels */ @@ -580,22 +610,22 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) } } /* pixel right */ - if (v + 1 < maxpixel) { + if (v + 1 <= maxpixel) { index = v + 1; if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_HORZ)) { BLI_stack_push(stack, &index); } } /* pixel top */ - if (v + tgpf->sizex < maxpixel) { - index = v + tgpf->sizex; + if (v + ibuf->x <= maxpixel) { + index = v + ibuf->x; if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) { BLI_stack_push(stack, &index); } } /* pixel bottom */ - if (v - tgpf->sizex >= 0) { - index = v - tgpf->sizex; + if (v - ibuf->x >= 0) { + index = v - ibuf->x; if (!is_leak_narrow(ibuf, maxpixel, tgpf->fill_leak, v, LEAK_VERT)) { BLI_stack_push(stack, &index); } @@ -625,7 +655,7 @@ static void gpencil_clean_borders(tGPDfill *tgpf) int pixel = 0; /* horizontal lines */ - for (idx = 0; idx < ibuf->x - 1; idx++) { + for (idx = 0; idx < ibuf->x; idx++) { /* bottom line */ set_pixel(ibuf, idx, fill_col); /* top line */ @@ -649,12 +679,117 @@ static void gpencil_clean_borders(tGPDfill *tgpf) tgpf->ima->id.tag |= LIB_TAG_DOIT; } +/* Naive dilate + * + * Expand green areas into enclosing red areas. + * Using stack prevents creep when replacing colors directly. + * ----------- + * XXXXXXX + * XoooooX + * XXooXXX + * XXXX + * ----------- + */ +static void dilate(ImBuf *ibuf) +{ + BLI_Stack *stack = BLI_stack_new(sizeof(int), __func__); + const float green[4] = { 0.0f, 1.0f, 0.0f, 1.0f }; + const int maxpixel = (ibuf->x * ibuf->y) - 1; + /* detect pixels and expand into red areas */ + for (int v = maxpixel; v != 0; v--) { + float color[4]; + int index; + int tp = 0; + int bm = 0; + int lt = 0; + int rt = 0; + get_pixel(ibuf, v, color); + if (color[1] == 1.0f) { + /* pixel left */ + if (v - 1 >= 0) { + index = v - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + lt = index; + } + } + /* pixel right */ + if (v + 1 <= maxpixel) { + index = v + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + rt = index; + } + } + /* pixel top */ + if (v + ibuf->x <= maxpixel) { + index = v + ibuf->x; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + tp = index; + } + } + /* pixel bottom */ + if (v - ibuf->x >= 0) { + index = v - ibuf->x; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + bm = index; + } + } + /* pixel top-left */ + if (tp && lt) { + index = tp - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } + } + /* pixel top-right */ + if (tp && rt) { + index = tp + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } + } + /* pixel bottom-left */ + if (bm && lt) { + index = bm - 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } + } + /* pixel bottom-right */ + if (bm && rt) { + index = bm + 1; + get_pixel(ibuf, index, color); + if (color[0] == 1.0f) { + BLI_stack_push(stack, &index); + } + } + } + } + /* set dilated pixels */ + while (!BLI_stack_is_empty(stack)) { + int v; + BLI_stack_pop(stack, &v); + set_pixel(ibuf, v, green); + } + BLI_stack_free(stack); +} + /* Get the outline points of a shape using Moore Neighborhood algorithm * * This is a Blender customized version of the general algorithm described * in https://en.wikipedia.org/wiki/Moore_neighborhood */ -static void gpencil_get_outline_points(tGPDfill *tgpf) +static void gpencil_get_outline_points(tGPDfill *tgpf) { ImBuf *ibuf; float rgba[4]; @@ -686,6 +821,9 @@ static void gpencil_get_outline_points(tGPDfill *tgpf) ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); int imagesize = ibuf->x * ibuf->y; + /* dilate */ + dilate(ibuf); + /* find the initial point to start outline analysis */ for (int idx = imagesize - 1; idx != 0; idx--) { get_pixel(ibuf, idx, rgba); @@ -835,9 +973,9 @@ static void gpencil_points_from_stack(tGPDfill *tgpf) while (!BLI_stack_is_empty(tgpf->stack)) { int v[2]; BLI_stack_pop(tgpf->stack, &v); - point2D->x = v[0]; - point2D->y = v[1]; - + copy_v2fl_v2i(&point2D->x, v); + /* shift points to center of pixel */ + add_v2_fl(&point2D->x, 0.5f); point2D->pressure = 1.0f; point2D->strength = 1.0f; point2D->time = 0.0f; @@ -962,7 +1100,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin); ED_gp_project_stroke_to_plane( - tgpf->ob, tgpf->rv3d, gps, origin, + tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1); } @@ -1076,7 +1214,8 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op)) tgpf->fill_threshold = brush->gpencil_settings->fill_threshold; tgpf->fill_simplylvl = brush->gpencil_settings->fill_simplylvl; tgpf->fill_draw_mode = brush->gpencil_settings->fill_draw_mode; - + tgpf->fill_factor = (short)max_ii(1, min_ii((int)brush->gpencil_settings->fill_factor,8)); + /* get color info */ Material *ma = BKE_gpencil_get_material_from_brush(brush); /* if no brush defaults, get material and color info */ @@ -1238,34 +1377,38 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) in_bounds = BLI_rcti_isect_pt(&ar->winrct, event->x, event->y); if ((in_bounds) && (ar->regiontype == RGN_TYPE_WINDOW)) { + /* TODO GPXX: Verify the mouse click is right for any window size */ tgpf->center[0] = event->mval[0]; tgpf->center[1] = event->mval[1]; - /* save size */ - tgpf->sizex = ar->winx; - tgpf->sizey = ar->winy; - /* render screen to temp image */ - gp_render_offscreen(tgpf); + if ( gp_render_offscreen(tgpf) ) { - /* apply boundary fill */ - gpencil_boundaryfill_area(tgpf); + /* apply boundary fill */ + gpencil_boundaryfill_area(tgpf); - /* clean borders to avoid infinite loops */ - gpencil_clean_borders(tgpf); + /* clean borders to avoid infinite loops */ + gpencil_clean_borders(tgpf); - /* analyze outline */ - gpencil_get_outline_points(tgpf); + /* analyze outline */ + gpencil_get_outline_points(tgpf); - /* create array of points from stack */ - gpencil_points_from_stack(tgpf); + /* create array of points from stack */ + gpencil_points_from_stack(tgpf); - /* create z-depth array for reproject */ - gpencil_get_depth_array(tgpf); + /* create z-depth array for reproject */ + gpencil_get_depth_array(tgpf); - /* create stroke and reproject */ - gpencil_stroke_from_buffer(tgpf); + /* create stroke and reproject */ + gpencil_stroke_from_buffer(tgpf); + + } + + /* restore size */ + tgpf->ar->winx = (short)tgpf->bwinx; + tgpf->ar->winy = (short)tgpf->bwiny; + tgpf->ar->winrct = tgpf->brect; /* free temp stack data */ if (tgpf->stack) { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 4fba83a5f02..aa47319e3d9 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -92,6 +92,7 @@ typedef struct tGPDdraw { float tintcolor[4]; /* tint color */ bool onion; /* onion flag */ bool custonion; /* use custom onion colors */ + bool is_fill_stroke; /* use fill tool */ float diff_mat[4][4]; /* matrix */ } tGPDdraw; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 99b38098138..40f0c0e7b84 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -398,7 +398,9 @@ static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) /* get drawing origin */ gp_get_3d_reference(p, origin); - ED_gp_project_stroke_to_plane(obact, rv3d, gps, origin, p->lock_axis - 1); + ED_gp_project_stroke_to_plane( + p->scene, obact, rv3d, gps, + origin, p->lock_axis - 1); } /* convert screen-coordinates to buffer-coordinates */ @@ -752,11 +754,11 @@ static short gp_stroke_addpoint( gp_get_3d_reference(p, origin); /* reproject current */ ED_gpencil_tpoint_to_point(p->ar, origin, pt, &spt); - ED_gp_project_point_to_plane(obact, rv3d, origin, p->lock_axis - 1, &spt); + ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(p->ar, origin, ptb, &spt2); - ED_gp_project_point_to_plane(obact, rv3d, origin, p->lock_axis - 1, &spt2); + ED_gp_project_point_to_plane(p->scene, obact, rv3d, origin, p->lock_axis - 1, &spt2); p->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize; pt->uv_fac = p->totpixlen; if ((gp_style) && (gp_style->sima)) { diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 88906488e1a..962442824f9 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -930,11 +930,13 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) ts->gpencil_v3d_align, origin); /* reproject current */ ED_gpencil_tpoint_to_point(tgpi->ar, origin, tpt, &spt); - ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt); + ED_gp_project_point_to_plane(tgpi->scene, tgpi->ob, tgpi->rv3d, + origin, tgpi->lock_axis - 1, &spt); /* reproject previous */ ED_gpencil_tpoint_to_point(tgpi->ar, origin, tptb, &spt2); - ED_gp_project_point_to_plane(tgpi->ob, tgpi->rv3d, origin, tgpi->lock_axis - 1, &spt2); + ED_gp_project_point_to_plane(tgpi->scene, tgpi->ob, tgpi->rv3d, + origin, tgpi->lock_axis - 1, &spt2); tgpi->totpixlen += len_v3v3(&spt.x, &spt2.x) / pixsize; tpt->uv_fac = tgpi->totpixlen; if ((gp_style) && (gp_style->sima)) { @@ -993,7 +995,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) tgpi->scene, tgpi->ob, tgpi->gpl, ts->gpencil_v3d_align, origin); ED_gp_project_stroke_to_plane( - tgpi->ob, tgpi->rv3d, gps, origin, ts->gp_sculpt.lock_axis - 1); + tgpi->scene, tgpi->ob, tgpi->rv3d, gps, + origin, ts->gp_sculpt.lock_axis - 1); } /* if parented change position relative to parent object */ diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 84bfd709b10..1605353a156 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -937,8 +937,12 @@ void ED_gpencil_project_stroke_to_view(bContext *C, bGPDlayer *gpl, bGPDstroke * * Reproject all points of the stroke to a plane locked to axis to avoid stroke offset */ void ED_gp_project_stroke_to_plane( - const Object *ob, const RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) + const Scene *scene, const Object *ob, + const RegionView3D *rv3d, bGPDstroke *gps, + const float origin[3], const int axis) { + const ToolSettings *ts = scene->toolsettings; + const View3DCursor *cursor = &scene->cursor; float plane_normal[3]; float vn[3]; @@ -953,13 +957,37 @@ void ED_gp_project_stroke_to_plane( */ ED_view3d_global_to_vector(rv3d, origin, plane_normal); } - else { + else if (axis < 3) { plane_normal[axis] = 1.0f; /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { - mul_mat3_m4_v3(ob->obmat, plane_normal); + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + + /* move origin to cursor */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(mat[3], cursor->location); + } + + mul_mat3_m4_v3(mat, plane_normal); } } + else { + float scale[3] = { 1.0f, 1.0f, 1.0f }; + plane_normal[2] = 1.0f; + float mat[4][4]; + loc_eul_size_to_mat4(mat, + cursor->location, + cursor->rotation_euler, + scale); + + /* move origin to object */ + if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { + copy_v3_v3(mat[3], ob->obmat[3]); + } + + mul_mat3_m4_v3(mat, plane_normal); + } /* Reproject the points in the plane */ for (int i = 0; i < gps->totpoints; i++) { @@ -984,8 +1012,12 @@ void ED_gp_project_stroke_to_plane( * \param[in, out] pt : Point to affect */ void ED_gp_project_point_to_plane( - const Object *ob, const RegionView3D *rv3d, const float origin[3], const int axis, bGPDspoint *pt) + const Scene *scene, const Object *ob, + const RegionView3D *rv3d, const float origin[3], + const int axis, bGPDspoint *pt) { + const ToolSettings *ts = scene->toolsettings; + const View3DCursor *cursor = &scene->cursor; float plane_normal[3]; float vn[3]; @@ -1000,14 +1032,37 @@ void ED_gp_project_point_to_plane( */ ED_view3d_global_to_vector(rv3d, origin, plane_normal); } - else { + else if (axis < 3) { plane_normal[axis] = 1.0f; /* if object, apply object rotation */ if (ob && (ob->type == OB_GPENCIL)) { - mul_mat3_m4_v3(ob->obmat, plane_normal); + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + + /* move origin to cursor */ + if (ts->gpencil_v3d_align & GP_PROJECT_CURSOR) { + copy_v3_v3(mat[3], cursor->location); + } + + mul_mat3_m4_v3(mat, plane_normal); } } + else { + float scale[3] = { 1.0f, 1.0f, 1.0f }; + plane_normal[2] = 1.0f; + float mat[4][4]; + loc_eul_size_to_mat4(mat, + cursor->location, + cursor->rotation_euler, + scale); + /* move origin to object */ + if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { + copy_v3_v3(mat[3], ob->obmat[3]); + } + + mul_mat3_m4_v3(mat, plane_normal); + } /* Reproject the points in the plane */ /* get a vector from the point with the current view direction of the viewport */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index e331032bd6e..fdbb8556891 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -225,9 +225,11 @@ void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob); void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode); void ED_gp_project_stroke_to_plane( + const struct Scene *scene, const struct Object *ob, const struct RegionView3D *rv3d, struct bGPDstroke *gps, const float origin[3], const int axis); void ED_gp_project_point_to_plane( + const struct Scene *scene, const struct Object *ob, const struct RegionView3D *rv3d, const float origin[3], const int axis, struct bGPDspoint *pt); void ED_gp_get_drawing_reference( diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl index 3de1bd838b3..6c7e2d17e06 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl @@ -1,6 +1,9 @@ uniform mat4 ModelViewProjectionMatrix; uniform vec2 Viewport; uniform int xraymode; +uniform int caps_start; +uniform int caps_end; +uniform int fill_stroke; layout(lines_adjacency) in; layout(triangle_strip, max_vertices = 13) out; @@ -15,6 +18,8 @@ out vec2 mTexCoord; #define GP_XRAY_3DSPACE 1 #define GP_XRAY_BACK 2 +#define GPENCIL_FLATCAP 1 + /* project 3d point to 2d on screen space */ vec2 toScreenSpace(vec4 vertex) { @@ -37,6 +42,22 @@ float getZdepth(vec4 point) /* in front by default */ return 0.0; } + +/* check equality but with a small tolerance */ +bool is_equal(vec4 p1, vec4 p2) +{ + float limit = 0.0001; + float x = abs(p1.x - p2.x); + float y = abs(p1.y - p2.y); + float z = abs(p1.z - p2.z); + + if ((x < limit) && (y < limit) && (z < limit)) { + return true; + } + + return false; +} + void main(void) { float MiterLimit = 0.75; @@ -134,10 +155,11 @@ void main(void) } /* generate the start endcap (alpha < 0 used as endcap flag)*/ - if (P0 == P2) { + float extend = (fill_stroke > 0) ? 2 : 1 ; + if ((caps_start != GPENCIL_FLATCAP) && is_equal(P0,P2)) { mTexCoord = vec2(1, 0.5); mColor = vec4(finalColor[1].rgb, finalColor[1].a * -1.0) ; - vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0; + vec2 svn1 = normalize(sp1 - sp2) * length_a * 4.0 * extend; gl_Position = vec4((sp1 + svn1) / Viewport, getZdepth(P1), 1.0); EmitVertex(); @@ -174,7 +196,7 @@ void main(void) EmitVertex(); /* generate the end endcap (alpha < 0 used as endcap flag)*/ - if (P1 == P3) { + if ((caps_end != GPENCIL_FLATCAP) && is_equal(P1,P3)) { mTexCoord = vec2(0, 1); mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; gl_Position = vec4((sp2 + (length_b * 2.0) * miter_b) / Viewport, getZdepth(P2), 1.0); @@ -187,7 +209,7 @@ void main(void) mTexCoord = vec2(1, 0.5); mColor = vec4(finalColor[2].rgb, finalColor[2].a * -1.0) ; - vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0; + vec2 svn2 = normalize(sp2 - sp1) * length_b * 4.0 * extend; gl_Position = vec4((sp2 + svn2) / Viewport, getZdepth(P2), 1.0); EmitVertex(); } diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl index 5cbe2f60ebd..968f913d4e4 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl @@ -4,7 +4,7 @@ uniform mat4 ProjectionMatrix; uniform float pixsize; /* rv3d->pixsize */ uniform int keep_size; uniform float objscale; -uniform int pixfactor; +uniform float pixfactor; in vec3 pos; in vec4 color; diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 5fec1528e37..4bfbb3655af 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -83,23 +83,25 @@ typedef struct BrushGpencilSettings { float fill_threshold; /** Number of pixel to consider the leak is too small (x 2). */ short fill_leak; - char _pad1[6]; + /** Fill zoom factor */ + short fill_factor; + char _pad_1[4]; /** Number of simplify steps. */ - int fill_simplylvl; + int fill_simplylvl; /** Type of control lines drawing mode. */ - int fill_draw_mode; + int fill_draw_mode; /** Icon identifier. */ - int icon_id; + int icon_id; /** Maximum distance before generate new point for very fast mouse movements. */ - int input_samples; + int input_samples; /** Random factor for UV rotation. */ float uv_random; /** Moved to 'Brush.gpencil_tool'. */ - int brush_type DNA_DEPRECATED; + int brush_type DNA_DEPRECATED; /** Soft, hard or stroke. */ - int eraser_mode; + int eraser_mode; /** Smooth while drawing factor. */ float active_smooth; /** Factor to apply to strength for soft eraser. */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 711ac8c4bb1..428eb8fbc57 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1053,6 +1053,7 @@ typedef enum eGP_Lockaxis_Types { GP_LOCKAXIS_X = 1, GP_LOCKAXIS_Y = 2, GP_LOCKAXIS_Z = 3, + GP_LOCKAXIS_CURSOR = 4 } eGP_Lockaxis_Types; /* Settings for a GPencil Stroke Sculpting Brush */ diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index b14e97b8656..86ac8d3bae6 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -126,10 +126,10 @@ static EnumPropertyItem rna_enum_gpencil_brush_eraser_modes_items[] = { }; static EnumPropertyItem rna_enum_gpencil_fill_draw_modes_items[] = { + {GP_FILL_DMODE_BOTH, "BOTH", 0, "Default", "Use both visible strokes and edit lines as fill boundary limits"}, {GP_FILL_DMODE_STROKE, "STROKE", 0, "Strokes", "Use visible strokes as fill boundary limits"}, - {GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Control", "Use internal control lines as fill boundary limits"}, - {GP_FILL_DMODE_BOTH, "BOTH", 0, "Both", "Use visible strokes and control lines as fill boundary limits"}, - {0, NULL, 0, NULL, NULL}, + {GP_FILL_DMODE_CONTROL, "CONTROL", 0, "Edit Lines", "Use edit lines as fill boundary limits"}, + {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem rna_enum_gpencil_brush_icons_items[] = { @@ -1160,6 +1160,15 @@ static void rna_def_gpencil_options(BlenderRNA *brna) RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* fill factor size */ + prop = RNA_def_property(srna, "fill_factor", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "fill_factor"); + RNA_def_property_range(prop, 1, 8); + RNA_def_property_ui_text(prop, "Resolution", + "Multiplier for fill resolution, higher resolution is more accurate but slower"); + RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, 0); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + /* fill simplify steps */ prop = RNA_def_property(srna, "fill_simplify_level", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "fill_simplylvl"); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 1393a9d9888..b66363f45ae 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -82,6 +82,7 @@ static const EnumPropertyItem rna_enum_gpencil_lock_axis_items[] = { {GP_LOCKAXIS_Y, "AXIS_Y", ICON_AXIS_FRONT, "Front (X-Z)", "Project strokes to plane locked to Y"}, {GP_LOCKAXIS_X, "AXIS_X", ICON_AXIS_SIDE, "Side (Y-Z)", "Project strokes to plane locked to X"}, {GP_LOCKAXIS_Z, "AXIS_Z", ICON_AXIS_TOP, "Top (X-Y)", "Project strokes to plane locked to Z"}, + {GP_LOCKAXIS_CURSOR, "CURSOR", ICON_PIVOT_CURSOR, "Cursor", "Align strokes to current 3D cursor orientation"}, {0, NULL, 0, NULL, NULL}, }; #endif