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_grease_pencil_common.py8
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c65
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h15
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c39
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c98
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c16
7 files changed, 178 insertions, 67 deletions
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index b93869b26ba..5d09dc8d942 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -622,6 +622,14 @@ class GreasePencilDataPanel:
row.prop(gpl, "after_color", text="")
sub.prop(gpl, "ghost_after_range", text="After")
+ # Smooth and subdivide new strokes
+ layout.separator()
+ col = layout.column(align=True)
+ col.label(text="New Stroke Quality:")
+ split = col.split()
+ split.prop(gpl, "smooth_drawfac")
+ split.prop(gpl, "subdivision")
+
class GreasePencilToolsPanel:
# subclass must set
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 95314445045..ab6217c20e3 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -223,70 +223,9 @@ static bool gp_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, int i
GP_EditBrush_Data *brush = gso->brush;
bGPDspoint *pt = &gps->points[i];
float inf = gp_brush_influence_calc(gso, radius, co);
- float pressure = 0.0f;
- float sco[3] = {0.0f};
- /* Do nothing if not enough points to smooth out */
- if (gps->totpoints <= 2) {
- return false;
- }
-
- /* Only affect endpoints by a fraction of the normal strength,
- * to prevent the stroke from shrinking too much
- */
- if ((i == 0) || (i == gps->totpoints - 1)) {
- inf *= 0.1f;
- }
-
- /* Compute smoothed coordinate by taking the ones nearby */
- /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
- {
- // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
- const int steps = 2;
- const float average_fac = 1.0f / (float)(steps * 2 + 1);
- int step;
-
- /* add the point itself */
- madd_v3_v3fl(sco, &pt->x, average_fac);
-
- if (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) {
- pressure += pt->pressure * average_fac;
- }
-
- /* n-steps before/after current point */
- // XXX: review how the endpoints are treated by this algorithm
- // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
- for (step = 1; step <= steps; step++) {
- bGPDspoint *pt1, *pt2;
- int before = i - step;
- int after = i + step;
-
- CLAMP_MIN(before, 0);
- CLAMP_MAX(after, gps->totpoints - 1);
-
- pt1 = &gps->points[before];
- pt2 = &gps->points[after];
-
- /* add both these points to the average-sum (s += p[i]/n) */
- madd_v3_v3fl(sco, &pt1->x, average_fac);
- madd_v3_v3fl(sco, &pt2->x, average_fac);
-
- /* do pressure too? */
- if (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) {
- pressure += pt1->pressure * average_fac;
- pressure += pt2->pressure * average_fac;
- }
- }
- }
-
- /* Based on influence factor, blend between original and optimal smoothed coordinate */
- interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
-
- if (brush->flag & GP_EDITBRUSH_FLAG_SMOOTH_PRESSURE) {
- pt->pressure = pressure;
- }
-
- return true;
+ /* perform smoothing */
+ return gp_smooth_stroke(gps, i, inf);
}
/* ----------------------------------------------- */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 45dfb36b9d9..5dd491c66d3 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -208,6 +208,21 @@ void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
+/**
+* Apply smooth to stroke
+*
+* gps Stroke to smooth
+* i Point index
+* inf Smooth factor
+*/
+bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf);
+
+/* subdivide a stroke
+* gps Stroke data
+* new_totpoints Total number of points
+*/
+void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
+
/******************************************************* */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index b76ed90a0f1..3784d11908f 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -571,6 +571,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
bGPDstroke *gps;
bGPDspoint *pt;
tGPspoint *ptc;
+ bGPDlayer *layer = gpencil_layer_getactive(p->gpd);
+
int i, totelem;
/* since strokes are so fine, when using their depth we need a margin otherwise they might get missed */
int depth_margin = (p->gpd->flag & GP_DATA_DEPTH_STROKE) ? 4 : 0;
@@ -610,8 +612,20 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
gps->inittime = p->inittime;
/* allocate enough memory for a continuous array for storage points */
- gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
+ int sublevel = layer->sublevel;
+ int new_totpoints = gps->totpoints;
+ for (i = 0; i < sublevel; ++i)
+ {
+ // Avoid error if subdivide is too big (assume totpoints is right)
+ if (new_totpoints + (new_totpoints - 1) > GP_STROKE_BUFFER_MAX)
+ {
+ sublevel = i; // reduce sublevel
+ break;
+ }
+ new_totpoints += new_totpoints - 1;
+ }
+ gps->points = MEM_callocN(sizeof(bGPDspoint) * new_totpoints, "gp_stroke_points");
+
/* set pointer to first non-initialized point */
pt = gps->points + (gps->totpoints - totelem);
@@ -730,10 +744,29 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->time = ptc->time;
}
+ /* subdivide the stroke */
+ if (sublevel > 0)
+ {
+ int sub = gps->totpoints;
+ for (i = 0; i < sublevel; ++i)
+ {
+ sub += sub - 1;
+ gp_subdivide_stroke(gps, sub);
+ }
+ }
+ /* smooth stroke */
+ if (layer->smooth_drawfac > 0.0f) // only if something to do
+ {
+ for (i = 0; i < gps->totpoints; i++)
+ {
+ gp_smooth_stroke(gps, i, layer->smooth_drawfac);
+ }
+ }
+
if (depth_arr)
MEM_freeN(depth_arr);
}
-
+
/* add stroke to frame */
BLI_addtail(&p->gpf->strokes, gps);
gp_stroke_added_enable(p);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index a23628e6507..8e56cf8199e 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -533,4 +533,102 @@ bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen
}
}
+/* Apply smooth to stroke point
+* gps Stroke to smooth
+* i Point index
+* inf Smooth factor
+*/
+bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf)
+{
+ bGPDspoint *pt = &gps->points[i];
+ float sco[3] = { 0.0f };
+
+ /* Do nothing if not enough points to smooth out */
+ if (gps->totpoints <= 2) {
+ return false;
+ }
+
+ /* Only affect endpoints by a fraction of the normal strength,
+ * to prevent the stroke from shrinking too much
+ */
+ if ((i == 0) || (i == gps->totpoints - 1)) {
+ inf *= 0.1f;
+ }
+
+ /* Compute smoothed coordinate by taking the ones nearby */
+ /* XXX: This is potentially slow, and suffers from accumulation error as earlier points are handled before later ones */
+ {
+ // XXX: this is hardcoded to look at 2 points on either side of the current one (i.e. 5 items total)
+ const int steps = 2;
+ const float average_fac = 1.0f / (float)(steps * 2 + 1);
+ int step;
+
+ /* add the point itself */
+ madd_v3_v3fl(sco, &pt->x, average_fac);
+
+ /* n-steps before/after current point */
+ // XXX: review how the endpoints are treated by this algorithm
+ // XXX: falloff measures should also introduce some weighting variations, so that further-out points get less weight
+ for (step = 1; step <= steps; step++) {
+ bGPDspoint *pt1, *pt2;
+ int before = i - step;
+ int after = i + step;
+
+ CLAMP_MIN(before, 0);
+ CLAMP_MAX(after, gps->totpoints - 1);
+
+ pt1 = &gps->points[before];
+ pt2 = &gps->points[after];
+
+ /* add both these points to the average-sum (s += p[i]/n) */
+ madd_v3_v3fl(sco, &pt1->x, average_fac);
+ madd_v3_v3fl(sco, &pt2->x, average_fac);
+
+ }
+ }
+
+ /* Based on influence factor, blend between original and optimal smoothed coordinate */
+ interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
+
+ return true;
+}
+
+/* subdivide a stroke
+* gps Stroke data
+* new_totpoints Total number of points
+*/
+void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints)
+{
+ int i;
+ // Subdivide stroke adding a point half way existing points
+ bGPDspoint *pt_a;
+ bGPDspoint *pt_b;
+ bGPDspoint *pt_n;
+
+ /* Move points to insert subdivision */
+ int y = 1;
+ for (i = gps->totpoints - 1; i > 0; --i)
+ {
+ pt_n = &gps->points[i];
+ gps->points[new_totpoints - y] = *pt_n;
+ y = y + 2;
+ }
+ /* Create interpolated points */
+ for (i = 0; i < new_totpoints - 1; ++i)
+ {
+ pt_a = &gps->points[i];
+ pt_n = &gps->points[i + 1];
+ pt_b = &gps->points[i + 2];
+ // Interpolate all values
+ interp_v3_v3v3(&pt_n->x, &pt_a->x, &pt_b->x, 0.5f);
+ pt_n->pressure = interpf(pt_a->pressure, pt_b->pressure, 0.5f);
+ pt_n->time = interpf(pt_a->time, pt_b->time, 0.5f);
+
+ ++i; // add to loop to jump next pair
+ }
+
+ gps->totpoints = new_totpoints; // Increase number of points
+
+}
+
/* ******************************************************** */
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index aa98ddb11ae..0ef213235b6 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -130,6 +130,10 @@ typedef struct bGPDlayer {
char info[128]; /* optional reference info about this layer (i.e. "director's comments, 12/3")
* this is used for the name of the layer too and kept unique. */
+
+ float smooth_drawfac; /* factor used for dynamic smooth of strokes */
+ short sublevel; /* subdivision level */
+ short pad[5]; /* padding for compiler error */
} bGPDlayer;
/* bGPDlayer->flag */
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 291456a591b..7d5e7c1b49a 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -796,7 +796,21 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
-
+
+ /* dynamic smooth factor */
+ prop = RNA_def_property(srna, "smooth_drawfac", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "smooth_drawfac");
+ RNA_def_property_range(prop, 0.0, 2.0f);
+ RNA_def_property_ui_text(prop, "Smooth", "Amount of smoothing to apply to newly created strokes, to reduce jitter/noise");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
+ /* Subdivision level */
+ prop = RNA_def_property(srna, "subdivision", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sublevel");
+ RNA_def_property_range(prop, 0, 3);
+ RNA_def_property_ui_text(prop, "Subdivide", "Number of times to subdivide newly created strokes, for less jagged strokes");
+ RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
+
/* Flags */
prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE);