Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_paint_common.py19
-rw-r--r--release/scripts/startup/bl_ui/space_topbar.py32
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c4
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c38
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c24
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c56
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c257
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c8
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c9
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c67
-rw-r--r--source/blender/editors/include/ED_gpencil.h2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_geom.glsl30
-rw-r--r--source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert.glsl2
-rw-r--r--source/blender/makesdna/DNA_brush_types.h16
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_brush.c15
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c1
21 files changed, 482 insertions, 133 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 = layout.row(align=True)
row.prop(gp_settings, "fill_leak", text="Leak Size")
- row.separator()
- row = layout.column(align=True)
+ row = layout.row(align=True)
row.prop(brush, "size", text="Thickness")
- row = layout.column(align=True)
+ 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 Draw Mode")
+ 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