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_brush.c')
-rw-r--r--source/blender/editors/gpencil/gpencil_brush.c3502
1 files changed, 1736 insertions, 1766 deletions
diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c
index 8f64ec1c868..ef0ebd06d07 100644
--- a/source/blender/editors/gpencil/gpencil_brush.c
+++ b/source/blender/editors/gpencil/gpencil_brush.c
@@ -22,7 +22,6 @@
* \ingroup edgpencil
*/
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -86,145 +85,133 @@
/* Context for brush operators */
typedef struct tGP_BrushEditData {
- /* Current editor/region/etc. */
- /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
- Depsgraph *depsgraph;
- Scene *scene;
- Object *object;
-
- ScrArea *sa;
- ARegion *ar;
-
- /* Current GPencil datablock */
- bGPdata *gpd;
+ /* Current editor/region/etc. */
+ /* NOTE: This stuff is mainly needed to handle 3D view projection stuff... */
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Object *object;
- /* Brush Settings */
- GP_Sculpt_Settings *settings;
- GP_Sculpt_Data *gp_brush;
- GP_Sculpt_Data *gp_brush_old;
+ ScrArea *sa;
+ ARegion *ar;
- eGP_Sculpt_Types brush_type;
- eGP_Sculpt_Types brush_type_old;
- eGP_Sculpt_Flag flag;
+ /* Current GPencil datablock */
+ bGPdata *gpd;
- /* Space Conversion Data */
- GP_SpaceConversion gsc;
+ /* Brush Settings */
+ GP_Sculpt_Settings *settings;
+ GP_Sculpt_Data *gp_brush;
+ GP_Sculpt_Data *gp_brush_old;
+ eGP_Sculpt_Types brush_type;
+ eGP_Sculpt_Types brush_type_old;
+ eGP_Sculpt_Flag flag;
- /* Is the brush currently painting? */
- bool is_painting;
- bool is_weight_mode;
+ /* Space Conversion Data */
+ GP_SpaceConversion gsc;
- /* Start of new sculpt stroke */
- bool first;
+ /* Is the brush currently painting? */
+ bool is_painting;
+ bool is_weight_mode;
- /* Is multiframe editing enabled, and are we using falloff for that? */
- bool is_multiframe;
- bool use_multiframe_falloff;
+ /* Start of new sculpt stroke */
+ bool first;
- /* Current frame */
- int cfra;
+ /* Is multiframe editing enabled, and are we using falloff for that? */
+ bool is_multiframe;
+ bool use_multiframe_falloff;
+ /* Current frame */
+ int cfra;
- /* Brush Runtime Data: */
- /* - position and pressure
- * - the *_prev variants are the previous values
- */
- float mval[2], mval_prev[2];
- float pressure, pressure_prev;
+ /* Brush Runtime Data: */
+ /* - position and pressure
+ * - the *_prev variants are the previous values
+ */
+ float mval[2], mval_prev[2];
+ float pressure, pressure_prev;
- /* - effect vector (e.g. 2D/3D translation for grab brush) */
- float dvec[3];
+ /* - effect vector (e.g. 2D/3D translation for grab brush) */
+ float dvec[3];
- /* - multiframe falloff factor */
- float mf_falloff;
+ /* - multiframe falloff factor */
+ float mf_falloff;
- /* active vertex group */
- int vrgroup;
+ /* active vertex group */
+ int vrgroup;
+ /* brush geometry (bounding box) */
+ rcti brush_rect;
- /* brush geometry (bounding box) */
- rcti brush_rect;
+ /* Custom data for certain brushes */
+ /* - map from bGPDstroke's to structs containing custom data about those strokes */
+ GHash *stroke_customdata;
+ /* - general customdata */
+ void *customdata;
- /* Custom data for certain brushes */
- /* - map from bGPDstroke's to structs containing custom data about those strokes */
- GHash *stroke_customdata;
- /* - general customdata */
- void *customdata;
+ /* Timer for in-place accumulation of brush effect */
+ wmTimer *timer;
+ bool timerTick; /* is this event from a timer */
-
- /* Timer for in-place accumulation of brush effect */
- wmTimer *timer;
- bool timerTick; /* is this event from a timer */
-
- RNG *rng;
+ RNG *rng;
} tGP_BrushEditData;
-
/* Callback for performing some brush operation on a single point */
typedef bool (*GP_BrushApplyCb)(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2]);
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2]);
/* ************************************************ */
/* Utility Functions */
/* apply lock axis reset */
-static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3])
+static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso,
+ bGPDspoint *pt,
+ const float save_pt[3])
{
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- return;
- }
-
- const ToolSettings *ts = gso->scene->toolsettings;
- const View3DCursor *cursor = &gso->scene->cursor;
- const int axis = ts->gp_sculpt.lock_axis;
-
- /* lock axis control */
- 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;
- }
- }
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ return;
+ }
+
+ const ToolSettings *ts = gso->scene->toolsettings;
+ const View3DCursor *cursor = &gso->scene->cursor;
+ const int axis = ts->gp_sculpt.lock_axis;
+
+ /* lock axis control */
+ 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;
+ }
+ }
}
/* Context ---------------------------------------- */
@@ -232,22 +219,22 @@ static void gpsculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, c
/* Get the sculpting settings */
static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene)
{
- return &scene->toolsettings->gp_sculpt;
+ return &scene->toolsettings->gp_sculpt;
}
/* Get the active brush */
static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
{
- GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
- GP_Sculpt_Data *gp_brush = NULL;
- if (is_weight_mode) {
- gp_brush = &gset->brush[gset->weighttype];
- }
- else {
- gp_brush = &gset->brush[gset->brushtype];
- }
-
- return gp_brush;
+ GP_Sculpt_Settings *gset = &scene->toolsettings->gp_sculpt;
+ GP_Sculpt_Data *gp_brush = NULL;
+ if (is_weight_mode) {
+ gp_brush = &gset->brush[gset->weighttype];
+ }
+ else {
+ gp_brush = &gset->brush[gset->brushtype];
+ }
+
+ return gp_brush;
}
/* Brush Operations ------------------------------- */
@@ -255,56 +242,56 @@ static GP_Sculpt_Data *gpsculpt_get_brush(Scene *scene, bool is_weight_mode)
/* Invert behavior of brush? */
static bool gp_brush_invert_check(tGP_BrushEditData *gso)
{
- /* The basic setting is the brush's setting (from the panel) */
- bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
-
- /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
- if (gso->flag & GP_SCULPT_FLAG_INVERT) {
- invert ^= true;
- }
-
- /* set temporary status */
- if (invert) {
- gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
- }
- else {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
- }
-
- return invert;
+ /* The basic setting is the brush's setting (from the panel) */
+ bool invert = ((gso->gp_brush->flag & GP_SCULPT_FLAG_INVERT) != 0);
+
+ /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
+ if (gso->flag & GP_SCULPT_FLAG_INVERT) {
+ invert ^= true;
+ }
+
+ /* set temporary status */
+ if (invert) {
+ gso->gp_brush->flag |= GP_SCULPT_FLAG_TMP_INVERT;
+ }
+ else {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+ }
+
+ return invert;
}
/* Compute strength of effect */
static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
{
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
- /* basic strength factor from brush settings */
- float influence = gp_brush->strength;
+ /* basic strength factor from brush settings */
+ float influence = gp_brush->strength;
- /* use pressure? */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
- influence *= gso->pressure;
- }
+ /* use pressure? */
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_PRESSURE) {
+ influence *= gso->pressure;
+ }
- /* distance fading */
- if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- int mval_i[2];
- round_v2i_v2fl(mval_i, gso->mval);
- float distance = (float)len_v2v2_int(mval_i, co);
- float fac;
+ /* distance fading */
+ if (gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ float distance = (float)len_v2v2_int(mval_i, co);
+ float fac;
- CLAMP(distance, 0.0f, (float)radius);
- fac = 1.0f - (distance / (float)radius);
+ CLAMP(distance, 0.0f, (float)radius);
+ fac = 1.0f - (distance / (float)radius);
- influence *= fac;
- }
+ influence *= fac;
+ }
- /* apply multiframe falloff */
- influence *= gso->mf_falloff;
+ /* apply multiframe falloff */
+ influence *= gso->mf_falloff;
- /* return influence */
- return influence;
+ /* return influence */
+ return influence;
}
/* ************************************************ */
@@ -318,38 +305,34 @@ static float gp_brush_influence_calc(tGP_BrushEditData *gso, const int radius, c
/* A simple (but slower + inaccurate) smooth-brush implementation to test the algorithm for stroke smoothing */
static bool gp_brush_smooth_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- // GP_Sculpt_Data *gp_brush = gso->brush;
- float inf = gp_brush_influence_calc(gso, radius, co);
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
- GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
- GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
- {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
-
- /* perform smoothing */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
- BKE_gpencil_smooth_stroke(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
- BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
- }
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
- BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- return true;
+ // GP_Sculpt_Data *gp_brush = gso->brush;
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ /* need one flag enabled by default */
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
+ }
+
+ /* perform smoothing */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ BKE_gpencil_smooth_stroke(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ BKE_gpencil_smooth_stroke_thickness(gps, pt_index, inf);
+ }
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ BKE_gpencil_smooth_stroke_uv(gps, pt_index, inf);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ return true;
}
/* ----------------------------------------------- */
@@ -357,77 +340,73 @@ static bool gp_brush_smooth_apply(
/* Make lines thicker or thinner by the specified amounts */
static bool gp_brush_thickness_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
-
- /* apply */
- // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
- if (gp_brush_invert_check(gso)) {
- /* make line thinner - reduce stroke pressure */
- pt->pressure -= inf;
- }
- else {
- /* make line thicker - increase stroke pressure */
- pt->pressure += inf;
- }
-
- /* Pressure should stay within [0.0, 1.0]
- * However, it is nice for volumetric strokes to be able to exceed
- * the upper end of this range. Therefore, we don't actually clamp
- * down on the upper end.
- */
- if (pt->pressure < 0.0f)
- pt->pressure = 0.0f;
-
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* apply */
+ // XXX: this is much too strong, and it should probably do some smoothing with the surrounding stuff
+ if (gp_brush_invert_check(gso)) {
+ /* make line thinner - reduce stroke pressure */
+ pt->pressure -= inf;
+ }
+ else {
+ /* make line thicker - increase stroke pressure */
+ pt->pressure += inf;
+ }
+
+ /* Pressure should stay within [0.0, 1.0]
+ * However, it is nice for volumetric strokes to be able to exceed
+ * the upper end of this range. Therefore, we don't actually clamp
+ * down on the upper end.
+ */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
}
-
/* ----------------------------------------------- */
/* Color Strength Brush */
/* Make color more or less transparent by the specified amounts */
static bool gp_brush_strength_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
-
- /* apply */
- if (gp_brush_invert_check(gso)) {
- /* make line more transparent - reduce alpha factor */
- pt->strength -= inf;
- }
- else {
- /* make line more opaque - increase stroke strength */
- pt->strength += inf;
- }
- /* smooth the strength */
- BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
-
- /* Strength should stay within [0.0, 1.0] */
- CLAMP(pt->strength, 0.0f, 1.0f);
-
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 20.0f;
+
+ /* apply */
+ if (gp_brush_invert_check(gso)) {
+ /* make line more transparent - reduce alpha factor */
+ pt->strength -= inf;
+ }
+ else {
+ /* make line more opaque - increase stroke strength */
+ pt->strength += inf;
+ }
+ /* smooth the strength */
+ BKE_gpencil_smooth_stroke_strength(gps, pt_index, inf);
+
+ /* Strength should stay within [0.0, 1.0] */
+ CLAMP(pt->strength, 0.0f, 1.0f);
+
+ return true;
}
-
/* ----------------------------------------------- */
/* Grab Brush */
@@ -438,145 +417,145 @@ static bool gp_brush_strength_apply(
* the brush region.
*/
typedef struct tGPSB_Grab_StrokeData {
- /* array of indices to corresponding points in the stroke */
- int *points;
- /* array of influence weights for each of the included points */
- float *weights;
-
- /* capacity of the arrays */
- int capacity;
- /* actual number of items currently stored */
- int size;
+ /* array of indices to corresponding points in the stroke */
+ int *points;
+ /* array of influence weights for each of the included points */
+ float *weights;
+
+ /* capacity of the arrays */
+ int capacity;
+ /* actual number of items currently stored */
+ int size;
} tGPSB_Grab_StrokeData;
/* initialise custom data for handling this stroke */
static void gp_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
{
- tGPSB_Grab_StrokeData *data = NULL;
+ tGPSB_Grab_StrokeData *data = NULL;
- BLI_assert(gps->totpoints > 0);
+ BLI_assert(gps->totpoints > 0);
- /* Check if there are buffers already (from a prior run) */
- if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
- /* Ensure that the caches are empty
- * - Since we reuse these between different strokes, we don't
- * want the previous invocation's data polluting the arrays
- */
- data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- BLI_assert(data != NULL);
+ /* Check if there are buffers already (from a prior run) */
+ if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
+ /* Ensure that the caches are empty
+ * - Since we reuse these between different strokes, we don't
+ * want the previous invocation's data polluting the arrays
+ */
+ data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ BLI_assert(data != NULL);
- data->size = 0; /* minimum requirement - so that we can repopulate again */
+ data->size = 0; /* minimum requirement - so that we can repopulate again */
- memset(data->points, 0, sizeof(int) * data->capacity);
- memset(data->weights, 0, sizeof(float) * data->capacity);
- }
- else {
- /* Create new instance */
- data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
+ memset(data->points, 0, sizeof(int) * data->capacity);
+ memset(data->weights, 0, sizeof(float) * data->capacity);
+ }
+ else {
+ /* Create new instance */
+ data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
- data->capacity = gps->totpoints;
- data->size = 0;
+ data->capacity = gps->totpoints;
+ data->size = 0;
- data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
- data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
+ data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
+ data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
- /* hook up to the cache */
- BLI_ghash_insert(gso->stroke_customdata, gps, data);
- }
+ /* hook up to the cache */
+ BLI_ghash_insert(gso->stroke_customdata, gps, data);
+ }
}
/* store references to stroke points in the initial stage */
static bool gp_brush_grab_store_points(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- float inf = gp_brush_influence_calc(gso, radius, co);
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ float inf = gp_brush_influence_calc(gso, radius, co);
- BLI_assert(data != NULL);
- BLI_assert(data->size < data->capacity);
+ BLI_assert(data != NULL);
+ BLI_assert(data->size < data->capacity);
- /* insert this point into the set of affected points */
- data->points[data->size] = pt_index;
- data->weights[data->size] = inf;
- data->size++;
+ /* insert this point into the set of affected points */
+ data->points[data->size] = pt_index;
+ data->weights[data->size] = inf;
+ data->size++;
- /* done */
- return true;
+ /* done */
+ return true;
}
/* Compute effect vector for grab brush */
static void gp_brush_grab_calc_dvec(tGP_BrushEditData *gso)
{
- /* Convert mouse-movements to movement vector */
- // TODO: incorporate pressure into this?
- // XXX: screen-space strokes in 3D space will suffer!
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = gso->ar->regiondata;
- float *rvec = gso->scene->cursor.location;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
-
- /* convert from 2D screenspace to 3D... */
- mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
- }
- else {
- /* 2D - just copy */
- // XXX: view2d?
- gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
- gso->dvec[2] = 0.0f; /* unused */
- }
+ /* Convert mouse-movements to movement vector */
+ // TODO: incorporate pressure into this?
+ // XXX: screen-space strokes in 3D space will suffer!
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float *rvec = gso->scene->cursor.location;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+
+ /* convert from 2D screenspace to 3D... */
+ mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ ED_view3d_win_to_delta(gso->ar, mval_f, gso->dvec, zfac);
+ }
+ else {
+ /* 2D - just copy */
+ // XXX: view2d?
+ gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+ gso->dvec[2] = 0.0f; /* unused */
+ }
}
/* Apply grab transform to all relevant points of the affected strokes */
-static void gp_brush_grab_apply_cached(
- tGP_BrushEditData *gso, bGPDstroke *gps, float diff_mat[4][4])
+static void gp_brush_grab_apply_cached(tGP_BrushEditData *gso,
+ bGPDstroke *gps,
+ float diff_mat[4][4])
{
- tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
- int i;
-
- /* Apply dvec to all of the stored points */
- for (i = 0; i < data->size; i++) {
- bGPDspoint *pt = &gps->points[data->points[i]];
- float delta[3] = {0.0f};
-
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
-
- float fpt[3];
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
- /* apply transformation */
- mul_v3_m4v3(fpt, diff_mat, &pt->x);
- /* apply */
- add_v3_v3v3(&pt->x, fpt, delta);
- /* undo transformation to the init parent position */
- float inverse_diff_mat[4][4];
- invert_m4_m4(inverse_diff_mat, diff_mat);
- mul_m4_v3(inverse_diff_mat, &pt->x);
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ tGPSB_Grab_StrokeData *data = BLI_ghash_lookup(gso->stroke_customdata, gps);
+ int i;
+
+ /* Apply dvec to all of the stored points */
+ for (i = 0; i < data->size; i++) {
+ bGPDspoint *pt = &gps->points[data->points[i]];
+ float delta[3] = {0.0f};
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
+
+ float fpt[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+ /* apply transformation */
+ mul_v3_m4v3(fpt, diff_mat, &pt->x);
+ /* apply */
+ add_v3_v3v3(&pt->x, fpt, delta);
+ /* undo transformation to the init parent position */
+ float inverse_diff_mat[4][4];
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
}
/* free customdata used for handling this stroke */
static void gp_brush_grab_stroke_free(void *ptr)
{
- tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
+ tGPSB_Grab_StrokeData *data = (tGPSB_Grab_StrokeData *)ptr;
- /* free arrays */
- MEM_freeN(data->points);
- MEM_freeN(data->weights);
+ /* free arrays */
+ MEM_freeN(data->points);
+ MEM_freeN(data->weights);
- /* ... and this item itself, since it was also allocated */
- MEM_freeN(data);
+ /* ... and this item itself, since it was also allocated */
+ MEM_freeN(data);
}
/* ----------------------------------------------- */
@@ -584,29 +563,28 @@ static void gp_brush_grab_stroke_free(void *ptr)
/* NOTE: Depends on gp_brush_grab_calc_dvec() */
static bool gp_brush_push_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
- float inf = gp_brush_influence_calc(gso, radius, co);
- float delta[3] = {0.0f};
+ float inf = gp_brush_influence_calc(gso, radius, co);
+ float delta[3] = {0.0f};
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, inf);
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, inf);
- /* apply */
- add_v3_v3(&pt->x, delta);
+ /* apply */
+ add_v3_v3(&pt->x, delta);
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- /* done */
- return true;
+ /* done */
+ return true;
}
/* ----------------------------------------------- */
@@ -615,84 +593,83 @@ static bool gp_brush_push_apply(
/* Compute reference midpoint for the brush - this is what we'll be moving towards */
static void gp_brush_calc_midpoint(tGP_BrushEditData *gso)
{
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- /* Convert mouse position to 3D space
- * See: gpencil_paint.c :: gp_stroke_convertcoords()
- */
- RegionView3D *rv3d = gso->ar->regiondata;
- const float *rvec = gso->scene->cursor.location;
- float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
-
- float mval_f[2];
- copy_v2_v2(mval_f, gso->mval);
- float mval_prj[2];
- float dvec[3];
-
-
- if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
- sub_v2_v2v2(mval_f, mval_prj, mval_f);
- ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
- sub_v3_v3v3(gso->dvec, rvec, dvec);
- }
- else {
- zero_v3(gso->dvec);
- }
- }
- else {
- /* Just 2D coordinates */
- // XXX: fix View2D offsets later
- gso->dvec[0] = (float)gso->mval[0];
- gso->dvec[1] = (float)gso->mval[1];
- gso->dvec[2] = 0.0f;
- }
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ /* Convert mouse position to 3D space
+ * See: gpencil_paint.c :: gp_stroke_convertcoords()
+ */
+ RegionView3D *rv3d = gso->ar->regiondata;
+ const float *rvec = gso->scene->cursor.location;
+ float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
+
+ float mval_f[2];
+ copy_v2_v2(mval_f, gso->mval);
+ float mval_prj[2];
+ float dvec[3];
+
+ if (ED_view3d_project_float_global(gso->ar, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
+ V3D_PROJ_RET_OK) {
+ sub_v2_v2v2(mval_f, mval_prj, mval_f);
+ ED_view3d_win_to_delta(gso->ar, mval_f, dvec, zfac);
+ sub_v3_v3v3(gso->dvec, rvec, dvec);
+ }
+ else {
+ zero_v3(gso->dvec);
+ }
+ }
+ else {
+ /* Just 2D coordinates */
+ // XXX: fix View2D offsets later
+ gso->dvec[0] = (float)gso->mval[0];
+ gso->dvec[1] = (float)gso->mval[1];
+ gso->dvec[2] = 0.0f;
+ }
}
/* Shrink distance between midpoint and this point... */
static bool gp_brush_pinch_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float fac, inf;
- float vec[3];
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Scale down standard influence value to get it more manageable...
- * - No damping = Unmanageable at > 0.5 strength
- * - Div 10 = Not enough effect
- * - Div 5 = Happy medium... (by trial and error)
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
-
- /* 1) Make this point relative to the cursor/midpoint (dvec) */
- sub_v3_v3v3(vec, &pt->x, gso->dvec);
-
- /* 2) Shrink the distance by pulling the point towards the midpoint
- * (0.0 = at midpoint, 1 = at edge of brush region)
- * OR
- * Increase the distance (if inverting the brush action!)
- */
- if (gp_brush_invert_check(gso)) {
- /* Inflate (inverse) */
- fac = 1.0f + (inf * inf); /* squared to temper the effect... */
- }
- else {
- /* Shrink (default) */
- fac = 1.0f - (inf * inf); /* squared to temper the effect... */
- }
- mul_v3_fl(vec, fac);
-
- /* 3) Translate back to original space, with the shrinkage applied */
- add_v3_v3v3(&pt->x, gso->dvec, vec);
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float fac, inf;
+ float vec[3];
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Scale down standard influence value to get it more manageable...
+ * - No damping = Unmanageable at > 0.5 strength
+ * - Div 10 = Not enough effect
+ * - Div 5 = Happy medium... (by trial and error)
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 5.0f;
+
+ /* 1) Make this point relative to the cursor/midpoint (dvec) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec);
+
+ /* 2) Shrink the distance by pulling the point towards the midpoint
+ * (0.0 = at midpoint, 1 = at edge of brush region)
+ * OR
+ * Increase the distance (if inverting the brush action!)
+ */
+ if (gp_brush_invert_check(gso)) {
+ /* Inflate (inverse) */
+ fac = 1.0f + (inf * inf); /* squared to temper the effect... */
+ }
+ else {
+ /* Shrink (default) */
+ fac = 1.0f - (inf * inf); /* squared to temper the effect... */
+ }
+ mul_v3_fl(vec, fac);
+
+ /* 3) Translate back to original space, with the shrinkage applied */
+ add_v3_v3v3(&pt->x, gso->dvec, vec);
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
/* ----------------------------------------------- */
@@ -703,268 +680,259 @@ static bool gp_brush_pinch_apply(
*/
static bool gp_brush_twist_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float angle, inf;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Angle to rotate by */
- inf = gp_brush_influence_calc(gso, radius, co);
- angle = DEG2RADF(1.0f) * inf;
-
- if (gp_brush_invert_check(gso)) {
- /* invert angle that we rotate by */
- angle *= -1;
- }
-
- /* Rotate in 2D or 3D space? */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* Perform rotation in 3D space... */
- RegionView3D *rv3d = gso->ar->regiondata;
- float rmat[3][3];
- float axis[3];
- float vec[3];
-
- /* Compute rotation matrix - rotate around view vector by angle */
- negate_v3_v3(axis, rv3d->persinv[2]);
- normalize_v3(axis);
-
- axis_angle_normalized_to_mat3(rmat, axis, angle);
-
- /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
- sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center
- * (center is stored in dvec) */
- mul_m3_v3(rmat, vec);
- add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
-
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- else {
- const float axis[3] = {0.0f, 0.0f, 1.0f};
- float vec[3] = {0.0f};
- float rmat[3][3];
-
- /* Express position of point relative to cursor, ready to rotate */
- // XXX: There is still some offset here, but it's close to working as expected...
- vec[0] = (float)(co[0] - gso->mval[0]);
- vec[1] = (float)(co[1] - gso->mval[1]);
-
- /* rotate point */
- axis_angle_normalized_to_mat3(rmat, axis, angle);
- mul_m3_v3(rmat, vec);
-
- /* Convert back to screen-coordinates */
- vec[0] += (float)gso->mval[0];
- vec[1] += (float)gso->mval[1];
-
- /* Map from screen-coordinates to final coordinate space */
- if (gps->flag & GP_STROKE_2DSPACE) {
- View2D *v2d = gso->gsc.v2d;
- UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
- }
- else {
- // XXX
- copy_v2_v2(&pt->x, vec);
- }
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float angle, inf;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Angle to rotate by */
+ inf = gp_brush_influence_calc(gso, radius, co);
+ angle = DEG2RADF(1.0f) * inf;
+
+ if (gp_brush_invert_check(gso)) {
+ /* invert angle that we rotate by */
+ angle *= -1;
+ }
+
+ /* Rotate in 2D or 3D space? */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* Perform rotation in 3D space... */
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float rmat[3][3];
+ float axis[3];
+ float vec[3];
+
+ /* Compute rotation matrix - rotate around view vector by angle */
+ negate_v3_v3(axis, rv3d->persinv[2]);
+ normalize_v3(axis);
+
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+
+ /* Rotate point (no matrix-space transforms needed, as GP points are in world space) */
+ sub_v3_v3v3(vec, &pt->x, gso->dvec); /* make relative to center
+ * (center is stored in dvec) */
+ mul_m3_v3(rmat, vec);
+ add_v3_v3v3(&pt->x, vec, gso->dvec); /* restore */
+
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ else {
+ const float axis[3] = {0.0f, 0.0f, 1.0f};
+ float vec[3] = {0.0f};
+ float rmat[3][3];
+
+ /* Express position of point relative to cursor, ready to rotate */
+ // XXX: There is still some offset here, but it's close to working as expected...
+ vec[0] = (float)(co[0] - gso->mval[0]);
+ vec[1] = (float)(co[1] - gso->mval[1]);
+
+ /* rotate point */
+ axis_angle_normalized_to_mat3(rmat, axis, angle);
+ mul_m3_v3(rmat, vec);
+
+ /* Convert back to screen-coordinates */
+ vec[0] += (float)gso->mval[0];
+ vec[1] += (float)gso->mval[1];
+
+ /* Map from screen-coordinates to final coordinate space */
+ if (gps->flag & GP_STROKE_2DSPACE) {
+ View2D *v2d = gso->gsc.v2d;
+ UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
+ }
+ else {
+ // XXX
+ copy_v2_v2(&pt->x, vec);
+ }
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
-
/* ----------------------------------------------- */
/* Randomize Brush */
/* Apply some random jitter to the point */
static bool gp_brush_randomize_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- bGPDspoint *pt = gps->points + pt_index;
- float save_pt[3];
- copy_v3_v3(save_pt, &pt->x);
-
- /* Amount of jitter to apply depends on the distance of the point to the cursor,
- * as well as the strength of the brush
- */
- const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
- const float fac = BLI_rng_get_float(gso->rng) * inf;
- /* need one flag enabled by default */
- if ((gso->settings->flag &
- (GP_SCULPT_SETT_FLAG_APPLY_POSITION |
- GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
- GP_SCULPT_SETT_FLAG_APPLY_THICKNESS |
- GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0)
- {
- gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
- }
-
- /* apply random to position */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
- /* Jitter is applied perpendicular to the mouse movement vector
- * - We compute all effects in screenspace (since it's easier)
- * and then project these to get the points/distances in
- * view-space as needed.
- */
- float mvec[2], svec[2];
-
- /* mouse movement in ints -> floats */
- mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
- mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
-
- /* rotate mvec by 90 degrees... */
- svec[0] = -mvec[1];
- svec[1] = mvec[0];
-
- /* scale the displacement by the random displacement, and apply */
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- mul_v2_fl(svec, -fac);
- }
- else {
- mul_v2_fl(svec, fac);
- }
-
- //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
-
- /* convert to dataspace */
- if (gps->flag & GP_STROKE_3DSPACE) {
- /* 3D: Project to 3D space */
- if (gso->sa->spacetype == SPACE_VIEW3D) {
- bool flip;
- RegionView3D *rv3d = gso->ar->regiondata;
- float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
- if (flip == false) {
- float dvec[3];
- ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
- add_v3_v3(&pt->x, dvec);
- /* compute lock axis */
- gpsculpt_compute_lock_axis(gso, pt, save_pt);
- }
- }
- else {
- /* ERROR */
- BLI_assert(!"3D stroke being sculpted in non-3D view");
- }
- }
- else {
- /* 2D: As-is */
- // XXX: v2d scaling/offset?
- float nco[2];
- nco[0] = (float)co[0] + svec[0];
- nco[1] = (float)co[1] + svec[1];
-
- copy_v2_v2(&pt->x, nco);
- }
- }
- /* apply random to strength */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->strength += fac;
- }
- else {
- pt->strength -= fac;
- }
- CLAMP_MIN(pt->strength, 0.0f);
- CLAMP_MAX(pt->strength, 1.0f);
- }
- /* apply random to thickness (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->pressure += fac;
- }
- else {
- pt->pressure -= fac;
- }
- /* only limit lower value */
- CLAMP_MIN(pt->pressure, 0.0f);
- }
- /* apply random to UV (use pressure) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
- if (BLI_rng_get_float(gso->rng) > 0.5f) {
- pt->uv_rot += fac;
- }
- else {
- pt->uv_rot -= fac;
- }
- CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
- }
-
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
-
- /* done */
- return true;
+ bGPDspoint *pt = gps->points + pt_index;
+ float save_pt[3];
+ copy_v3_v3(save_pt, &pt->x);
+
+ /* Amount of jitter to apply depends on the distance of the point to the cursor,
+ * as well as the strength of the brush
+ */
+ const float inf = gp_brush_influence_calc(gso, radius, co) / 2.0f;
+ const float fac = BLI_rng_get_float(gso->rng) * inf;
+ /* need one flag enabled by default */
+ if ((gso->settings->flag &
+ (GP_SCULPT_SETT_FLAG_APPLY_POSITION | GP_SCULPT_SETT_FLAG_APPLY_STRENGTH |
+ GP_SCULPT_SETT_FLAG_APPLY_THICKNESS | GP_SCULPT_SETT_FLAG_APPLY_UV)) == 0) {
+ gso->settings->flag |= GP_SCULPT_SETT_FLAG_APPLY_POSITION;
+ }
+
+ /* apply random to position */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_POSITION) {
+ /* Jitter is applied perpendicular to the mouse movement vector
+ * - We compute all effects in screenspace (since it's easier)
+ * and then project these to get the points/distances in
+ * view-space as needed.
+ */
+ float mvec[2], svec[2];
+
+ /* mouse movement in ints -> floats */
+ mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
+ mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
+
+ /* rotate mvec by 90 degrees... */
+ svec[0] = -mvec[1];
+ svec[1] = mvec[0];
+
+ /* scale the displacement by the random displacement, and apply */
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ mul_v2_fl(svec, -fac);
+ }
+ else {
+ mul_v2_fl(svec, fac);
+ }
+
+ //printf("%f %f (%f), nco = {%f %f}, co = %d %d\n", svec[0], svec[1], fac, nco[0], nco[1], co[0], co[1]);
+
+ /* convert to dataspace */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D: Project to 3D space */
+ if (gso->sa->spacetype == SPACE_VIEW3D) {
+ bool flip;
+ RegionView3D *rv3d = gso->ar->regiondata;
+ float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
+ if (flip == false) {
+ float dvec[3];
+ ED_view3d_win_to_delta(gso->gsc.ar, svec, dvec, zfac);
+ add_v3_v3(&pt->x, dvec);
+ /* compute lock axis */
+ gpsculpt_compute_lock_axis(gso, pt, save_pt);
+ }
+ }
+ else {
+ /* ERROR */
+ BLI_assert(!"3D stroke being sculpted in non-3D view");
+ }
+ }
+ else {
+ /* 2D: As-is */
+ // XXX: v2d scaling/offset?
+ float nco[2];
+ nco[0] = (float)co[0] + svec[0];
+ nco[1] = (float)co[1] + svec[1];
+
+ copy_v2_v2(&pt->x, nco);
+ }
+ }
+ /* apply random to strength */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_STRENGTH) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->strength += fac;
+ }
+ else {
+ pt->strength -= fac;
+ }
+ CLAMP_MIN(pt->strength, 0.0f);
+ CLAMP_MAX(pt->strength, 1.0f);
+ }
+ /* apply random to thickness (use pressure) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_THICKNESS) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->pressure += fac;
+ }
+ else {
+ pt->pressure -= fac;
+ }
+ /* only limit lower value */
+ CLAMP_MIN(pt->pressure, 0.0f);
+ }
+ /* apply random to UV (use pressure) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_APPLY_UV) {
+ if (BLI_rng_get_float(gso->rng) > 0.5f) {
+ pt->uv_rot += fac;
+ }
+ else {
+ pt->uv_rot -= fac;
+ }
+ CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
+ }
+
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ /* done */
+ return true;
}
/* Weight Paint Brush */
/* Change weight paint for vertex groups */
static bool gp_brush_weight_apply(
- tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index,
- const int radius, const int co[2])
+ tGP_BrushEditData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
{
- /* create dvert */
- BKE_gpencil_dvert_ensure(gps);
-
- bGPDspoint *pt = gps->points + pt_index;
- MDeformVert *dvert = gps->dvert + pt_index;
- float inf;
-
- /* Compute strength of effect
- * - We divide the strength by 10, so that users can set "sane" values.
- * Otherwise, good default values are in the range of 0.093
- */
- inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
-
- /* need a vertex group */
- if (gso->vrgroup == -1) {
- if (gso->object) {
- BKE_object_defgroup_add(gso->object);
- gso->vrgroup = 0;
- }
- }
- else {
- bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
- if (defgroup->flag & DG_LOCK_WEIGHT) {
- return false;
- }
- }
- /* get current weight */
- MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
- float curweight = dw ? dw->weight : 0.0f;
-
- if (gp_brush_invert_check(gso)) {
- /* reduce weight */
- curweight -= inf;
- }
- else {
- /* increase weight */
- curweight += inf;
- }
-
- /* verify target weight */
- CLAMP_MAX(curweight, gso->gp_brush->weight);
-
- CLAMP(curweight, 0.0f, 1.0f);
- if (dw) {
- dw->weight = curweight;
- }
-
- /* weight should stay within [0.0, 1.0] */
- if (pt->pressure < 0.0f)
- pt->pressure = 0.0f;
-
- return true;
+ /* create dvert */
+ BKE_gpencil_dvert_ensure(gps);
+
+ bGPDspoint *pt = gps->points + pt_index;
+ MDeformVert *dvert = gps->dvert + pt_index;
+ float inf;
+
+ /* Compute strength of effect
+ * - We divide the strength by 10, so that users can set "sane" values.
+ * Otherwise, good default values are in the range of 0.093
+ */
+ inf = gp_brush_influence_calc(gso, radius, co) / 10.0f;
+
+ /* need a vertex group */
+ if (gso->vrgroup == -1) {
+ if (gso->object) {
+ BKE_object_defgroup_add(gso->object);
+ gso->vrgroup = 0;
+ }
+ }
+ else {
+ bDeformGroup *defgroup = BLI_findlink(&gso->object->defbase, gso->vrgroup);
+ if (defgroup->flag & DG_LOCK_WEIGHT) {
+ return false;
+ }
+ }
+ /* get current weight */
+ MDeformWeight *dw = defvert_verify_index(dvert, gso->vrgroup);
+ float curweight = dw ? dw->weight : 0.0f;
+
+ if (gp_brush_invert_check(gso)) {
+ /* reduce weight */
+ curweight -= inf;
+ }
+ else {
+ /* increase weight */
+ curweight += inf;
+ }
+
+ /* verify target weight */
+ CLAMP_MAX(curweight, gso->gp_brush->weight);
+
+ CLAMP(curweight, 0.0f, 1.0f);
+ if (dw) {
+ dw->weight = curweight;
+ }
+
+ /* weight should stay within [0.0, 1.0] */
+ if (pt->pressure < 0.0f)
+ pt->pressure = 0.0f;
+
+ return true;
}
-
-
/* ************************************************ */
/* Non Callback-Based Brushes */
@@ -980,217 +948,218 @@ static bool gp_brush_weight_apply(
/* Custom state data for clone brush */
typedef struct tGPSB_CloneBrushData {
- /* midpoint of the strokes on the clipboard */
- float buffer_midpoint[3];
+ /* midpoint of the strokes on the clipboard */
+ float buffer_midpoint[3];
- /* number of strokes in the paste buffer (and/or to be created each time) */
- size_t totitems;
+ /* number of strokes in the paste buffer (and/or to be created each time) */
+ size_t totitems;
- /* for "stamp" mode, the currently pasted brushes */
- bGPDstroke **new_strokes;
+ /* for "stamp" mode, the currently pasted brushes */
+ bGPDstroke **new_strokes;
- /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
- GHash *new_colors;
+ /* mapping from colors referenced per stroke, to the new colours in the "pasted" strokes */
+ GHash *new_colors;
} tGPSB_CloneBrushData;
/* Initialise "clone" brush data */
static void gp_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data;
- bGPDstroke *gps;
-
- /* init custom data */
- gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
-
- /* compute midpoint of strokes on clipboard */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- const float dfac = 1.0f / ((float)gps->totpoints);
- float mid[3] = {0.0f};
-
- bGPDspoint *pt;
- int i;
-
- /* compute midpoint of this stroke */
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- float co[3];
-
- mul_v3_v3fl(co, &pt->x, dfac);
- add_v3_v3(mid, co);
- }
-
- /* combine this stroke's data with the main data */
- add_v3_v3(data->buffer_midpoint, mid);
- data->totitems++;
- }
- }
-
- /* Divide the midpoint by the number of strokes, to finish averaging it */
- if (data->totitems > 1) {
- mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
- }
-
- /* Create a buffer for storing the current strokes */
- if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
- data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems, "cloned strokes ptr array");
- }
-
- /* Init colormap for mapping between the pasted stroke's source color (names)
- * and the final colours that will be used here instead.
- */
- data->new_colors = gp_copybuf_validate_colormap(C);
+ tGPSB_CloneBrushData *data;
+ bGPDstroke *gps;
+
+ /* init custom data */
+ gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
+
+ /* compute midpoint of strokes on clipboard */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ const float dfac = 1.0f / ((float)gps->totpoints);
+ float mid[3] = {0.0f};
+
+ bGPDspoint *pt;
+ int i;
+
+ /* compute midpoint of this stroke */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float co[3];
+
+ mul_v3_v3fl(co, &pt->x, dfac);
+ add_v3_v3(mid, co);
+ }
+
+ /* combine this stroke's data with the main data */
+ add_v3_v3(data->buffer_midpoint, mid);
+ data->totitems++;
+ }
+ }
+
+ /* Divide the midpoint by the number of strokes, to finish averaging it */
+ if (data->totitems > 1) {
+ mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
+ }
+
+ /* Create a buffer for storing the current strokes */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems,
+ "cloned strokes ptr array");
+ }
+
+ /* Init colormap for mapping between the pasted stroke's source color (names)
+ * and the final colours that will be used here instead.
+ */
+ data->new_colors = gp_copybuf_validate_colormap(C);
}
/* Free custom data used for "clone" brush */
static void gp_brush_clone_free(tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
-
- /* free strokes array */
- if (data->new_strokes) {
- MEM_freeN(data->new_strokes);
- data->new_strokes = NULL;
- }
-
- /* free copybuf colormap */
- if (data->new_colors) {
- BLI_ghash_free(data->new_colors, NULL, NULL);
- data->new_colors = NULL;
- }
-
- /* free the customdata itself */
- MEM_freeN(data);
- gso->customdata = NULL;
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ /* free strokes array */
+ if (data->new_strokes) {
+ MEM_freeN(data->new_strokes);
+ data->new_strokes = NULL;
+ }
+
+ /* free copybuf colormap */
+ if (data->new_colors) {
+ BLI_ghash_free(data->new_colors, NULL, NULL);
+ data->new_colors = NULL;
+ }
+
+ /* free the customdata itself */
+ MEM_freeN(data);
+ gso->customdata = NULL;
}
/* Create new copies of the strokes on the clipboard */
static void gp_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
-
- Object *ob = CTX_data_active_object(C);
- bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- int cfra_eval = (int)DEG_get_ctime(depsgraph);
-
- bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
- bGPDstroke *gps;
-
- float delta[3];
- size_t strokes_added = 0;
-
- /* Compute amount to offset the points by */
- /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
-
- gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
- sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
-
- /* Copy each stroke into the layer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- bGPDstroke *new_stroke;
- bGPDspoint *pt;
- int i;
-
- /* Make a new stroke */
- new_stroke = MEM_dupallocN(gps);
-
- new_stroke->points = MEM_dupallocN(gps->points);
- if (gps->dvert != NULL) {
- new_stroke->dvert = MEM_dupallocN(gps->dvert);
- BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
- }
- new_stroke->triangles = MEM_dupallocN(gps->triangles);
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
-
- /* Fix color references */
- Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
- gps->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
- if (!ma || gps->mat_nr) {
- gps->mat_nr = 0;
- }
- /* Adjust all the stroke's points, so that the strokes
- * get pasted relative to where the cursor is now
- */
- for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
- /* assume that the delta can just be applied, and then everything works */
- add_v3_v3(&pt->x, delta);
- }
-
- /* Store ref for later */
- if ((data->new_strokes) && (strokes_added < data->totitems)) {
- data->new_strokes[strokes_added] = new_stroke;
- strokes_added++;
- }
- }
- }
+ tGPSB_CloneBrushData *data = gso->customdata;
+
+ Object *ob = CTX_data_active_object(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ int cfra_eval = (int)DEG_get_ctime(depsgraph);
+
+ bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW);
+ bGPDstroke *gps;
+
+ float delta[3];
+ size_t strokes_added = 0;
+
+ /* Compute amount to offset the points by */
+ /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
+
+ gp_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
+ sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
+
+ /* Copy each stroke into the layer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ bGPDstroke *new_stroke;
+ bGPDspoint *pt;
+ int i;
+
+ /* Make a new stroke */
+ new_stroke = MEM_dupallocN(gps);
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+ if (gps->dvert != NULL) {
+ new_stroke->dvert = MEM_dupallocN(gps->dvert);
+ BKE_gpencil_stroke_weights_duplicate(gps, new_stroke);
+ }
+ new_stroke->triangles = MEM_dupallocN(gps->triangles);
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+
+ /* Fix color references */
+ Material *ma = BLI_ghash_lookup(data->new_colors, &new_stroke->mat_nr);
+ gps->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
+ if (!ma || gps->mat_nr) {
+ gps->mat_nr = 0;
+ }
+ /* Adjust all the stroke's points, so that the strokes
+ * get pasted relative to where the cursor is now
+ */
+ for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
+ /* assume that the delta can just be applied, and then everything works */
+ add_v3_v3(&pt->x, delta);
+ }
+
+ /* Store ref for later */
+ if ((data->new_strokes) && (strokes_added < data->totitems)) {
+ data->new_strokes[strokes_added] = new_stroke;
+ strokes_added++;
+ }
+ }
+ }
}
/* Move newly-added strokes around - "Stamp" mode of the Clone brush */
static void gp_brush_clone_adjust(tGP_BrushEditData *gso)
{
- tGPSB_CloneBrushData *data = gso->customdata;
- size_t snum;
-
- /* Compute the amount of movement to apply (overwrites dvec) */
- gp_brush_grab_calc_dvec(gso);
-
- /* For each of the stored strokes, apply the offset to each point */
- /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */
- for (snum = 0; snum < data->totitems; snum++) {
- bGPDstroke *gps = data->new_strokes[snum];
- bGPDspoint *pt;
- int i;
-
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
- /* "Smudge" Effect when falloff is enabled */
- float delta[3] = {0.0f};
- int sco[2] = {0};
- float influence;
-
- /* compute influence on point */
- gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
- influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
-
- /* adjust the amount of displacement to apply */
- mul_v3_v3fl(delta, gso->dvec, influence);
-
- /* apply */
- add_v3_v3(&pt->x, delta);
- }
- else {
- /* Just apply the offset - All points move perfectly in sync with the cursor */
- add_v3_v3(&pt->x, gso->dvec);
- }
- }
- }
+ tGPSB_CloneBrushData *data = gso->customdata;
+ size_t snum;
+
+ /* Compute the amount of movement to apply (overwrites dvec) */
+ gp_brush_grab_calc_dvec(gso);
+
+ /* For each of the stored strokes, apply the offset to each point */
+ /* NOTE: Again this assumes that in the 3D view, we only have 3d space and not screenspace strokes... */
+ for (snum = 0; snum < data->totitems; snum++) {
+ bGPDstroke *gps = data->new_strokes[snum];
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ if (gso->gp_brush->flag & GP_SCULPT_FLAG_USE_FALLOFF) {
+ /* "Smudge" Effect when falloff is enabled */
+ float delta[3] = {0.0f};
+ int sco[2] = {0};
+ float influence;
+
+ /* compute influence on point */
+ gp_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
+ influence = gp_brush_influence_calc(gso, gso->gp_brush->size, sco);
+
+ /* adjust the amount of displacement to apply */
+ mul_v3_v3fl(delta, gso->dvec, influence);
+
+ /* apply */
+ add_v3_v3(&pt->x, delta);
+ }
+ else {
+ /* Just apply the offset - All points move perfectly in sync with the cursor */
+ add_v3_v3(&pt->x, gso->dvec);
+ }
+ }
+ }
}
/* Entrypoint for applying "clone" brush */
static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
{
- /* Which "mode" are we operating in? */
- if (gso->first) {
- /* Create initial clones */
- gp_brush_clone_add(C, gso);
- }
- else {
- /* Stamp or Continuous Mode */
- if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
- /* Stamp - Proceed to translate the newly added strokes */
- gp_brush_clone_adjust(gso);
- }
- else {
- /* Continuous - Just keep pasting everytime we move */
- /* TODO: The spacing of repeat should be controlled using a "stepsize" or similar property? */
- gp_brush_clone_add(C, gso);
- }
- }
-
- return true;
+ /* Which "mode" are we operating in? */
+ if (gso->first) {
+ /* Create initial clones */
+ gp_brush_clone_add(C, gso);
+ }
+ else {
+ /* Stamp or Continuous Mode */
+ if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
+ /* Stamp - Proceed to translate the newly added strokes */
+ gp_brush_clone_adjust(gso);
+ }
+ else {
+ /* Continuous - Just keep pasting everytime we move */
+ /* TODO: The spacing of repeat should be controlled using a "stepsize" or similar property? */
+ gp_brush_clone_add(C, gso);
+ }
+ }
+
+ return true;
}
/* ************************************************ */
@@ -1198,18 +1167,19 @@ static bool gpsculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
{
- const char *brush_name = NULL;
- char str[UI_MAX_DRAW_STR] = "";
+ const char *brush_name = NULL;
+ char str[UI_MAX_DRAW_STR] = "";
- RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
+ RNA_enum_name(rna_enum_gpencil_sculpt_brush_items, gso->brush_type, &brush_name);
- BLI_snprintf(str, sizeof(str),
- IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
- " | Ctrl to Invert Action | Wheel Up/Down for Size "
- " | Shift-Wheel Up/Down for Strength"),
- (brush_name) ? brush_name : "<?>");
+ BLI_snprintf(str,
+ sizeof(str),
+ IFACE_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
+ " | Ctrl to Invert Action | Wheel Up/Down for Size "
+ " | Shift-Wheel Up/Down for Strength"),
+ (brush_name) ? brush_name : "<?>");
- ED_workspace_status_text(C, str);
+ ED_workspace_status_text(C, str);
}
/* ************************************************ */
@@ -1219,586 +1189,576 @@ static void gpsculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
static bool gpsculpt_brush_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
- Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *ob = CTX_data_active_object(C);
- const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
- /* set the brush using the tool */
+ const bool is_weight_mode = ob->mode == OB_MODE_WEIGHT_GPENCIL;
+ /* set the brush using the tool */
#if 0
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ eGP_Sculpt_Types mode = is_weight_mode ? gset->weighttype : gset->brushtype;
#endif
- tGP_BrushEditData *gso;
-
- /* setup operator data */
- gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
- op->customdata = gso;
-
- gso->depsgraph = CTX_data_depsgraph(C);
- /* store state */
- gso->settings = gpsculpt_get_settings(scene);
- gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
- gso->is_weight_mode = is_weight_mode;
-
- if (is_weight_mode) {
- gso->brush_type = gso->settings->weighttype;
- }
- else {
- gso->brush_type = gso->settings->brushtype;
- }
-
- /* Random generator, only init once. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= POINTER_AS_UINT(gso);
- gso->rng = BLI_rng_new(rng_seed);
-
- gso->is_painting = false;
- gso->first = true;
-
- gso->gpd = ED_gpencil_data_get_active(C);
- gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
-
- /* some brushes cannot use pressure for radius */
- if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
- }
-
- gso->scene = scene;
- gso->object = ob;
- if (ob) {
- gso->vrgroup = ob->actdef - 1;
- if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
- gso->vrgroup = -1;
- }
- }
- else {
- gso->vrgroup = - 1;
- }
-
- gso->sa = CTX_wm_area(C);
- gso->ar = CTX_wm_region(C);
-
- /* multiframe settings */
- gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
- gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
-
- /* Init multi-edit falloff curve data before doing anything,
- * so we won't have to do it again later. */
- if (gso->is_multiframe) {
- curvemapping_initialize(ts->gp_sculpt.cur_falloff);
- }
-
- /* initialise custom data for brushes */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_CLONE:
- {
- bGPDstroke *gps;
- bool found = false;
-
- /* check that there are some usable strokes in the buffer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- found = true;
- break;
- }
- }
-
- if (found == false) {
- /* STOP HERE! Nothing to paste! */
- BKE_report(op->reports, RPT_ERROR,
- "Copy some strokes to the clipboard before using the Clone brush to paste copies of them");
-
- MEM_freeN(gso);
- op->customdata = NULL;
- return false;
- }
- else {
- /* initialise customdata */
- gp_brush_clone_init(C, gso);
- }
- break;
- }
-
- case GP_SCULPT_TYPE_GRAB:
- {
- /* initialise the cache needed for this brush */
- gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
- break;
- }
-
- /* Others - No customdata needed */
- default:
- break;
- }
-
-
- /* setup space conversions */
- gp_point_conversion_init(C, &gso->gsc);
-
- /* update header */
- gpsculpt_brush_header_set(C, gso);
-
- /* setup cursor drawing */
- //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, true, NULL);
- }
- return true;
+ tGP_BrushEditData *gso;
+
+ /* setup operator data */
+ gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
+ op->customdata = gso;
+
+ gso->depsgraph = CTX_data_depsgraph(C);
+ /* store state */
+ gso->settings = gpsculpt_get_settings(scene);
+ gso->gp_brush = gpsculpt_get_brush(scene, is_weight_mode);
+ gso->is_weight_mode = is_weight_mode;
+
+ if (is_weight_mode) {
+ gso->brush_type = gso->settings->weighttype;
+ }
+ else {
+ gso->brush_type = gso->settings->brushtype;
+ }
+
+ /* Random generator, only init once. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(gso);
+ gso->rng = BLI_rng_new(rng_seed);
+
+ gso->is_painting = false;
+ gso->first = true;
+
+ gso->gpd = ED_gpencil_data_get_active(C);
+ gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
+
+ /* some brushes cannot use pressure for radius */
+ if (ELEM(gso->brush_type, GP_SCULPT_TYPE_GRAB, GP_SCULPT_TYPE_CLONE)) {
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_PRESSURE_RADIUS;
+ }
+
+ gso->scene = scene;
+ gso->object = ob;
+ if (ob) {
+ gso->vrgroup = ob->actdef - 1;
+ if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
+ gso->vrgroup = -1;
+ }
+ }
+ else {
+ gso->vrgroup = -1;
+ }
+
+ gso->sa = CTX_wm_area(C);
+ gso->ar = CTX_wm_region(C);
+
+ /* multiframe settings */
+ gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
+ gso->use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+
+ /* Init multi-edit falloff curve data before doing anything,
+ * so we won't have to do it again later. */
+ if (gso->is_multiframe) {
+ curvemapping_initialize(ts->gp_sculpt.cur_falloff);
+ }
+
+ /* initialise custom data for brushes */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_CLONE: {
+ bGPDstroke *gps;
+ bool found = false;
+
+ /* check that there are some usable strokes in the buffer */
+ for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ /* STOP HERE! Nothing to paste! */
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Copy some strokes to the clipboard before using the Clone brush to paste "
+ "copies of them");
+
+ MEM_freeN(gso);
+ op->customdata = NULL;
+ return false;
+ }
+ else {
+ /* initialise customdata */
+ gp_brush_clone_init(C, gso);
+ }
+ break;
+ }
+
+ case GP_SCULPT_TYPE_GRAB: {
+ /* initialise the cache needed for this brush */
+ gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
+ break;
+ }
+
+ /* Others - No customdata needed */
+ default:
+ break;
+ }
+
+ /* setup space conversions */
+ gp_point_conversion_init(C, &gso->gsc);
+
+ /* update header */
+ gpsculpt_brush_header_set(C, gso);
+
+ /* setup cursor drawing */
+ //WM_cursor_modal_set(CTX_wm_window(C), BC_CROSSCURSOR);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, true, NULL);
+ }
+ return true;
}
static void gpsculpt_brush_exit(bContext *C, wmOperator *op)
{
- tGP_BrushEditData *gso = op->customdata;
- wmWindow *win = CTX_wm_window(C);
-
- /* free brush-specific data */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB:
- {
- /* Free per-stroke customdata
- * - Keys don't need to be freed, as those are the strokes
- * - Values assigned to those keys do, as they are custom structs
- */
- BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
- break;
- }
-
- case GP_SCULPT_TYPE_CLONE:
- {
- /* Free customdata */
- gp_brush_clone_free(gso);
- break;
- }
-
- default:
- break;
- }
-
- /* unregister timer (only used for realtime) */
- if (gso->timer) {
- WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
- }
-
- if (gso->rng != NULL) {
- BLI_rng_free(gso->rng);
- }
-
- /* disable cursor and headerprints */
- ED_workspace_status_text(C, NULL);
- WM_cursor_modal_restore(win);
- if (gso->sa->spacetype != SPACE_VIEW3D) {
- ED_gpencil_toggle_brush_cursor(C, false, NULL);
- }
-
- /* disable temp invert flag */
- gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
-
- /* free operator data */
- MEM_freeN(gso);
- op->customdata = NULL;
+ tGP_BrushEditData *gso = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+
+ /* free brush-specific data */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_GRAB: {
+ /* Free per-stroke customdata
+ * - Keys don't need to be freed, as those are the strokes
+ * - Values assigned to those keys do, as they are custom structs
+ */
+ BLI_ghash_free(gso->stroke_customdata, NULL, gp_brush_grab_stroke_free);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_CLONE: {
+ /* Free customdata */
+ gp_brush_clone_free(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* unregister timer (only used for realtime) */
+ if (gso->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), win, gso->timer);
+ }
+
+ if (gso->rng != NULL) {
+ BLI_rng_free(gso->rng);
+ }
+
+ /* disable cursor and headerprints */
+ ED_workspace_status_text(C, NULL);
+ WM_cursor_modal_restore(win);
+ if (gso->sa->spacetype != SPACE_VIEW3D) {
+ ED_gpencil_toggle_brush_cursor(C, false, NULL);
+ }
+
+ /* disable temp invert flag */
+ gso->gp_brush->flag &= ~GP_SCULPT_FLAG_TMP_INVERT;
+
+ /* free operator data */
+ MEM_freeN(gso);
+ op->customdata = NULL;
}
/* poll callback for stroke sculpting operator(s) */
static bool gpsculpt_brush_poll(bContext *C)
{
- /* NOTE: this is a bit slower, but is the most accurate... */
- return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
+ /* NOTE: this is a bit slower, but is the most accurate... */
+ return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
}
/* Init Sculpt Stroke ---------------------------------- */
static void gpsculpt_brush_init_stroke(tGP_BrushEditData *gso)
{
- bGPdata *gpd = gso->gpd;
-
- bGPDlayer *gpl;
- int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
-
- /* only try to add a new frame if this is the first stroke, or the frame has changed */
- if ((gpd == NULL) || (cfra_eval == gso->cfra))
- return;
-
- /* go through each layer, and ensure that we've got a valid frame to use */
- for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
- /* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
- bGPDframe *gpf = gpl->actframe;
-
- /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
- * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
- * spent too much time editing the wrong frame...
- */
- // XXX: should this be allowed when framelock is enabled?
- if (gpf->framenum != cfra_eval) {
- BKE_gpencil_frame_addcopy(gpl, cfra_eval);
- }
- }
- }
-
- /* save off new current frame, so that next update works fine */
- gso->cfra = cfra_eval;
+ bGPdata *gpd = gso->gpd;
+
+ bGPDlayer *gpl;
+ int cfra_eval = (int)DEG_get_ctime(gso->depsgraph);
+
+ /* only try to add a new frame if this is the first stroke, or the frame has changed */
+ if ((gpd == NULL) || (cfra_eval == gso->cfra))
+ return;
+
+ /* go through each layer, and ensure that we've got a valid frame to use */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* only editable and visible layers are considered */
+ if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *gpf = gpl->actframe;
+
+ /* Make a new frame to work on if the layer's frame and the current scene frame don't match up
+ * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
+ * spent too much time editing the wrong frame...
+ */
+ // XXX: should this be allowed when framelock is enabled?
+ if (gpf->framenum != cfra_eval) {
+ BKE_gpencil_frame_addcopy(gpl, cfra_eval);
+ }
+ }
+ }
+
+ /* save off new current frame, so that next update works fine */
+ gso->cfra = cfra_eval;
}
/* Apply ----------------------------------------------- */
/* Apply brush operation to points in this stroke */
-static bool gpsculpt_brush_do_stroke(
- tGP_BrushEditData *gso, bGPDstroke *gps,
- float diff_mat[4][4], GP_BrushApplyCb apply)
+static bool gpsculpt_brush_do_stroke(tGP_BrushEditData *gso,
+ bGPDstroke *gps,
+ float diff_mat[4][4],
+ GP_BrushApplyCb apply)
{
- GP_SpaceConversion *gsc = &gso->gsc;
- rcti *rect = &gso->brush_rect;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ? gso->gp_brush->size * gso->pressure : gso->gp_brush->size;
-
- bGPDspoint *pt1, *pt2;
- int pc1[2] = {0};
- int pc2[2] = {0};
- int i;
- bool include_last = false;
- bool changed = false;
-
- if (gps->totpoints == 1) {
- bGPDspoint pt_temp;
- gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
- gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
-
- /* do boundbox check first */
- if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
- /* only check if point is inside */
- int mval_i[2];
- round_v2i_v2fl(mval_i, gso->mval);
- if (len_v2v2_int(mval_i, pc1) <= radius) {
- /* apply operation to this point */
- changed = apply(gso, gps, 0, radius, pc1);
- }
- }
- }
- else {
- /* Loop over the points in the stroke, checking for intersections
- * - an intersection means that we touched the stroke
- */
- for (i = 0; (i + 1) < gps->totpoints; i++) {
- /* Get points to work with */
- pt1 = gps->points + i;
- pt2 = gps->points + i + 1;
-
- /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
- if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
- if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
- include_last = false;
- continue;
- }
- }
- bGPDspoint npt;
- gp_point_to_parent_space(pt1, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
-
- gp_point_to_parent_space(pt2, diff_mat, &npt);
- gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
-
- /* Check that point segment of the boundbox of the selection stroke */
- if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
- ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1])))
- {
- /* Check if point segment of stroke had anything to do with
- * brush region (either within stroke painted, or on its lines)
- * - this assumes that linewidth is irrelevant
- */
- if (gp_stroke_inside_circle(gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
- /* Apply operation to these points */
- bool ok = false;
-
- /* To each point individually... */
- ok = apply(gso, gps, i, radius, pc1);
-
- /* Only do the second point if this is the last segment,
- * and it is unlikely that the point will get handled
- * otherwise.
- *
- * NOTE: There is a small risk here that the second point wasn't really
- * actually in-range. In that case, it only got in because
- * the line linking the points was!
- */
- if (i + 1 == gps->totpoints - 1) {
- ok |= apply(gso, gps, i + 1, radius, pc2);
- include_last = false;
- }
- else {
- include_last = true;
- }
-
- changed |= ok;
- }
- else if (include_last) {
- /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included
- * because the whole edge isn't in bounds, but it would've qualified since it did with the
- * previous step (but wasn't added then, to avoid double-ups)
- */
- changed |= apply(gso, gps, i, radius, pc1);
- include_last = false;
- }
- }
- }
- }
-
- return changed;
+ GP_SpaceConversion *gsc = &gso->gsc;
+ rcti *rect = &gso->brush_rect;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
+ gso->gp_brush->size * gso->pressure :
+ gso->gp_brush->size;
+
+ bGPDspoint *pt1, *pt2;
+ int pc1[2] = {0};
+ int pc2[2] = {0};
+ int i;
+ bool include_last = false;
+ bool changed = false;
+
+ if (gps->totpoints == 1) {
+ bGPDspoint pt_temp;
+ gp_point_to_parent_space(gps->points, diff_mat, &pt_temp);
+ gp_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
+
+ /* do boundbox check first */
+ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
+ /* only check if point is inside */
+ int mval_i[2];
+ round_v2i_v2fl(mval_i, gso->mval);
+ if (len_v2v2_int(mval_i, pc1) <= radius) {
+ /* apply operation to this point */
+ changed = apply(gso, gps, 0, radius, pc1);
+ }
+ }
+ }
+ else {
+ /* Loop over the points in the stroke, checking for intersections
+ * - an intersection means that we touched the stroke
+ */
+ for (i = 0; (i + 1) < gps->totpoints; i++) {
+ /* Get points to work with */
+ pt1 = gps->points + i;
+ pt2 = gps->points + i + 1;
+
+ /* Skip if neither one is selected (and we are only allowed to edit/consider selected points) */
+ if (gso->settings->flag & GP_SCULPT_SETT_FLAG_SELECT_MASK) {
+ if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
+ include_last = false;
+ continue;
+ }
+ }
+ bGPDspoint npt;
+ gp_point_to_parent_space(pt1, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
+
+ gp_point_to_parent_space(pt2, diff_mat, &npt);
+ gp_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
+
+ /* Check that point segment of the boundbox of the selection stroke */
+ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
+ ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
+ /* Check if point segment of stroke had anything to do with
+ * brush region (either within stroke painted, or on its lines)
+ * - this assumes that linewidth is irrelevant
+ */
+ if (gp_stroke_inside_circle(
+ gso->mval, gso->mval_prev, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
+ /* Apply operation to these points */
+ bool ok = false;
+
+ /* To each point individually... */
+ ok = apply(gso, gps, i, radius, pc1);
+
+ /* Only do the second point if this is the last segment,
+ * and it is unlikely that the point will get handled
+ * otherwise.
+ *
+ * NOTE: There is a small risk here that the second point wasn't really
+ * actually in-range. In that case, it only got in because
+ * the line linking the points was!
+ */
+ if (i + 1 == gps->totpoints - 1) {
+ ok |= apply(gso, gps, i + 1, radius, pc2);
+ include_last = false;
+ }
+ else {
+ include_last = true;
+ }
+
+ changed |= ok;
+ }
+ else if (include_last) {
+ /* This case is for cases where for whatever reason the second vert (1st here) doesn't get included
+ * because the whole edge isn't in bounds, but it would've qualified since it did with the
+ * previous step (but wasn't added then, to avoid double-ups)
+ */
+ changed |= apply(gso, gps, i, radius, pc1);
+ include_last = false;
+ }
+ }
+ }
+ }
+
+ return changed;
}
/* Apply sculpt brushes to strokes in the given frame */
static bool gpsculpt_brush_do_frame(
- bContext *C, tGP_BrushEditData *gso,
- bGPDlayer *gpl, bGPDframe *gpf,
- float diff_mat[4][4])
+ bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, float diff_mat[4][4])
{
- bool changed = false;
- Object *ob = CTX_data_active_object(C);
-
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
- continue;
- }
-
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
- {
- if (gso->first) {
- /* First time this brush stroke is being applied:
- * 1) Prepare data buffers (init/clear) for this stroke
- * 2) Use the points now under the cursor
- */
- gp_brush_grab_stroke_init(gso, gps);
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
- }
- else {
- /* Apply effect to the stored points */
- gp_brush_grab_apply_cached(gso, gps, diff_mat);
- changed |= true;
- }
- break;
- }
-
- case GP_SCULPT_TYPE_PUSH: /* Push points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
- break;
- }
-
- case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
- {
- changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
- break;
- }
-
-
- default:
- printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
- break;
- }
- /* Triangulation must be calculated if changed */
- if (changed) {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
- gps->tot_triangles = 0;
- }
- }
-
- return changed;
+ bool changed = false;
+ Object *ob = CTX_data_active_object(C);
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
+ continue;
+ }
+
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_SMOOTH: /* Smooth strokes */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_smooth_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_THICKNESS: /* Adjust stroke thickness */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_thickness_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_STRENGTH: /* Adjust stroke color strength */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_strength_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ {
+ if (gso->first) {
+ /* First time this brush stroke is being applied:
+ * 1) Prepare data buffers (init/clear) for this stroke
+ * 2) Use the points now under the cursor
+ */
+ gp_brush_grab_stroke_init(gso, gps);
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_grab_store_points);
+ }
+ else {
+ /* Apply effect to the stored points */
+ gp_brush_grab_apply_cached(gso, gps, diff_mat);
+ changed |= true;
+ }
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_push_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_pinch_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_twist_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Apply jitter */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_randomize_apply);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_WEIGHT: /* Adjust vertex group weight */
+ {
+ changed |= gpsculpt_brush_do_stroke(gso, gps, diff_mat, gp_brush_weight_apply);
+ break;
+ }
+
+ default:
+ printf("ERROR: Unknown type of GPencil Sculpt brush - %u\n", gso->brush_type);
+ break;
+ }
+ /* Triangulation must be calculated if changed */
+ if (changed) {
+ gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+ gps->tot_triangles = 0;
+ }
+ }
+
+ return changed;
}
/* Perform two-pass brushes which modify the existing strokes */
static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
{
- ToolSettings *ts = CTX_data_tool_settings(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *obact = gso->object;
- bGPdata *gpd = gso->gpd;
- bool changed = false;
-
- /* Calculate brush-specific data which applies equally to all points */
- switch (gso->brush_type) {
- case GP_SCULPT_TYPE_GRAB: /* Grab points */
- case GP_SCULPT_TYPE_PUSH: /* Push points */
- {
- /* calculate amount of displacement to apply */
- gp_brush_grab_calc_dvec(gso);
- break;
- }
-
- case GP_SCULPT_TYPE_PINCH: /* Pinch points */
- case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
- {
- /* calculate midpoint of the brush (in data space) */
- gp_brush_calc_midpoint(gso);
- break;
- }
-
- case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
- {
- /* compute the displacement vector for the cursor (in data space) */
- gp_brush_grab_calc_dvec(gso);
- break;
- }
-
- default:
- break;
- }
-
-
- /* Find visible strokes, and perform operations on those if hit */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- /* If no active frame, don't do anything... */
- if (gpl->actframe == NULL) {
- continue;
- }
-
- /* calculate difference matrix */
- float diff_mat[4][4];
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
-
- /* Active Frame or MultiFrame? */
- if (gso->is_multiframe) {
- /* init multiframe falloff options */
- int f_init = 0;
- int f_end = 0;
-
- if (gso->use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
- }
-
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- /* Always do active frame; Otherwise, only include selected frames */
- if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
- /* compute multiframe falloff factor */
- if (gso->use_multiframe_falloff) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
- gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
- gpf, gpl->actframe->framenum,
- f_init, f_end,
- ts->gp_sculpt.cur_falloff);
- }
- else {
- /* No falloff */
- gso->mf_falloff = 1.0f;
- }
-
- /* affect strokes in this frame */
- changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
- }
- }
- }
- else {
- /* Apply to active frame's strokes */
- gso->mf_falloff = 1.0f;
- changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
- }
- }
- CTX_DATA_END;
-
- return changed;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *obact = gso->object;
+ bGPdata *gpd = gso->gpd;
+ bool changed = false;
+
+ /* Calculate brush-specific data which applies equally to all points */
+ switch (gso->brush_type) {
+ case GP_SCULPT_TYPE_GRAB: /* Grab points */
+ case GP_SCULPT_TYPE_PUSH: /* Push points */
+ {
+ /* calculate amount of displacement to apply */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_PINCH: /* Pinch points */
+ case GP_SCULPT_TYPE_TWIST: /* Twist points around midpoint */
+ {
+ /* calculate midpoint of the brush (in data space) */
+ gp_brush_calc_midpoint(gso);
+ break;
+ }
+
+ case GP_SCULPT_TYPE_RANDOMIZE: /* Random jitter */
+ {
+ /* compute the displacement vector for the cursor (in data space) */
+ gp_brush_grab_calc_dvec(gso);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ /* Find visible strokes, and perform operations on those if hit */
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ /* If no active frame, don't do anything... */
+ if (gpl->actframe == NULL) {
+ continue;
+ }
+
+ /* calculate difference matrix */
+ float diff_mat[4][4];
+ ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+
+ /* Active Frame or MultiFrame? */
+ if (gso->is_multiframe) {
+ /* init multiframe falloff options */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (gso->use_multiframe_falloff) {
+ BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ }
+
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ /* Always do active frame; Otherwise, only include selected frames */
+ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
+ /* compute multiframe falloff factor */
+ if (gso->use_multiframe_falloff) {
+ /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+ else {
+ /* No falloff */
+ gso->mf_falloff = 1.0f;
+ }
+
+ /* affect strokes in this frame */
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
+ }
+ }
+ }
+ else {
+ /* Apply to active frame's strokes */
+ gso->mf_falloff = 1.0f;
+ changed |= gpsculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
+ }
+ }
+ CTX_DATA_END;
+
+ return changed;
}
/* Calculate settings for applying brush */
static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
- tGP_BrushEditData *gso = op->customdata;
- GP_Sculpt_Data *gp_brush = gso->gp_brush;
- const int radius = (
- (gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
- gso->gp_brush->size * gso->pressure : gso->gp_brush->size);
- float mousef[2];
- int mouse[2];
- bool changed = false;
-
- /* Get latest mouse coordinates */
- RNA_float_get_array(itemptr, "mouse", mousef);
- gso->mval[0] = mouse[0] = (int)(mousef[0]);
- gso->mval[1] = mouse[1] = (int)(mousef[1]);
-
- gso->pressure = RNA_float_get(itemptr, "pressure");
-
- if (RNA_boolean_get(itemptr, "pen_flip"))
- gso->flag |= GP_SCULPT_FLAG_INVERT;
- else
- gso->flag &= ~GP_SCULPT_FLAG_INVERT;
-
-
- /* Store coordinates as reference, if operator just started running */
- if (gso->first) {
- gso->mval_prev[0] = gso->mval[0];
- gso->mval_prev[1] = gso->mval[1];
- gso->pressure_prev = gso->pressure;
- }
-
- /* Update brush_rect, so that it represents the bounding rectangle of brush */
- gso->brush_rect.xmin = mouse[0] - radius;
- gso->brush_rect.ymin = mouse[1] - radius;
- gso->brush_rect.xmax = mouse[0] + radius;
- gso->brush_rect.ymax = mouse[1] + radius;
-
-
- /* Apply brush */
- if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
- changed = gpsculpt_brush_apply_clone(C, gso);
- }
- else {
- changed = gpsculpt_brush_apply_standard(C, gso);
- }
-
-
- /* Updates */
- if (changed) {
- DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
- }
-
- /* Store values for next step */
- gso->mval_prev[0] = gso->mval[0];
- gso->mval_prev[1] = gso->mval[1];
- gso->pressure_prev = gso->pressure;
- gso->first = false;
+ tGP_BrushEditData *gso = op->customdata;
+ GP_Sculpt_Data *gp_brush = gso->gp_brush;
+ const int radius = ((gp_brush->flag & GP_SCULPT_FLAG_PRESSURE_RADIUS) ?
+ gso->gp_brush->size * gso->pressure :
+ gso->gp_brush->size);
+ float mousef[2];
+ int mouse[2];
+ bool changed = false;
+
+ /* Get latest mouse coordinates */
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ gso->mval[0] = mouse[0] = (int)(mousef[0]);
+ gso->mval[1] = mouse[1] = (int)(mousef[1]);
+
+ gso->pressure = RNA_float_get(itemptr, "pressure");
+
+ if (RNA_boolean_get(itemptr, "pen_flip"))
+ gso->flag |= GP_SCULPT_FLAG_INVERT;
+ else
+ gso->flag &= ~GP_SCULPT_FLAG_INVERT;
+
+ /* Store coordinates as reference, if operator just started running */
+ if (gso->first) {
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ }
+
+ /* Update brush_rect, so that it represents the bounding rectangle of brush */
+ gso->brush_rect.xmin = mouse[0] - radius;
+ gso->brush_rect.ymin = mouse[1] - radius;
+ gso->brush_rect.xmax = mouse[0] + radius;
+ gso->brush_rect.ymax = mouse[1] + radius;
+
+ /* Apply brush */
+ if (gso->brush_type == GP_SCULPT_TYPE_CLONE) {
+ changed = gpsculpt_brush_apply_clone(C, gso);
+ }
+ else {
+ changed = gpsculpt_brush_apply_standard(C, gso);
+ }
+
+ /* Updates */
+ if (changed) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+
+ /* Store values for next step */
+ gso->mval_prev[0] = gso->mval[0];
+ gso->mval_prev[1] = gso->mval[1];
+ gso->pressure_prev = gso->pressure;
+ gso->first = false;
}
/* Running --------------------------------------------- */
@@ -1806,370 +1766,380 @@ static void gpsculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itempt
/* helper - a record stroke, and apply paint event */
static void gpsculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = op->customdata;
- ToolSettings *ts = CTX_data_tool_settings(C);
- GP_Sculpt_Settings *gset = &ts->gp_sculpt;
- PointerRNA itemptr;
- float mouse[2];
- int tablet = 0;
-
- mouse[0] = event->mval[0] + 1;
- mouse[1] = event->mval[1] + 1;
-
- /* fill in stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
-
- RNA_float_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
- RNA_boolean_set(&itemptr, "is_start", gso->first);
-
- /* handle pressure sensitivity (which is supplied by tablets) */
- if (event->tablet_data) {
- const wmTabletData *wmtab = event->tablet_data;
- float pressure = wmtab->Pressure;
-
- tablet = (wmtab->Active != EVT_TABLET_NONE);
-
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets: clamp the values to be sane
- */
- if (tablet && (pressure >= 0.99f)) {
- pressure = 1.0f;
- }
- RNA_float_set(&itemptr, "pressure", pressure);
- }
- else {
- RNA_float_set(&itemptr, "pressure", 1.0f);
- }
-
- if (!gso->is_weight_mode) {
- if (event->shift) {
- gso->gp_brush_old = gso->gp_brush;
- gso->brush_type_old = gso->brush_type;
-
- gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
- gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
- }
- else {
- if (gso->gp_brush_old != NULL) {
- gso->gp_brush = gso->gp_brush_old;
- gso->brush_type = gso->brush_type_old;
- }
- }
- }
-
- /* apply */
- gpsculpt_brush_apply(C, op, &itemptr);
+ tGP_BrushEditData *gso = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ GP_Sculpt_Settings *gset = &ts->gp_sculpt;
+ PointerRNA itemptr;
+ float mouse[2];
+ int tablet = 0;
+
+ mouse[0] = event->mval[0] + 1;
+ mouse[1] = event->mval[1] + 1;
+
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
+ RNA_boolean_set(&itemptr, "is_start", gso->first);
+
+ /* handle pressure sensitivity (which is supplied by tablets) */
+ if (event->tablet_data) {
+ const wmTabletData *wmtab = event->tablet_data;
+ float pressure = wmtab->Pressure;
+
+ tablet = (wmtab->Active != EVT_TABLET_NONE);
+
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets: clamp the values to be sane
+ */
+ if (tablet && (pressure >= 0.99f)) {
+ pressure = 1.0f;
+ }
+ RNA_float_set(&itemptr, "pressure", pressure);
+ }
+ else {
+ RNA_float_set(&itemptr, "pressure", 1.0f);
+ }
+
+ if (!gso->is_weight_mode) {
+ if (event->shift) {
+ gso->gp_brush_old = gso->gp_brush;
+ gso->brush_type_old = gso->brush_type;
+
+ gso->gp_brush = &gset->brush[GP_SCULPT_TYPE_SMOOTH];
+ gso->brush_type = GP_SCULPT_TYPE_SMOOTH;
+ }
+ else {
+ if (gso->gp_brush_old != NULL) {
+ gso->gp_brush = gso->gp_brush_old;
+ gso->brush_type = gso->brush_type_old;
+ }
+ }
+ }
+
+ /* apply */
+ gpsculpt_brush_apply(C, op, &itemptr);
}
/* reapply */
static int gpsculpt_brush_exec(bContext *C, wmOperator *op)
{
- if (!gpsculpt_brush_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
- RNA_BEGIN(op->ptr, itemptr, "stroke")
- {
- gpsculpt_brush_apply(C, op, &itemptr);
- }
- RNA_END;
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ gpsculpt_brush_apply(C, op, &itemptr);
+ }
+ RNA_END;
- gpsculpt_brush_exit(C, op);
+ gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
-
/* start modal painting */
static int gpsculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = NULL;
- const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
- bool needs_timer = false;
- float brush_rate = 0.0f;
-
- /* the operator cannot work while play animation */
- if (is_playing) {
- BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while play animation");
-
- return OPERATOR_CANCELLED;
- }
-
- /* init painting data */
- if (!gpsculpt_brush_init(C, op))
- return OPERATOR_CANCELLED;
-
- gso = op->customdata;
-
- /* initialise type-specific data (used for the entire session) */
- switch (gso->brush_type) {
- /* Brushes requiring timer... */
- case GP_SCULPT_TYPE_THICKNESS:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_STRENGTH:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_PINCH:
- brush_rate = 0.001f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- case GP_SCULPT_TYPE_TWIST:
- brush_rate = 0.01f; // XXX: hardcoded
- needs_timer = true;
- break;
-
- default:
- break;
- }
-
- /* register timer for increasing influence by hovering over an area */
- if (needs_timer) {
- gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
- }
-
- /* register modal handler */
- WM_event_add_modal_handler(C, op);
-
- /* start drawing immediately? */
- if (is_modal == false) {
- ARegion *ar = CTX_wm_region(C);
-
- /* ensure that we'll have a new frame to draw on */
- gpsculpt_brush_init_stroke(gso);
-
- /* apply first dab... */
- gso->is_painting = true;
- gpsculpt_brush_apply_event(C, op, event);
-
- /* redraw view with feedback */
- ED_region_tag_redraw(ar);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ tGP_BrushEditData *gso = NULL;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
+ bool needs_timer = false;
+ float brush_rate = 0.0f;
+
+ /* the operator cannot work while play animation */
+ if (is_playing) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while play animation");
+
+ return OPERATOR_CANCELLED;
+ }
+
+ /* init painting data */
+ if (!gpsculpt_brush_init(C, op))
+ return OPERATOR_CANCELLED;
+
+ gso = op->customdata;
+
+ /* initialise type-specific data (used for the entire session) */
+ switch (gso->brush_type) {
+ /* Brushes requiring timer... */
+ case GP_SCULPT_TYPE_THICKNESS:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_STRENGTH:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_PINCH:
+ brush_rate = 0.001f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ case GP_SCULPT_TYPE_TWIST:
+ brush_rate = 0.01f; // XXX: hardcoded
+ needs_timer = true;
+ break;
+
+ default:
+ break;
+ }
+
+ /* register timer for increasing influence by hovering over an area */
+ if (needs_timer) {
+ gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
+ }
+
+ /* register modal handler */
+ WM_event_add_modal_handler(C, op);
+
+ /* start drawing immediately? */
+ if (is_modal == false) {
+ ARegion *ar = CTX_wm_region(C);
+
+ /* ensure that we'll have a new frame to draw on */
+ gpsculpt_brush_init_stroke(gso);
+
+ /* apply first dab... */
+ gso->is_painting = true;
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* redraw view with feedback */
+ ED_region_tag_redraw(ar);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
/* painting - handle events */
static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- tGP_BrushEditData *gso = op->customdata;
- const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
- bool redraw_region = false;
- bool redraw_toolsettings = false;
-
- /* The operator can be in 2 states: Painting and Idling */
- if (gso->is_painting) {
- /* Painting */
- switch (event->type) {
- /* Mouse Move = Apply somewhere else */
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- /* apply brush effect at new position */
- gpsculpt_brush_apply_event(C, op, event);
-
- /* force redraw, so that the cursor will at least be valid */
- redraw_region = true;
- break;
-
- /* Timer Tick - Only if this was our own timer */
- case TIMER:
- if (event->customdata == gso->timer) {
- gso->timerTick = true;
- gpsculpt_brush_apply_event(C, op, event);
- gso->timerTick = false;
- }
- break;
-
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- /* Painting mbut release = Stop painting (back to idle) */
- case LEFTMOUSE:
- //BLI_assert(event->val == KM_RELEASE);
- if (is_modal) {
- /* go back to idling... */
- gso->is_painting = false;
- }
- else {
- /* end sculpt session, since we're not modal */
- gso->is_painting = false;
-
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
- }
- break;
-
- /* Abort painting if any of the usual things are tried */
- case MIDDLEMOUSE:
- case RIGHTMOUSE:
- case ESCKEY:
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
- }
- }
- else {
- /* Idling */
- BLI_assert(is_modal == true);
-
- switch (event->type) {
- /* Painting mbut press = Start painting (switch to painting state) */
- case LEFTMOUSE:
- /* do initial "click" apply */
- gso->is_painting = true;
- gso->first = true;
-
- gpsculpt_brush_init_stroke(gso);
- gpsculpt_brush_apply_event(C, op, event);
- break;
-
- /* Exit modal operator, based on the "standard" ops */
- case RIGHTMOUSE:
- case ESCKEY:
- gpsculpt_brush_exit(C, op);
- return OPERATOR_FINISHED;
-
- /* MMB is often used for view manipulations */
- case MIDDLEMOUSE:
- return OPERATOR_PASS_THROUGH;
-
- /* Mouse movements should update the brush cursor - Just redraw the active region */
- case MOUSEMOVE:
- case INBETWEEN_MOUSEMOVE:
- redraw_region = true;
- break;
-
- /* Adjust brush settings */
- /* FIXME: Step increments and modifier keys are hardcoded here! */
- case WHEELUPMOUSE:
- case PADPLUSKEY:
- if (event->shift) {
- /* increase strength */
- gso->gp_brush->strength += 0.05f;
- CLAMP_MAX(gso->gp_brush->strength, 1.0f);
- }
- else {
- /* increase brush size */
- gso->gp_brush->size += 3;
- CLAMP_MAX(gso->gp_brush->size, 300);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- case WHEELDOWNMOUSE:
- case PADMINUS:
- if (event->shift) {
- /* decrease strength */
- gso->gp_brush->strength -= 0.05f;
- CLAMP_MIN(gso->gp_brush->strength, 0.0f);
- }
- else {
- /* decrease brush size */
- gso->gp_brush->size -= 3;
- CLAMP_MIN(gso->gp_brush->size, 1);
- }
-
- redraw_region = true;
- redraw_toolsettings = true;
- break;
-
- /* Change Frame - Allowed */
- case LEFTARROWKEY:
- case RIGHTARROWKEY:
- case UPARROWKEY:
- case DOWNARROWKEY:
- return OPERATOR_PASS_THROUGH;
-
- /* Camera/View Gizmo's - Allowed */
- /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
- case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
- case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
- return OPERATOR_PASS_THROUGH;
-
- /* Unhandled event */
- default:
- break;
- }
- }
-
- /* Redraw region? */
- if (redraw_region) {
- ARegion *ar = CTX_wm_region(C);
- ED_region_tag_redraw(ar);
- }
-
- /* Redraw toolsettings (brush settings)? */
- if (redraw_toolsettings) {
- DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ tGP_BrushEditData *gso = op->customdata;
+ const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
+ bool redraw_region = false;
+ bool redraw_toolsettings = false;
+
+ /* The operator can be in 2 states: Painting and Idling */
+ if (gso->is_painting) {
+ /* Painting */
+ switch (event->type) {
+ /* Mouse Move = Apply somewhere else */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ /* apply brush effect at new position */
+ gpsculpt_brush_apply_event(C, op, event);
+
+ /* force redraw, so that the cursor will at least be valid */
+ redraw_region = true;
+ break;
+
+ /* Timer Tick - Only if this was our own timer */
+ case TIMER:
+ if (event->customdata == gso->timer) {
+ gso->timerTick = true;
+ gpsculpt_brush_apply_event(C, op, event);
+ gso->timerTick = false;
+ }
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Painting mbut release = Stop painting (back to idle) */
+ case LEFTMOUSE:
+ //BLI_assert(event->val == KM_RELEASE);
+ if (is_modal) {
+ /* go back to idling... */
+ gso->is_painting = false;
+ }
+ else {
+ /* end sculpt session, since we're not modal */
+ gso->is_painting = false;
+
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+
+ /* Abort painting if any of the usual things are tried */
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else {
+ /* Idling */
+ BLI_assert(is_modal == true);
+
+ switch (event->type) {
+ /* Painting mbut press = Start painting (switch to painting state) */
+ case LEFTMOUSE:
+ /* do initial "click" apply */
+ gso->is_painting = true;
+ gso->first = true;
+
+ gpsculpt_brush_init_stroke(gso);
+ gpsculpt_brush_apply_event(C, op, event);
+ break;
+
+ /* Exit modal operator, based on the "standard" ops */
+ case RIGHTMOUSE:
+ case ESCKEY:
+ gpsculpt_brush_exit(C, op);
+ return OPERATOR_FINISHED;
+
+ /* MMB is often used for view manipulations */
+ case MIDDLEMOUSE:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Mouse movements should update the brush cursor - Just redraw the active region */
+ case MOUSEMOVE:
+ case INBETWEEN_MOUSEMOVE:
+ redraw_region = true;
+ break;
+
+ /* Adjust brush settings */
+ /* FIXME: Step increments and modifier keys are hardcoded here! */
+ case WHEELUPMOUSE:
+ case PADPLUSKEY:
+ if (event->shift) {
+ /* increase strength */
+ gso->gp_brush->strength += 0.05f;
+ CLAMP_MAX(gso->gp_brush->strength, 1.0f);
+ }
+ else {
+ /* increase brush size */
+ gso->gp_brush->size += 3;
+ CLAMP_MAX(gso->gp_brush->size, 300);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PADMINUS:
+ if (event->shift) {
+ /* decrease strength */
+ gso->gp_brush->strength -= 0.05f;
+ CLAMP_MIN(gso->gp_brush->strength, 0.0f);
+ }
+ else {
+ /* decrease brush size */
+ gso->gp_brush->size -= 3;
+ CLAMP_MIN(gso->gp_brush->size, 1);
+ }
+
+ redraw_region = true;
+ redraw_toolsettings = true;
+ break;
+
+ /* Change Frame - Allowed */
+ case LEFTARROWKEY:
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Camera/View Gizmo's - Allowed */
+ /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
+ case PAD0:
+ case PAD1:
+ case PAD2:
+ case PAD3:
+ case PAD4:
+ case PAD5:
+ case PAD6:
+ case PAD7:
+ case PAD8:
+ case PAD9:
+ return OPERATOR_PASS_THROUGH;
+
+ /* Unhandled event */
+ default:
+ break;
+ }
+ }
+
+ /* Redraw region? */
+ if (redraw_region) {
+ ARegion *ar = CTX_wm_region(C);
+ ED_region_tag_redraw(ar);
+ }
+
+ /* Redraw toolsettings (brush settings)? */
+ if (redraw_toolsettings) {
+ DEG_id_tag_update(&gso->gpd->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Stroke Sculpt";
- ot->idname = "GPENCIL_OT_sculpt_paint";
- ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
-
- /* api callbacks */
- ot->exec = gpsculpt_brush_exec;
- ot->invoke = gpsculpt_brush_invoke;
- ot->modal = gpsculpt_brush_modal;
- ot->cancel = gpsculpt_brush_exit;
- ot->poll = gpsculpt_brush_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- /* properties */
- PropertyRNA *prop;
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input",
- "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* identifiers */
+ ot->name = "Stroke Sculpt";
+ ot->idname = "GPENCIL_OT_sculpt_paint";
+ ot->description = "Apply tweaks to strokes by painting over the strokes"; // XXX
+
+ /* api callbacks */
+ ot->exec = gpsculpt_brush_exec;
+ ot->invoke = gpsculpt_brush_invoke;
+ ot->modal = gpsculpt_brush_modal;
+ ot->cancel = gpsculpt_brush_exit;
+ ot->poll = gpsculpt_brush_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(
+ ot->srna,
+ "wait_for_input",
+ true,
+ "Wait for Input",
+ "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}