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:
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_paint.c')
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c321
1 files changed, 240 insertions, 81 deletions
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 01b0fe80dfc..06079c34d12 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_hash.h"
#include "BLI_math.h"
#include "BLI_math_geom.h"
#include "BLI_rand.h"
@@ -155,7 +156,7 @@ typedef struct tGPsdata {
/** window where painting originated. */
wmWindow *win;
/** area where painting originated. */
- ScrArea *sa;
+ ScrArea *area;
/** region where painting originated. */
ARegion *region;
/** needed for GP_STROKE_2DSPACE. */
@@ -254,6 +255,10 @@ typedef struct tGPsdata {
tGPguide guide;
ReportList *reports;
+
+ /** Random settings by stroke */
+ GpRandomSettings random_settings;
+
} tGPsdata;
/* ------ */
@@ -296,9 +301,9 @@ static void gp_session_validatebuffer(tGPsdata *p);
static bool gpencil_draw_poll(bContext *C)
{
if (ED_operator_regionactive(C)) {
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
/* 3D Viewport */
- if (sa->spacetype != SPACE_VIEW3D) {
+ if (area->spacetype != SPACE_VIEW3D) {
return false;
}
@@ -353,7 +358,7 @@ static void gp_get_3d_reference(tGPsdata *p, float vec[3])
if (p->ownerPtr.type == &RNA_Object) {
ob = (Object *)p->ownerPtr.data;
}
- ED_gpencil_drawing_reference_get(p->scene, ob, p->gpl, *p->align_flag, vec);
+ ED_gpencil_drawing_reference_get(p->scene, ob, *p->align_flag, vec);
}
/* Stroke Editing ---------------------------- */
@@ -444,7 +449,10 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
}
int mval_i[2];
- round_v2i_v2fl(mval_i, mval);
+ float rmval[2];
+ rmval[0] = mval[0] - 0.5f;
+ rmval[1] = mval[1] - 0.5f;
+ round_v2i_v2fl(mval_i, rmval);
if (gpencil_project_check(p) &&
(ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
@@ -486,6 +494,7 @@ static void gp_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[
/* Apply jitter to stroke point. */
static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
{
+ const float axis[2] = {0.0f, 1.0f};
/* Jitter is applied perpendicular to the mouse movement vector (2D space). */
float mvec[2];
/* Mouse movement in ints -> floats. */
@@ -493,16 +502,15 @@ static void gp_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplitude)
tGPspoint *pt_prev = pt - 1;
sub_v2_v2v2(mvec, &pt->x, &pt_prev->x);
normalize_v2(mvec);
+ /* Rotate mvec by 90 degrees... */
+ float angle = angle_v2v2(mvec, axis);
+ /* Reduce noise in the direction of the stroke. */
+ mvec[0] *= cos(angle);
+ mvec[1] *= sin(angle);
+
+ /* Scale by displacement amount, and apply. */
+ madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f);
}
- else {
- mvec[0] = 0.0f;
- mvec[1] = 0.0f;
- }
- /* Rotate mvec by 90 degrees... */
- SWAP(float, mvec[0], mvec[1]);
- mvec[0] -= mvec[0];
- /* Scale by displacement amount, and apply. */
- madd_v2_v2fl(&pt->x, mvec, amplitude);
}
/* apply pressure change depending of the angle of the stroke to simulate a pen with shape */
@@ -511,7 +519,6 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
float mvec[2];
float sen = brush->gpencil_settings->draw_angle_factor; /* sensitivity */
float fac;
- float mpressure;
/* default angle of brush in radians */
float angle = brush->gpencil_settings->draw_angle;
@@ -539,9 +546,7 @@ static void gp_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const floa
fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
/* interpolate with previous point for smoother transitions */
- mpressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
- pt->pressure = mpressure;
-
+ pt->pressure = interpf(pt->pressure - (sen * fac), (pt - 1)->pressure, 0.3f);
CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
}
}
@@ -686,6 +691,78 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t
}
}
+static void gp_apply_randomness(tGPsdata *p,
+ BrushGpencilSettings *brush_settings,
+ tGPspoint *pt,
+ const bool press,
+ const bool strength,
+ const bool uv)
+{
+ bGPdata *gpd = p->gpd;
+ GpRandomSettings random_settings = p->random_settings;
+ float value = 0.0f;
+ /* Apply randomness to pressure. */
+ if ((brush_settings->draw_random_press > 0.0f) && (press)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * 2.0 * brush_settings->draw_random_press;
+ }
+ else {
+ value = 1.0 + random_settings.pressure * brush_settings->draw_random_press;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->pressure *= value;
+ CLAMP(pt->pressure, 0.1f, 1.0f);
+ }
+
+ /* Apply randomness to color strength. */
+ if ((brush_settings->draw_random_strength) && (strength)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) {
+ float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
+ value = 1.0 + rand * brush_settings->draw_random_strength;
+ }
+ else {
+ value = 1.0 + random_settings.strength * brush_settings->draw_random_strength;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_pressure, 0, random_settings.pen_press);
+ }
+
+ pt->strength *= value;
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+
+ /* Apply randomness to uv texture rotation. */
+ if ((brush_settings->uv_random > 0.0f) && (uv)) {
+ if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) {
+ float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f -
+ 1.0f;
+ value = rand * M_PI_2 * brush_settings->uv_random;
+ }
+ else {
+ value = random_settings.uv * M_PI_2 * brush_settings->uv_random;
+ }
+
+ /* Apply random curve. */
+ if (brush_settings->flag2 & GP_BRUSH_USE_UV_RAND_PRESS) {
+ value *= BKE_curvemapping_evaluateF(
+ brush_settings->curve_rand_uv, 0, random_settings.pen_press);
+ }
+
+ pt->uv_rot += value;
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+}
+
/* add current stroke-point to buffer (returns whether point was successfully added) */
static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
{
@@ -743,10 +820,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
return GP_STROKEADD_INVALID;
}
- /* Set vertex colors for buffer. */
- ED_gpencil_sbuffer_vertex_color_set(
- p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material);
-
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
@@ -767,6 +840,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
+ /* Set vertex colors for buffer. */
+ ED_gpencil_sbuffer_vertex_color_set(p->depsgraph,
+ p->ob,
+ p->scene->toolsettings,
+ p->brush,
+ p->material,
+ p->random_settings.hsv,
+ p->random_settings.pen_press);
+
if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) {
/* Apply jitter to position */
if (brush_settings->draw_jitter > 0.0f) {
@@ -780,24 +862,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
const float fac = rand * square_f(exp_factor) * jitpress;
gp_brush_jitter(gpd, pt, fac);
}
- /* apply randomness to pressure */
- if (brush_settings->draw_random_press > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press;
- CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f);
- }
- /* apply randomness to uv texture rotation */
- if (brush_settings->uv_random > 0.0f) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->uv_rot += rand * M_PI * brush_settings->uv_random;
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
- /* apply randomness to color strength */
- if (brush_settings->draw_random_strength) {
- float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f;
- pt->strength *= 1.0 + rand * brush_settings->draw_random_strength;
- CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
- }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, true, true, true);
}
/* apply angle of stroke to brush size */
@@ -809,7 +876,7 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure
pt->time = (float)(curtime - p->inittime);
/* point uv (only 3d view) */
- if ((p->sa->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
+ if ((p->area->spacetype == SPACE_VIEW3D) && (gpd->runtime.sbuffer_used > 0)) {
tGPspoint *ptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1;
bGPDspoint spt, spt2;
@@ -956,9 +1023,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
pt++;
@@ -991,7 +1059,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
pt->time = ptc->time;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) {
BKE_gpencil_dvert_ensure(gps);
@@ -1110,11 +1178,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
pt->pressure = ptc->pressure;
pt->strength = ptc->strength;
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ copy_v4_v4(pt->vert_color, ptc->vert_color);
pt->time = ptc->time;
pt->uv_fac = ptc->uv_fac;
pt->uv_rot = ptc->uv_rot;
/* Apply the vertex color to point. */
- ED_gpencil_point_vertex_color_set(ts, brush, pt);
+ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc);
if (dvert != NULL) {
dvert->totweight = 0;
@@ -1142,6 +1211,16 @@ static void gp_stroke_newfrombuffer(tGPsdata *p)
reduce += 0.25f; /* reduce the factor */
}
}
+ /* If reproject the stroke using Stroke mode, need to apply a smooth because
+ * the reprojection creates small jitter. */
+ if (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) {
+ float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
+ float sfac = interpf(1.0f, 0.2f, ifac);
+ for (i = 0; i < gps->totpoints - 1; i++) {
+ BKE_gpencil_stroke_smooth(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
+ }
+ }
/* Simplify adaptive */
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
@@ -1239,7 +1318,7 @@ static bool gp_stroke_eraser_is_occluded(tGPsdata *p,
gp_settings = eraser->gpencil_settings;
}
- if ((gp_settings != NULL) && (p->sa->spacetype == SPACE_VIEW3D) &&
+ if ((gp_settings != NULL) && (p->area->spacetype == SPACE_VIEW3D) &&
(gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
RegionView3D *rv3d = p->region->regiondata;
bGPDlayer *gpl = p->gpl;
@@ -1356,7 +1435,6 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
bGPDframe *gpf,
bGPDstroke *gps,
const float mval[2],
- const float mvalo[2],
const int radius,
const rcti *rect)
{
@@ -1475,7 +1553,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
* eraser region (either within stroke painted, or on its lines)
* - this assumes that linewidth is irrelevant
*/
- if (gp_stroke_inside_circle(mval, mvalo, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
+ if (gp_stroke_inside_circle(mval, radius, pc0[0], pc0[1], pc2[0], pc2[1])) {
if ((gp_stroke_eraser_is_occluded(p, pt0, pc0[0], pc0[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
(gp_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
@@ -1591,9 +1669,9 @@ static void gp_stroke_doeraser(tGPsdata *p)
rect.xmax = p->mval[0] + calc_radius;
rect.ymax = p->mval[1] + calc_radius;
- if (p->sa->spacetype == SPACE_VIEW3D) {
+ if (p->area->spacetype == SPACE_VIEW3D) {
if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
view3d_region_operator_needs_opengl(p->win, p->region);
ED_view3d_autodist_init(p->depsgraph, p->region, v3d, 0);
}
@@ -1631,8 +1709,8 @@ static void gp_stroke_doeraser(tGPsdata *p)
/* Not all strokes in the datablock may be valid in the current editor/context
* (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
*/
- if (ED_gpencil_stroke_can_use_direct(p->sa, gps)) {
- gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->mvalo, calc_radius, &rect);
+ if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
+ gp_stroke_eraser_dostroke(p, gpf, gps, p->mval, calc_radius, &rect);
}
}
}
@@ -1736,13 +1814,19 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p)
/* if not exist, create a new one */
if ((paint->brush == NULL) || (paint->brush->gpencil_settings == NULL)) {
/* create new brushes */
- BKE_brush_gpencil_paint_presets(bmain, ts);
+ BKE_brush_gpencil_paint_presets(bmain, ts, true);
changed = true;
}
- /* be sure curves are initializated */
+ /* Be sure curves are initializated. */
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_strength);
BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_pressure);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_strength);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_uv);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_hue);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_saturation);
+ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_value);
/* assign to temp tGPsdata */
p->brush = paint->brush;
@@ -1814,7 +1898,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
* - must verify that region data is 3D-view (and not something else)
*/
/* CAUTION: If this is the "toolbar", then this will change on the first stroke */
- p->sa = curarea;
+ p->area = curarea;
p->region = region;
p->align_flag = &ts->gpencil_v3d_align;
@@ -1829,7 +1913,7 @@ static bool gp_session_initdata(bContext *C, wmOperator *op, tGPsdata *p)
}
if ((!obact) || (obact->type != OB_GPENCIL)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* if active object doesn't exist or isn't a GP Object, create one */
const float *cur = p->scene->cursor.location;
@@ -1987,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
return;
}
- /* Eraser mode: If no active strokes, just return. */
+ /* Eraser mode: If no active strokes, add one or just return. */
if (paintmode == GP_PAINTMODE_ERASER) {
+ /* Eraser mode:
+ * 1) Add new frames to all frames that we might touch,
+ * 2) Ensure that p->gpf refers to the frame used for the active layer
+ * (to avoid problems with other tools which expect it to exist)
+ *
+ * This is done only if additive drawing is enabled.
+ */
bool has_layer_to_erase = false;
LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) {
@@ -1997,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
continue;
}
+ /* Add a new frame if needed (and based off the active frame,
+ * as we need some existing strokes to erase)
+ *
+ * Note: We don't add a new frame if there's nothing there now, so
+ * -> If there are no frames at all, don't add one
+ * -> If there are no strokes in that frame, don't add a new empty frame
+ */
if (gpl->actframe && gpl->actframe->strokes.first) {
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+ }
has_layer_to_erase = true;
break;
}
}
+ /* Ensure this gets set. */
+ if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) {
+ p->gpf = p->gpl->actframe;
+ }
+
if (has_layer_to_erase == false) {
p->status = GP_STATUS_ERROR;
return;
@@ -2056,8 +2162,8 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* when drawing in the camera view, in 2D space, set the subrect */
p->subrect = NULL;
if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
- if (p->sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = p->sa->spacedata.first;
+ if (p->area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = p->area->spacedata.first;
RegionView3D *rv3d = p->region->regiondata;
/* for camera view set the subrect */
@@ -2074,7 +2180,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
p->gsc.gpd = p->gpd;
p->gsc.gpl = p->gpl;
- p->gsc.sa = p->sa;
+ p->gsc.area = p->area;
p->gsc.region = p->region;
p->gsc.v2d = p->v2d;
@@ -2085,7 +2191,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps
/* check if points will need to be made in view-aligned space */
if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
- switch (p->sa->spacetype) {
+ switch (p->area->spacetype) {
case SPACE_VIEW3D: {
p->gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE;
break;
@@ -2110,7 +2216,7 @@ static void gp_paint_strokeend(tGPsdata *p)
* the conversions will project the values correctly...
*/
if (gpencil_project_check(p)) {
- View3D *v3d = p->sa->spacedata.first;
+ View3D *v3d = p->area->spacedata.first;
/* need to restore the original projection settings before packing up */
view3d_region_operator_needs_opengl(p->win, p->region);
@@ -2193,18 +2299,17 @@ static void gpencil_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
}
/* Turn brush cursor in 3D view on/off */
-static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short enable)
+static void gpencil_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
{
if (p->erasercursor && !enable) {
/* clear cursor */
- WM_paint_cursor_end(CTX_wm_manager(C), p->erasercursor);
+ WM_paint_cursor_end(p->erasercursor);
p->erasercursor = NULL;
}
else if (enable && !p->erasercursor) {
ED_gpencil_toggle_brush_cursor(p->C, false, NULL);
/* enable cursor */
- p->erasercursor = WM_paint_cursor_activate(CTX_wm_manager(C),
- SPACE_TYPE_ANY,
+ p->erasercursor = WM_paint_cursor_activate(SPACE_TYPE_ANY,
RGN_TYPE_ANY,
NULL, /* XXX */
gpencil_draw_eraser,
@@ -2229,7 +2334,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
/* check size of buffer before cleanup, to determine if anything happened here */
if (p->paintmode == GP_PAINTMODE_ERASER) {
/* turn off radial brush cursor */
- gpencil_draw_toggle_eraser_cursor(C, p, false);
+ gpencil_draw_toggle_eraser_cursor(p, false);
}
/* always store the new eraser size to be used again next time
@@ -2241,7 +2346,7 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op)
}
/* restore cursor to indicate end of drawing */
- if (p->sa->spacetype != SPACE_VIEW3D) {
+ if (p->area->spacetype != SPACE_VIEW3D) {
WM_cursor_modal_restore(CTX_wm_window(C));
}
else {
@@ -2688,6 +2793,8 @@ static void gpencil_draw_apply_event(bContext *C,
/* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
p->pressure = event->tablet.pressure;
+ /* By default use pen pressure for random curves but attenuated. */
+ p->random_settings.pen_press = pow(p->pressure, 3.0f);
/* Hack for pressure sensitive eraser on D+RMB when using a tablet:
* The pen has to float over the tablet surface, resulting in
@@ -3040,11 +3147,13 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
else {
p = op->customdata;
}
+ /* Init random settings. */
+ ED_gpencil_init_random_settings(p->brush, event->mval, &p->random_settings);
/* TODO: set any additional settings that we can take from the events?
* if eraser is on, draw radial aid */
if (p->paintmode == GP_PAINTMODE_ERASER) {
- gpencil_draw_toggle_eraser_cursor(C, p, true);
+ gpencil_draw_toggle_eraser_cursor(p, true);
}
else {
ED_gpencil_toggle_brush_cursor(C, true, NULL);
@@ -3094,10 +3203,10 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
-static bool gpencil_area_exists(bContext *C, ScrArea *sa_test)
+static bool gpencil_area_exists(bContext *C, ScrArea *area_test)
{
- bScreen *sc = CTX_wm_screen(C);
- return (BLI_findindex(&sc->areabase, sa_test) != -1);
+ bScreen *screen = CTX_wm_screen(C);
+ return (BLI_findindex(&screen->areabase, area_test) != -1);
}
static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
@@ -3107,7 +3216,7 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
/* we must check that we're still within the area that we're set up to work from
* otherwise we could crash (see bug #20586)
*/
- if (CTX_wm_area(C) != p->sa) {
+ if (CTX_wm_area(C) != p->area) {
printf("\t\t\tGP - wrong area execution abort!\n");
p->status = GP_STATUS_ERROR;
}
@@ -3125,6 +3234,30 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
return op->customdata;
}
+/* Apply pressure change depending of the angle of the stroke for a segment. */
+static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *pt)
+{
+ Brush *brush = p->brush;
+ /* Sensitivity. */
+ const float sen = brush->gpencil_settings->draw_angle_factor;
+ /* Default angle of brush in radians */
+ const float angle = brush->gpencil_settings->draw_angle;
+
+ float mvec[2];
+ float fac;
+
+ /* angle vector of the brush with full thickness */
+ float v0[2] = {cos(angle), sin(angle)};
+
+ mvec[0] = pt->x - pt_prev->x;
+ mvec[1] = pt->y - pt_prev->y;
+ normalize_v2(mvec);
+ fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */
+ /* interpolate with previous point for smoother transitions */
+ pt->pressure = interpf(pt->pressure - (sen * fac), pt_prev->pressure, 0.3f);
+ CLAMP(pt->pressure, GPENCIL_ALPHA_OPACITY_THRESH, 1.0f);
+}
+
/* Add arc points between two mouse events using the previous segment to determine the vertice of
* the arc.
* /+ CTL
@@ -3139,10 +3272,17 @@ static tGPsdata *gpencil_stroke_begin(bContext *C, wmOperator *op)
static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
{
bGPdata *gpd = p->gpd;
+ BrushGpencilSettings *brush_settings = p->brush->gpencil_settings;
+
if (gpd->runtime.sbuffer_used < 3) {
+ tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
+ /* Apply other randomness to first points. */
+ for (int i = 0; i < gpd->runtime.sbuffer_used; i++) {
+ tGPspoint *pt = &points[i];
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
+ }
return;
}
-
int idx_prev = gpd->runtime.sbuffer_used;
/* Add space for new arc points. */
@@ -3197,7 +3337,9 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
corner[0] = midpoint[0] - (cp1[0] - midpoint[0]);
corner[1] = midpoint[1] - (cp1[1] - midpoint[1]);
+ float stepcolor = 1.0f / segments;
+ tGPspoint *pt_step = pt_prev;
for (int i = 0; i < segments; i++) {
pt = &points[idx_prev + i - 1];
pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a);
@@ -3206,6 +3348,20 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments)
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_prev->pressure;
pt->strength = pt_prev->strength;
+ /* Interpolate vertex color. */
+ interp_v4_v4v4(
+ pt->vert_color, pt_before->vert_color, pt_prev->vert_color, stepcolor * (i + 1));
+
+ /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */
+ if (brush_settings->draw_angle_factor != 0.0f) {
+ gp_brush_angle_segment(p, pt_step, pt);
+ CLAMP(pt->pressure, pt_prev->pressure * 0.5f, 1.0f);
+ /* Use the previous interpolated point for next segment. */
+ pt_step = pt;
+ }
+
+ /* Apply other randomness. */
+ gp_apply_randomness(p, brush_settings, pt, false, false, true);
a += step;
}
@@ -3257,6 +3413,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
else {
@@ -3273,6 +3430,7 @@ static void gpencil_add_guide_points(const tGPsdata *p,
/* Set pressure and strength equals to previous. It will be smoothed later. */
pt->pressure = pt_before->pressure;
pt->strength = pt_before->strength;
+ copy_v4_v4(pt->vert_color, pt_before->vert_color);
}
}
}
@@ -3481,18 +3639,19 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
*/
if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
/* Change to whatever region is now under the mouse */
- ARegion *current_region = BKE_area_find_region_xy(p->sa, RGN_TYPE_ANY, event->x, event->y);
+ ARegion *current_region = BKE_area_find_region_xy(
+ p->area, RGN_TYPE_ANY, event->x, event->y);
if (G.debug & G_DEBUG) {
- printf("found alternative region %p (old was %p) - at %d %d (sa: %d %d -> %d %d)\n",
+ printf("found alternative region %p (old was %p) - at %d %d (area: %d %d -> %d %d)\n",
current_region,
p->region,
event->x,
event->y,
- p->sa->totrct.xmin,
- p->sa->totrct.ymin,
- p->sa->totrct.xmax,
- p->sa->totrct.ymax);
+ p->area->totrct.xmin,
+ p->area->totrct.ymin,
+ p->area->totrct.xmax,
+ p->area->totrct.ymax);
}
if (current_region) {
@@ -3540,7 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
p->paintmode = RNA_enum_get(op->ptr, "mode");
}
- gpencil_draw_toggle_eraser_cursor(C, p, p->paintmode == GP_PAINTMODE_ERASER);
+ gpencil_draw_toggle_eraser_cursor(p, p->paintmode == GP_PAINTMODE_ERASER);
/* not painting, so start stroke (this should be mouse-button down) */
p = gpencil_stroke_begin(C, op);
@@ -3637,7 +3796,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
- if (0 == gpencil_area_exists(C, p->sa)) {
+ if (0 == gpencil_area_exists(C, p->area)) {
estate = OPERATOR_CANCELLED;
}
else {