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/sculpt_paint/paint_stroke.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c2126
1 files changed, 1063 insertions, 1063 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index d66224034eb..4a586f4f7df 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -21,7 +21,6 @@
* \ingroup edsculpt
*/
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
@@ -49,7 +48,6 @@
#include "WM_api.h"
#include "WM_types.h"
-
#include "GPU_immediate.h"
#include "GPU_state.h"
@@ -70,844 +68,847 @@
#endif
typedef struct PaintSample {
- float mouse[2];
- float pressure;
+ float mouse[2];
+ float pressure;
} PaintSample;
typedef struct PaintStroke {
- void *mode_data;
- void *stroke_cursor;
- wmTimer *timer;
- struct RNG *rng;
-
- /* Cached values */
- ViewContext vc;
- Brush *brush;
- UnifiedPaintSettings *ups;
-
- /* used for lines and curves */
- ListBase line;
-
- /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
- * to smooth the stroke */
- PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
- int num_samples;
- int cur_sample;
-
- float last_mouse_position[2];
- /* space distance covered so far */
- float stroke_distance;
-
- /* Set whether any stroke step has yet occurred
- * e.g. in sculpt mode, stroke doesn't start until cursor
- * passes over the mesh */
- bool stroke_started;
- /* Set when enough motion was found for rake rotation */
- bool rake_started;
- /* event that started stroke, for modal() return */
- int event_type;
- /* check if stroke variables have been initialized */
- bool stroke_init;
- /* check if various brush mapping variables have been initialized */
- bool brush_init;
- float initial_mouse[2];
- /* cached_pressure stores initial pressure for size pressure influence mainly */
- float cached_size_pressure;
- /* last pressure will store last pressure value for use in interpolation for space strokes */
- float last_pressure;
- int stroke_mode;
-
- float zoom_2d;
- int pen_flip;
-
- /* line constraint */
- bool constrain_line;
- float constrained_pos[2];
-
- StrokeGetLocation get_location;
- StrokeTestStart test_start;
- StrokeUpdateStep update_step;
- StrokeRedraw redraw;
- StrokeDone done;
+ void *mode_data;
+ void *stroke_cursor;
+ wmTimer *timer;
+ struct RNG *rng;
+
+ /* Cached values */
+ ViewContext vc;
+ Brush *brush;
+ UnifiedPaintSettings *ups;
+
+ /* used for lines and curves */
+ ListBase line;
+
+ /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
+ * to smooth the stroke */
+ PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
+ int num_samples;
+ int cur_sample;
+
+ float last_mouse_position[2];
+ /* space distance covered so far */
+ float stroke_distance;
+
+ /* Set whether any stroke step has yet occurred
+ * e.g. in sculpt mode, stroke doesn't start until cursor
+ * passes over the mesh */
+ bool stroke_started;
+ /* Set when enough motion was found for rake rotation */
+ bool rake_started;
+ /* event that started stroke, for modal() return */
+ int event_type;
+ /* check if stroke variables have been initialized */
+ bool stroke_init;
+ /* check if various brush mapping variables have been initialized */
+ bool brush_init;
+ float initial_mouse[2];
+ /* cached_pressure stores initial pressure for size pressure influence mainly */
+ float cached_size_pressure;
+ /* last pressure will store last pressure value for use in interpolation for space strokes */
+ float last_pressure;
+ int stroke_mode;
+
+ float zoom_2d;
+ int pen_flip;
+
+ /* line constraint */
+ bool constrain_line;
+ float constrained_pos[2];
+
+ StrokeGetLocation get_location;
+ StrokeTestStart test_start;
+ StrokeUpdateStep update_step;
+ StrokeRedraw redraw;
+ StrokeDone done;
} PaintStroke;
/*** Cursors ***/
static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- PaintStroke *stroke = customdata;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ PaintStroke *stroke = customdata;
- if (stroke && brush) {
- GPU_line_smooth(true);
- GPU_blend(true);
+ if (stroke && brush) {
+ GPU_line_smooth(true);
+ GPU_blend(true);
- ARegion *ar = stroke->vc.ar;
+ ARegion *ar = stroke->vc.ar;
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ubv(paint->paint_cursor_col);
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ubv(paint->paint_cursor_col);
- immBegin(GPU_PRIM_LINES, 2);
- immVertex2f(pos, x, y);
- immVertex2f(pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex2f(pos, x, y);
+ immVertex2f(pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immEnd();
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_blend(false);
- GPU_line_smooth(false);
- }
+ GPU_blend(false);
+ GPU_line_smooth(false);
+ }
}
static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
{
- Paint *paint = BKE_paint_get_active_from_context(C);
- PaintStroke *stroke = customdata;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintStroke *stroke = customdata;
- GPU_line_smooth(true);
+ GPU_line_smooth(true);
- uint shdr_pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- immUniform1i("colors_len", 2); /* "advanced" mode */
- const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
- immUniformArray4fv("colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
- immUniform1f("dash_width", 6.0f);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
+ immUniformArray4fv(
+ "colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
+ immUniform1f("dash_width", 6.0f);
- immBegin(GPU_PRIM_LINES, 2);
+ immBegin(GPU_PRIM_LINES, 2);
- ARegion *ar = stroke->vc.ar;
+ ARegion *ar = stroke->vc.ar;
- if (stroke->constrain_line) {
- immVertex2f(shdr_pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ if (stroke->constrain_line) {
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immVertex2f(shdr_pos,
- stroke->constrained_pos[0] + ar->winrct.xmin,
- stroke->constrained_pos[1] + ar->winrct.ymin);
- }
- else {
- immVertex2f(shdr_pos,
- stroke->last_mouse_position[0] + ar->winrct.xmin,
- stroke->last_mouse_position[1] + ar->winrct.ymin);
+ immVertex2f(shdr_pos,
+ stroke->constrained_pos[0] + ar->winrct.xmin,
+ stroke->constrained_pos[1] + ar->winrct.ymin);
+ }
+ else {
+ immVertex2f(shdr_pos,
+ stroke->last_mouse_position[0] + ar->winrct.xmin,
+ stroke->last_mouse_position[1] + ar->winrct.ymin);
- immVertex2f(shdr_pos, x, y);
- }
+ immVertex2f(shdr_pos, x, y);
+ }
- immEnd();
+ immEnd();
- immUnbindProgram();
+ immUnbindProgram();
- GPU_line_smooth(false);
+ GPU_line_smooth(false);
}
static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
{
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (ELEM(brush->sculpt_tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
- {
- return false;
- }
- else {
- return true;
- }
- default:
- break;
- }
-
- return true;
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB)) {
+ return false;
+ }
+ else {
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return true;
}
/* Initialize the stroke cache variants from operator properties */
-static bool paint_brush_update(
- bContext *C,
- Brush *brush,
- ePaintMode mode,
- struct PaintStroke *stroke,
- const float mouse_init[2],
- float mouse[2], float pressure,
- float r_location[3], bool *r_location_is_set)
+static bool paint_brush_update(bContext *C,
+ Brush *brush,
+ ePaintMode mode,
+ struct PaintStroke *stroke,
+ const float mouse_init[2],
+ float mouse[2],
+ float pressure,
+ float r_location[3],
+ bool *r_location_is_set)
{
- Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = stroke->ups;
- bool location_sampled = false;
- bool location_success = false;
- /* Use to perform all operations except applying the stroke,
- * needed for operations that require cursor motion (rake). */
- bool is_dry_run = false;
- bool do_random = false;
- bool do_random_mask = false;
- *r_location_is_set = false;
- /* XXX: Use pressure value from first brush step for brushes which don't
- * support strokes (grab, thumb). They depends on initial state and
- * brush coord/pressure/etc.
- * It's more an events design issue, which doesn't split coordinate/pressure/angle
- * changing events. We should avoid this after events system re-design */
- if (!stroke->brush_init) {
- copy_v2_v2(stroke->initial_mouse, mouse);
- copy_v2_v2(ups->last_rake, mouse);
- copy_v2_v2(ups->tex_mouse, mouse);
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- stroke->cached_size_pressure = pressure;
-
- ups->do_linear_conversion = false;
- ups->colorspace = NULL;
-
- /* check here if color sampling the main brush should do color conversion. This is done here
- * to avoid locking up to get the image buffer during sampling */
- if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
- ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(brush->mtex.tex->ima, &brush->mtex.tex->iuser, NULL);
- if (tex_ibuf && tex_ibuf->rect_float == NULL) {
- ups->do_linear_conversion = true;
- ups->colorspace = tex_ibuf->rect_colorspace;
- }
- BKE_image_pool_release_ibuf(brush->mtex.tex->ima, tex_ibuf, NULL);
- }
-
- stroke->brush_init = true;
- }
-
- if (paint_supports_dynamic_size(brush, mode)) {
- copy_v2_v2(ups->tex_mouse, mouse);
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- stroke->cached_size_pressure = pressure;
- }
-
- /* Truly temporary data that isn't stored in properties */
-
- ups->stroke_active = true;
- ups->size_pressure_value = stroke->cached_size_pressure;
-
- ups->pixel_radius = BKE_brush_size_get(scene, brush);
-
- if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
- ups->pixel_radius *= stroke->cached_size_pressure;
- }
-
- if (paint_supports_dynamic_tex_coords(brush, mode)) {
-
- if (ELEM(brush->mtex.brush_map_mode,
- MTEX_MAP_MODE_VIEW,
- MTEX_MAP_MODE_AREA,
- MTEX_MAP_MODE_RANDOM))
- {
- do_random = true;
- }
-
- if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coords(ups, false);
- else {
- copy_v2_v2(ups->tex_mouse, mouse);
- }
-
- /* take care of mask texture, if any */
- if (brush->mask_mtex.tex) {
-
- if (ELEM(brush->mask_mtex.brush_map_mode,
- MTEX_MAP_MODE_VIEW,
- MTEX_MAP_MODE_AREA,
- MTEX_MAP_MODE_RANDOM))
- {
- do_random_mask = true;
- }
-
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coords(ups, true);
- else {
- copy_v2_v2(ups->mask_tex_mouse, mouse);
- }
- }
- }
-
-
- if (brush->flag & BRUSH_ANCHORED) {
- bool hit = false;
- float halfway[2];
-
- const float dx = mouse[0] - stroke->initial_mouse[0];
- const float dy = mouse[1] - stroke->initial_mouse[1];
-
- ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
-
- ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
-
- if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
- halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
-
- if (stroke->get_location) {
- if (stroke->get_location(C, r_location, halfway)) {
- hit = true;
- location_sampled = true;
- location_success = true;
- *r_location_is_set = true;
- }
- else if (!paint_tool_require_location(brush, mode)) {
- hit = true;
- }
- }
- else {
- hit = true;
- }
- }
- if (hit) {
- copy_v2_v2(ups->anchored_initial_mouse, halfway);
- copy_v2_v2(ups->tex_mouse, halfway);
- copy_v2_v2(ups->mask_tex_mouse, halfway);
- copy_v2_v2(mouse, halfway);
- ups->anchored_size /= 2.0f;
- ups->pixel_radius /= 2.0f;
- stroke->stroke_distance = ups->pixel_radius;
- }
- else {
- copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
- copy_v2_v2(mouse, stroke->initial_mouse);
- stroke->stroke_distance = ups->pixel_radius;
- }
- ups->pixel_radius /= stroke->zoom_2d;
- ups->draw_anchored = true;
- }
- else {
- /* here we are using the initial mouse coordinate because we do not want the rake
- * result to depend on jittering */
- if (!stroke->brush_init) {
- copy_v2_v2(ups->last_rake, mouse_init);
- }
- /* curve strokes do their own rake calculation */
- else if (!(brush->flag & BRUSH_CURVE)) {
- if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
- /* Not enough motion to define an angle. */
- if (!stroke->rake_started) {
- is_dry_run = true;
- }
- }
- else {
- stroke->rake_started = true;
- }
- }
- }
-
- if ((do_random || do_random_mask) && stroke->rng == NULL) {
- /* Lazy initialization. */
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= (uint)POINTER_AS_INT(brush);
- stroke->rng = BLI_rng_new(rng_seed);
- }
-
- if (do_random) {
- if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
- brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
- }
- }
-
- if (do_random_mask) {
- if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
- ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
- brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
- }
- }
-
- if (!location_sampled) {
- if (stroke->get_location) {
- if (stroke->get_location(C, r_location, mouse)) {
- location_success = true;
- *r_location_is_set = true;
- }
- else if (!paint_tool_require_location(brush, mode))
- location_success = true;
- }
- else {
- zero_v3(r_location);
- location_success = true;
- /* don't set 'r_location_is_set', since we don't want to use the value. */
- }
- }
-
- return location_success && (is_dry_run == false);
+ Scene *scene = CTX_data_scene(C);
+ UnifiedPaintSettings *ups = stroke->ups;
+ bool location_sampled = false;
+ bool location_success = false;
+ /* Use to perform all operations except applying the stroke,
+ * needed for operations that require cursor motion (rake). */
+ bool is_dry_run = false;
+ bool do_random = false;
+ bool do_random_mask = false;
+ *r_location_is_set = false;
+ /* XXX: Use pressure value from first brush step for brushes which don't
+ * support strokes (grab, thumb). They depends on initial state and
+ * brush coord/pressure/etc.
+ * It's more an events design issue, which doesn't split coordinate/pressure/angle
+ * changing events. We should avoid this after events system re-design */
+ if (!stroke->brush_init) {
+ copy_v2_v2(stroke->initial_mouse, mouse);
+ copy_v2_v2(ups->last_rake, mouse);
+ copy_v2_v2(ups->tex_mouse, mouse);
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ stroke->cached_size_pressure = pressure;
+
+ ups->do_linear_conversion = false;
+ ups->colorspace = NULL;
+
+ /* check here if color sampling the main brush should do color conversion. This is done here
+ * to avoid locking up to get the image buffer during sampling */
+ if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
+ ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(
+ brush->mtex.tex->ima, &brush->mtex.tex->iuser, NULL);
+ if (tex_ibuf && tex_ibuf->rect_float == NULL) {
+ ups->do_linear_conversion = true;
+ ups->colorspace = tex_ibuf->rect_colorspace;
+ }
+ BKE_image_pool_release_ibuf(brush->mtex.tex->ima, tex_ibuf, NULL);
+ }
+
+ stroke->brush_init = true;
+ }
+
+ if (paint_supports_dynamic_size(brush, mode)) {
+ copy_v2_v2(ups->tex_mouse, mouse);
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ stroke->cached_size_pressure = pressure;
+ }
+
+ /* Truly temporary data that isn't stored in properties */
+
+ ups->stroke_active = true;
+ ups->size_pressure_value = stroke->cached_size_pressure;
+
+ ups->pixel_radius = BKE_brush_size_get(scene, brush);
+
+ if (BKE_brush_use_size_pressure(scene, brush) && paint_supports_dynamic_size(brush, mode)) {
+ ups->pixel_radius *= stroke->cached_size_pressure;
+ }
+
+ if (paint_supports_dynamic_tex_coords(brush, mode)) {
+
+ if (ELEM(brush->mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM)) {
+ do_random = true;
+ }
+
+ if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coords(ups, false);
+ else {
+ copy_v2_v2(ups->tex_mouse, mouse);
+ }
+
+ /* take care of mask texture, if any */
+ if (brush->mask_mtex.tex) {
+
+ if (ELEM(brush->mask_mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_RANDOM)) {
+ do_random_mask = true;
+ }
+
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coords(ups, true);
+ else {
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ }
+ }
+ }
+
+ if (brush->flag & BRUSH_ANCHORED) {
+ bool hit = false;
+ float halfway[2];
+
+ const float dx = mouse[0] - stroke->initial_mouse[0];
+ const float dy = mouse[1] - stroke->initial_mouse[1];
+
+ ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
+
+ ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
+
+ if (brush->flag & BRUSH_EDGE_TO_EDGE) {
+ halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
+ halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
+
+ if (stroke->get_location) {
+ if (stroke->get_location(C, r_location, halfway)) {
+ hit = true;
+ location_sampled = true;
+ location_success = true;
+ *r_location_is_set = true;
+ }
+ else if (!paint_tool_require_location(brush, mode)) {
+ hit = true;
+ }
+ }
+ else {
+ hit = true;
+ }
+ }
+ if (hit) {
+ copy_v2_v2(ups->anchored_initial_mouse, halfway);
+ copy_v2_v2(ups->tex_mouse, halfway);
+ copy_v2_v2(ups->mask_tex_mouse, halfway);
+ copy_v2_v2(mouse, halfway);
+ ups->anchored_size /= 2.0f;
+ ups->pixel_radius /= 2.0f;
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ else {
+ copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
+ copy_v2_v2(mouse, stroke->initial_mouse);
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ ups->pixel_radius /= stroke->zoom_2d;
+ ups->draw_anchored = true;
+ }
+ else {
+ /* here we are using the initial mouse coordinate because we do not want the rake
+ * result to depend on jittering */
+ if (!stroke->brush_init) {
+ copy_v2_v2(ups->last_rake, mouse_init);
+ }
+ /* curve strokes do their own rake calculation */
+ else if (!(brush->flag & BRUSH_CURVE)) {
+ if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
+ /* Not enough motion to define an angle. */
+ if (!stroke->rake_started) {
+ is_dry_run = true;
+ }
+ }
+ else {
+ stroke->rake_started = true;
+ }
+ }
+ }
+
+ if ((do_random || do_random_mask) && stroke->rng == NULL) {
+ /* Lazy initialization. */
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= (uint)POINTER_AS_INT(brush);
+ stroke->rng = BLI_rng_new(rng_seed);
+ }
+
+ if (do_random) {
+ if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
+ brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
+ }
+ }
+
+ if (do_random_mask) {
+ if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
+ ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
+ brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
+ }
+ }
+
+ if (!location_sampled) {
+ if (stroke->get_location) {
+ if (stroke->get_location(C, r_location, mouse)) {
+ location_success = true;
+ *r_location_is_set = true;
+ }
+ else if (!paint_tool_require_location(brush, mode))
+ location_success = true;
+ }
+ else {
+ zero_v3(r_location);
+ location_success = true;
+ /* don't set 'r_location_is_set', since we don't want to use the value. */
+ }
+ }
+
+ return location_success && (is_dry_run == false);
}
static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
{
- bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ?
- (brush->jitter_absolute != 0) : (brush->jitter != 0);
-
- /* jitter-ed brush gives weird and unpredictable result for this
- * kinds of stroke, so manually disable jitter usage (sergey) */
- use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
- use_jitter &= (!ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) ||
- !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
+ bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? (brush->jitter_absolute != 0) :
+ (brush->jitter != 0);
+ /* jitter-ed brush gives weird and unpredictable result for this
+ * kinds of stroke, so manually disable jitter usage (sergey) */
+ use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
+ use_jitter &= (!ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) ||
+ !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
- return use_jitter;
+ return use_jitter;
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
-static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure)
+static void paint_brush_stroke_add_step(bContext *C,
+ wmOperator *op,
+ const float mouse_in[2],
+ float pressure)
{
- Scene *scene = CTX_data_scene(C);
- Paint *paint = BKE_paint_get_active_from_context(C);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- Brush *brush = BKE_paint_brush(paint);
- PaintStroke *stroke = op->customdata;
- UnifiedPaintSettings *ups = stroke->ups;
- float mouse_out[2];
- PointerRNA itemptr;
- float location[3];
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Brush *brush = BKE_paint_brush(paint);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+ float mouse_out[2];
+ PointerRNA itemptr;
+ float location[3];
/* the following code is adapted from texture paint. It may not be needed but leaving here
* just in case for reference (code in texpaint removed as part of refactoring).
* It's strange that only texpaint had these guards. */
#if 0
- /* special exception here for too high pressure values on first touch in
- * windows for some tablets, then we just skip first touch .. */
- if (tablet && (pressure >= 0.99f) &&
- ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush)))
- {
- return;
- }
-
- /* This can be removed once fixed properly in
- * BKE_brush_painter_paint(
- * BrushPainter *painter, BrushFunc func,
- * float *pos, double time, float pressure, void *user);
- * at zero pressure we should do nothing 1/2^12 is 0.0002
- * which is the sensitivity of the most sensitive pen tablet available */
- if (tablet && (pressure < 0.0002f) &&
- ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
- BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
- BKE_brush_use_size_pressure(scene, pop->s.brush)))
- {
- return;
- }
+ /* special exception here for too high pressure values on first touch in
+ * windows for some tablets, then we just skip first touch .. */
+ if (tablet && (pressure >= 0.99f) &&
+ ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
+ BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
+ BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ {
+ return;
+ }
+
+ /* This can be removed once fixed properly in
+ * BKE_brush_painter_paint(
+ * BrushPainter *painter, BrushFunc func,
+ * float *pos, double time, float pressure, void *user);
+ * at zero pressure we should do nothing 1/2^12 is 0.0002
+ * which is the sensitivity of the most sensitive pen tablet available */
+ if (tablet && (pressure < 0.0002f) &&
+ ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
+ BKE_brush_use_alpha_pressure(scene, pop->s.brush) ||
+ BKE_brush_use_size_pressure(scene, pop->s.brush)))
+ {
+ return;
+ }
#endif
- /* copy last position -before- jittering, or space fill code
- * will create too many dabs */
- copy_v2_v2(stroke->last_mouse_position, mouse_in);
- stroke->last_pressure = pressure;
-
- if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
- float delta[2];
- float factor = stroke->zoom_2d;
-
- if (brush->flag & BRUSH_JITTER_PRESSURE)
- factor *= pressure;
-
- BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
-
- /* XXX: meh, this is round about because
- * BKE_brush_jitter_pos isn't written in the best way to
- * be reused here */
- if (factor != 1.0f) {
- sub_v2_v2v2(delta, mouse_out, mouse_in);
- mul_v2_fl(delta, factor);
- add_v2_v2v2(mouse_out, mouse_in, delta);
- }
- }
- else {
- copy_v2_v2(mouse_out, mouse_in);
- }
-
-
- bool is_location_is_set;
- ups->last_hit = paint_brush_update(
- C, brush, mode, stroke, mouse_in, mouse_out, pressure,
- location, &is_location_is_set);
- if (is_location_is_set) {
- copy_v3_v3(ups->last_location, location);
- }
- if (!ups->last_hit) {
- return;
- }
-
- /* Add to stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set(&itemptr, "size", ups->pixel_radius);
- RNA_float_set_array(&itemptr, "location", location);
- RNA_float_set_array(&itemptr, "mouse", mouse_out);
- RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
- RNA_float_set(&itemptr, "pressure", pressure);
-
- stroke->update_step(C, stroke, &itemptr);
-
- /* don't record this for now, it takes up a lot of memory when doing long
- * strokes with small brush size, and operators have register disabled */
- RNA_collection_clear(op->ptr, "stroke");
+ /* copy last position -before- jittering, or space fill code
+ * will create too many dabs */
+ copy_v2_v2(stroke->last_mouse_position, mouse_in);
+ stroke->last_pressure = pressure;
+
+ if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
+ float delta[2];
+ float factor = stroke->zoom_2d;
+
+ if (brush->flag & BRUSH_JITTER_PRESSURE)
+ factor *= pressure;
+
+ BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
+
+ /* XXX: meh, this is round about because
+ * BKE_brush_jitter_pos isn't written in the best way to
+ * be reused here */
+ if (factor != 1.0f) {
+ sub_v2_v2v2(delta, mouse_out, mouse_in);
+ mul_v2_fl(delta, factor);
+ add_v2_v2v2(mouse_out, mouse_in, delta);
+ }
+ }
+ else {
+ copy_v2_v2(mouse_out, mouse_in);
+ }
+
+ bool is_location_is_set;
+ ups->last_hit = paint_brush_update(
+ C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
+ if (is_location_is_set) {
+ copy_v3_v3(ups->last_location, location);
+ }
+ if (!ups->last_hit) {
+ return;
+ }
+
+ /* Add to stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
+ RNA_float_set(&itemptr, "size", ups->pixel_radius);
+ RNA_float_set_array(&itemptr, "location", location);
+ RNA_float_set_array(&itemptr, "mouse", mouse_out);
+ RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
+ RNA_float_set(&itemptr, "pressure", pressure);
+
+ stroke->update_step(C, stroke, &itemptr);
+
+ /* don't record this for now, it takes up a lot of memory when doing long
+ * strokes with small brush size, and operators have register disabled */
+ RNA_collection_clear(op->ptr, "stroke");
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
-static bool paint_smooth_stroke(
- PaintStroke *stroke, const PaintSample *sample, ePaintMode mode,
- float r_mouse[2], float *r_pressure)
+static bool paint_smooth_stroke(PaintStroke *stroke,
+ const PaintSample *sample,
+ ePaintMode mode,
+ float r_mouse[2],
+ float *r_pressure)
{
- if (paint_supports_smooth_stroke(stroke->brush, mode)) {
- float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
- float u = stroke->brush->smooth_stroke_factor;
-
- /* If the mouse is moving within the radius of the last move,
- * don't update the mouse position. This allows sharp turns. */
- if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
- return false;
- }
-
- interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
- *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
- }
- else {
- r_mouse[0] = sample->mouse[0];
- r_mouse[1] = sample->mouse[1];
- *r_pressure = sample->pressure;
- }
-
- return true;
+ if (paint_supports_smooth_stroke(stroke->brush, mode)) {
+ float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
+ float u = stroke->brush->smooth_stroke_factor;
+
+ /* If the mouse is moving within the radius of the last move,
+ * don't update the mouse position. This allows sharp turns. */
+ if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) {
+ return false;
+ }
+
+ interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
+ *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
+ }
+ else {
+ r_mouse[0] = sample->mouse[0];
+ r_mouse[1] = sample->mouse[1];
+ *r_pressure = sample->pressure;
+ }
+
+ return true;
}
-static float paint_space_stroke_spacing(
- const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure)
+static float paint_space_stroke_spacing(const Scene *scene,
+ PaintStroke *stroke,
+ float size_pressure,
+ float spacing_pressure)
{
- /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
- * causing very high step sizes, hanging blender [#32381] */
- const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
- float spacing = stroke->brush->spacing;
+ /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel
+ * causing very high step sizes, hanging blender [#32381] */
+ const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure);
+ float spacing = stroke->brush->spacing;
- /* apply spacing pressure */
- if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
- spacing = spacing * (1.5f - spacing_pressure);
+ /* apply spacing pressure */
+ if (stroke->brush->flag & BRUSH_SPACING_PRESSURE)
+ spacing = spacing * (1.5f - spacing_pressure);
- /* stroke system is used for 2d paint too, so we need to account for
- * the fact that brush can be scaled there. */
- spacing *= stroke->zoom_2d;
+ /* stroke system is used for 2d paint too, so we need to account for
+ * the fact that brush can be scaled there. */
+ spacing *= stroke->zoom_2d;
- return max_ff(1.0, size_clamp * spacing / 50.0f);
+ return max_ff(1.0, size_clamp * spacing / 50.0f);
}
-
-
static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
{
- int i;
- const int n = 100 / spacing;
- const float h = spacing / 50.0f;
- const float x0 = x - 1;
+ int i;
+ const int n = 100 / spacing;
+ const float h = spacing / 50.0f;
+ const float x0 = x - 1;
- float sum;
+ float sum;
- sum = 0;
- for (i = 0; i < n; i++) {
- float xx;
+ sum = 0;
+ for (i = 0; i < n; i++) {
+ float xx;
- xx = fabsf(x0 + i * h);
+ xx = fabsf(x0 + i * h);
- if (xx < 1.0f)
- sum += BKE_brush_curve_strength(br, xx, 1);
- }
+ if (xx < 1.0f)
+ sum += BKE_brush_curve_strength(br, xx, 1);
+ }
- return sum;
+ return sum;
}
static float paint_stroke_integrate_overlap(Brush *br, float factor)
{
- int i;
- int m;
- float g;
- float max;
-
- float spacing = br->spacing * factor;
-
- if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
- return 1.0;
-
- m = 10;
- g = 1.0f / m;
- max = 0;
- for (i = 0; i < m; i++) {
- float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
-
- if (overlap > max)
- max = overlap;
- }
-
- if (max == 0.0f)
- return 1.0f;
- else
- return 1.0f / max;
+ int i;
+ int m;
+ float g;
+ float max;
+
+ float spacing = br->spacing * factor;
+
+ if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
+ return 1.0;
+
+ m = 10;
+ g = 1.0f / m;
+ max = 0;
+ for (i = 0; i < m; i++) {
+ float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
+
+ if (overlap > max)
+ max = overlap;
+ }
+
+ if (max == 0.0f)
+ return 1.0f;
+ else
+ return 1.0f / max;
}
static float paint_space_stroke_spacing_variable(
- const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
+ const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
{
- if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
- /* use pressure to modify size. set spacing so that at 100%, the circles
- * are aligned nicely with no overlap. for this the spacing needs to be
- * the average of the previous and next size. */
- float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
- float q = s * dpressure / (2.0f * length);
- float pressure_fac = (1.0f + q) / (1.0f - q);
-
- float last_size_pressure = stroke->last_pressure;
- float new_size_pressure = stroke->last_pressure * pressure_fac;
-
- /* average spacing */
- float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
- float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
-
- return 0.5f * (last_spacing + new_spacing);
- }
- else {
- /* no size pressure */
- return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
- }
+ if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
+ /* use pressure to modify size. set spacing so that at 100%, the circles
+ * are aligned nicely with no overlap. for this the spacing needs to be
+ * the average of the previous and next size. */
+ float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ float q = s * dpressure / (2.0f * length);
+ float pressure_fac = (1.0f + q) / (1.0f - q);
+
+ float last_size_pressure = stroke->last_pressure;
+ float new_size_pressure = stroke->last_pressure * pressure_fac;
+
+ /* average spacing */
+ float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure);
+ float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure);
+
+ return 0.5f * (last_spacing + new_spacing);
+ }
+ else {
+ /* no size pressure */
+ return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure);
+ }
}
/* For brushes with stroke spacing enabled, moves mouse in steps
* towards the final mouse location. */
-static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mouse[2], float final_pressure)
+static int paint_space_stroke(bContext *C,
+ wmOperator *op,
+ const float final_mouse[2],
+ float final_pressure)
{
- const Scene *scene = CTX_data_scene(C);
- PaintStroke *stroke = op->customdata;
- UnifiedPaintSettings *ups = stroke->ups;
- int cnt = 0;
+ const Scene *scene = CTX_data_scene(C);
+ PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
+ int cnt = 0;
- float pressure, dpressure;
- float mouse[2], dmouse[2];
- float length;
- float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+ float pressure, dpressure;
+ float mouse[2], dmouse[2];
+ float length;
+ float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- while (length > 0.0f) {
- float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
+ while (length > 0.0f) {
+ float spacing = paint_space_stroke_spacing_variable(
+ scene, stroke, pressure, dpressure, length);
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
- pressure = stroke->last_pressure + (spacing / length) * dpressure;
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ pressure = stroke->last_pressure + (spacing / length) * dpressure;
- ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
+ spacing / no_pressure_spacing);
- stroke->stroke_distance += spacing / stroke->zoom_2d;
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
- length -= spacing;
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ length -= spacing;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- cnt++;
- }
- else {
- break;
- }
- }
+ cnt++;
+ }
+ else {
+ break;
+ }
+ }
- return cnt;
+ return cnt;
}
/**** Public API ****/
-PaintStroke *paint_stroke_new(
- bContext *C,
- wmOperator *op,
- StrokeGetLocation get_location,
- StrokeTestStart test_start,
- StrokeUpdateStep update_step,
- StrokeRedraw redraw,
- StrokeDone done, int event_type)
+PaintStroke *paint_stroke_new(bContext *C,
+ wmOperator *op,
+ StrokeGetLocation get_location,
+ StrokeTestStart test_start,
+ StrokeUpdateStep update_step,
+ StrokeRedraw redraw,
+ StrokeDone done,
+ int event_type)
{
- PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
- ToolSettings *toolsettings = CTX_data_tool_settings(C);
- UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
- Paint *p = BKE_paint_get_active_from_context(C);
- Brush *br = stroke->brush = BKE_paint_brush(p);
- float zoomx, zoomy;
-
- ED_view3d_viewcontext_init(C, &stroke->vc);
-
- stroke->get_location = get_location;
- stroke->test_start = test_start;
- stroke->update_step = update_step;
- stroke->redraw = redraw;
- stroke->done = done;
- stroke->event_type = event_type; /* for modal, return event */
- stroke->ups = ups;
- stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
-
- get_imapaint_zoom(C, &zoomx, &zoomy);
- stroke->zoom_2d = max_ff(zoomx, zoomy);
-
- if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
- if (br->flag & (BRUSH_CURVE)) {
- RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
- }
- }
- /* initialize here */
- ups->overlap_factor = 1.0;
- ups->stroke_active = true;
-
- zero_v3(ups->average_stroke_accum);
- ups->average_stroke_counter = 0;
-
- /* initialize here to avoid initialization conflict with threaded strokes */
- curvemapping_initialize(br->curve);
- if (p->flags & PAINT_USE_CAVITY_MASK)
- curvemapping_initialize(p->cavity_curve);
-
- BKE_paint_set_overlay_override(br->overlay_flags);
-
- return stroke;
+ PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = stroke->brush = BKE_paint_brush(p);
+ float zoomx, zoomy;
+
+ ED_view3d_viewcontext_init(C, &stroke->vc);
+
+ stroke->get_location = get_location;
+ stroke->test_start = test_start;
+ stroke->update_step = update_step;
+ stroke->redraw = redraw;
+ stroke->done = done;
+ stroke->event_type = event_type; /* for modal, return event */
+ stroke->ups = ups;
+ stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
+
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ stroke->zoom_2d = max_ff(zoomx, zoomy);
+
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
+ if (br->flag & (BRUSH_CURVE)) {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
+ }
+ /* initialize here */
+ ups->overlap_factor = 1.0;
+ ups->stroke_active = true;
+
+ zero_v3(ups->average_stroke_accum);
+ ups->average_stroke_counter = 0;
+
+ /* initialize here to avoid initialization conflict with threaded strokes */
+ curvemapping_initialize(br->curve);
+ if (p->flags & PAINT_USE_CAVITY_MASK)
+ curvemapping_initialize(p->cavity_curve);
+
+ BKE_paint_set_overlay_override(br->overlay_flags);
+
+ return stroke;
}
void paint_stroke_data_free(struct wmOperator *op)
{
- BKE_paint_set_overlay_override(0);
- MEM_SAFE_FREE(op->customdata);
+ BKE_paint_set_overlay_override(0);
+ MEM_SAFE_FREE(op->customdata);
}
static void stroke_done(struct bContext *C, struct wmOperator *op)
{
- struct PaintStroke *stroke = op->customdata;
- UnifiedPaintSettings *ups = stroke->ups;
+ struct PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
- ups->draw_anchored = false;
- ups->stroke_active = false;
+ ups->draw_anchored = false;
+ ups->stroke_active = false;
- /* reset rotation here to avoid doing so in cursor display */
- if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- ups->brush_rotation = 0.0f;
+ /* reset rotation here to avoid doing so in cursor display */
+ if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ ups->brush_rotation = 0.0f;
- if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- ups->brush_rotation_sec = 0.0f;
+ if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
+ ups->brush_rotation_sec = 0.0f;
- if (stroke->stroke_started) {
- if (stroke->redraw)
- stroke->redraw(C, stroke, true);
+ if (stroke->stroke_started) {
+ if (stroke->redraw)
+ stroke->redraw(C, stroke, true);
- if (stroke->done)
- stroke->done(C, stroke);
- }
+ if (stroke->done)
+ stroke->done(C, stroke);
+ }
- if (stroke->timer) {
- WM_event_remove_timer(
- CTX_wm_manager(C),
- CTX_wm_window(C),
- stroke->timer);
- }
+ if (stroke->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
+ }
- if (stroke->rng) {
- BLI_rng_free(stroke->rng);
- }
+ if (stroke->rng) {
+ BLI_rng_free(stroke->rng);
+ }
- if (stroke->stroke_cursor)
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+ if (stroke->stroke_cursor)
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
- BLI_freelistN(&stroke->line);
+ BLI_freelistN(&stroke->line);
- paint_stroke_data_free(op);
+ paint_stroke_data_free(op);
}
/* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
{
- return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
+ return (br->flag & BRUSH_SPACE) && paint_supports_dynamic_size(br, mode);
}
static bool sculpt_is_grab_tool(Brush *br)
{
- return ELEM(
- br->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK);
+ return ELEM(br->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK);
}
/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
{
- if (br->flag & BRUSH_ANCHORED)
- return false;
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
-
- case PAINT_MODE_TEXTURE_2D: /* fall through */
- case PAINT_MODE_TEXTURE_3D:
- if ((br->imagepaint_tool == PAINT_TOOL_FILL) &&
- (br->flag & BRUSH_USE_GRADIENT))
- {
- return false;
- }
- break;
-
- default:
- break;
- }
- return true;
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+
+ case PAINT_MODE_TEXTURE_2D: /* fall through */
+ case PAINT_MODE_TEXTURE_3D:
+ if ((br->imagepaint_tool == PAINT_TOOL_FILL) && (br->flag & BRUSH_USE_GRADIENT)) {
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return true;
}
bool paint_supports_smooth_stroke(Brush *br, ePaintMode mode)
{
- if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
- (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE)))
- {
- return false;
- }
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
- default:
- break;
- }
- return true;
+ if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
+ (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE))) {
+ return false;
+ }
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
}
bool paint_supports_texture(ePaintMode mode)
{
- /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
- return ELEM(mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
+ /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
+ return ELEM(
+ mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
}
/* return true if the brush size can change during paint (normally used for pressure) */
bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
{
- if (br->flag & BRUSH_ANCHORED)
- return false;
-
- switch (mode) {
- case PAINT_MODE_SCULPT:
- if (sculpt_is_grab_tool(br))
- return false;
- break;
- default:
- break;
- }
- return true;
+ if (br->flag & BRUSH_ANCHORED)
+ return false;
+
+ switch (mode) {
+ case PAINT_MODE_SCULPT:
+ if (sculpt_is_grab_tool(br))
+ return false;
+ break;
+ default:
+ break;
+ }
+ return true;
}
#define PAINT_STROKE_MODAL_CANCEL 1
@@ -915,487 +916,486 @@ bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
/* called in paint_ops.c, on each regeneration of keymaps */
struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
{
- static struct EnumPropertyItem modal_items[] = {
- {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0,
- "Cancel",
- "Cancel and undo a stroke in progress"},
+ static struct EnumPropertyItem modal_items[] = {
+ {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel and undo a stroke in progress"},
- { 0 }
- };
+ {0}};
- static const char *name = "Paint Stroke Modal";
+ static const char *name = "Paint Stroke Modal";
- struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
+ struct wmKeyMap *keymap = WM_modalkeymap_get(keyconf, name);
- /* this function is called for each spacetype, only needs to add map once */
- if (!keymap) {
- keymap = WM_modalkeymap_add(keyconf, name, modal_items);
- }
+ /* this function is called for each spacetype, only needs to add map once */
+ if (!keymap) {
+ keymap = WM_modalkeymap_add(keyconf, name, modal_items);
+ }
- return keymap;
+ return keymap;
}
static void paint_stroke_add_sample(
- const Paint *paint,
- PaintStroke *stroke,
- float x, float y, float pressure)
+ const Paint *paint, PaintStroke *stroke, float x, float y, float pressure)
{
- PaintSample *sample = &stroke->samples[stroke->cur_sample];
- int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
-
- sample->mouse[0] = x;
- sample->mouse[1] = y;
- sample->pressure = pressure;
-
- stroke->cur_sample++;
- if (stroke->cur_sample >= max_samples)
- stroke->cur_sample = 0;
- if (stroke->num_samples < max_samples)
- stroke->num_samples++;
+ PaintSample *sample = &stroke->samples[stroke->cur_sample];
+ int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
+
+ sample->mouse[0] = x;
+ sample->mouse[1] = y;
+ sample->pressure = pressure;
+
+ stroke->cur_sample++;
+ if (stroke->cur_sample >= max_samples)
+ stroke->cur_sample = 0;
+ if (stroke->num_samples < max_samples)
+ stroke->num_samples++;
}
-static void paint_stroke_sample_average(
- const PaintStroke *stroke,
- PaintSample *average)
+static void paint_stroke_sample_average(const PaintStroke *stroke, PaintSample *average)
{
- int i;
+ int i;
- memset(average, 0, sizeof(*average));
+ memset(average, 0, sizeof(*average));
- BLI_assert(stroke->num_samples > 0);
+ BLI_assert(stroke->num_samples > 0);
- for (i = 0; i < stroke->num_samples; i++) {
- add_v2_v2(average->mouse, stroke->samples[i].mouse);
- average->pressure += stroke->samples[i].pressure;
- }
+ for (i = 0; i < stroke->num_samples; i++) {
+ add_v2_v2(average->mouse, stroke->samples[i].mouse);
+ average->pressure += stroke->samples[i].pressure;
+ }
- mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
- average->pressure /= stroke->num_samples;
+ mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
+ average->pressure /= stroke->num_samples;
- // printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
+ // printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
}
/**
* Slightly different version of spacing for line/curve strokes,
* makes sure the dabs stay on the line path.
*/
-static void paint_line_strokes_spacing(
- bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue,
- const float old_pos[2], const float new_pos[2])
+static void paint_line_strokes_spacing(bContext *C,
+ wmOperator *op,
+ PaintStroke *stroke,
+ float spacing,
+ float *length_residue,
+ const float old_pos[2],
+ const float new_pos[2])
{
- UnifiedPaintSettings *ups = stroke->ups;
+ UnifiedPaintSettings *ups = stroke->ups;
- float mouse[2], dmouse[2];
- float length;
+ float mouse[2], dmouse[2];
+ float length;
- sub_v2_v2v2(dmouse, new_pos, old_pos);
- copy_v2_v2(stroke->last_mouse_position, old_pos);
+ sub_v2_v2v2(dmouse, new_pos, old_pos);
+ copy_v2_v2(stroke->last_mouse_position, old_pos);
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- BLI_assert(length >= 0.0f);
+ BLI_assert(length >= 0.0f);
- if (length == 0.0f)
- return;
+ if (length == 0.0f)
+ return;
- while (length > 0.0f) {
- float spacing_final = spacing - *length_residue;
- length += *length_residue;
- *length_residue = 0.0;
+ while (length > 0.0f) {
+ float spacing_final = spacing - *length_residue;
+ length += *length_residue;
+ *length_residue = 0.0;
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
- ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
- stroke->stroke_distance += spacing / stroke->zoom_2d;
- paint_brush_stroke_add_step(C, op, mouse, 1.0);
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, 1.0);
- length -= spacing;
- spacing_final = spacing;
- }
- else {
- break;
- }
- }
+ length -= spacing;
+ spacing_final = spacing;
+ }
+ else {
+ break;
+ }
+ }
- *length_residue = length;
+ *length_residue = length;
}
-
static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2])
{
- Brush *br = stroke->brush;
- if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ Brush *br = stroke->brush;
+ if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
- paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
- paint_space_stroke(C, op, mouse, 1.0);
- }
+ paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
+ paint_space_stroke(C, op, mouse, 1.0);
+ }
}
static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
{
- Brush *br = stroke->brush;
+ Brush *br = stroke->brush;
- if (br->flag & BRUSH_CURVE) {
- UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
- const Scene *scene = CTX_data_scene(C);
- const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
- PaintCurve *pc = br->paint_curve;
- PaintCurvePoint *pcp;
- float length_residue = 0.0f;
- int i;
+ if (br->flag & BRUSH_CURVE) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ const Scene *scene = CTX_data_scene(C);
+ const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+ float length_residue = 0.0f;
+ int i;
- if (!pc)
- return true;
+ if (!pc)
+ return true;
#ifdef DEBUG_TIME
- TIMEIT_START_AVERAGED(whole_stroke);
+ TIMEIT_START_AVERAGED(whole_stroke);
#endif
- pcp = pc->points;
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
-
- for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
- int j;
- float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
- float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
- PaintCurvePoint *pcp_next = pcp + 1;
- bool do_rake = false;
-
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_bezier(
- pcp->bez.vec[1][j],
- pcp->bez.vec[2][j],
- pcp_next->bez.vec[0][j],
- pcp_next->bez.vec[1][j],
- data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
- }
-
- if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
- (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE))
- {
- do_rake = true;
- for (j = 0; j < 2; j++) {
- BKE_curve_forward_diff_tangent_bezier(
- pcp->bez.vec[1][j],
- pcp->bez.vec[2][j],
- pcp_next->bez.vec[0][j],
- pcp_next->bez.vec[1][j],
- tangents + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
- }
- }
-
- for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
- if (do_rake) {
- float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
- paint_update_brush_rake_rotation(ups, br, rotation);
- }
-
- if (!stroke->stroke_started) {
- stroke->last_pressure = 1.0;
- copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
- stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
-
- if (stroke->stroke_started) {
- paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
- paint_line_strokes_spacing(
- C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
- }
- }
- else {
- paint_line_strokes_spacing(
- C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
- }
- }
- }
-
- stroke_done(C, op);
+ pcp = pc->points;
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
+ int j;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ PaintCurvePoint *pcp_next = pcp + 1;
+ bool do_rake = false;
+
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_bezier(pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ data + j,
+ PAINT_CURVE_NUM_SEGMENTS,
+ sizeof(float[2]));
+ }
+
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ do_rake = true;
+ for (j = 0; j < 2; j++) {
+ BKE_curve_forward_diff_tangent_bezier(pcp->bez.vec[1][j],
+ pcp->bez.vec[2][j],
+ pcp_next->bez.vec[0][j],
+ pcp_next->bez.vec[1][j],
+ tangents + j,
+ PAINT_CURVE_NUM_SEGMENTS,
+ sizeof(float[2]));
+ }
+ }
+
+ for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (do_rake) {
+ float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
+ paint_update_brush_rake_rotation(ups, br, rotation);
+ }
+
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = 1.0;
+ copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
+ stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
+
+ if (stroke->stroke_started) {
+ paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
+ paint_line_strokes_spacing(
+ C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ else {
+ paint_line_strokes_spacing(
+ C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ }
+
+ stroke_done(C, op);
#ifdef DEBUG_TIME
- TIMEIT_END_AVERAGED(whole_stroke);
+ TIMEIT_END_AVERAGED(whole_stroke);
#endif
- return true;
- }
+ return true;
+ }
- return false;
+ return false;
}
static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
{
- if (stroke->constrain_line) {
- float line[2];
- float angle, len, res;
-
- sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
- angle = atan2f(line[1], line[0]);
- len = len_v2(line);
-
- /* divide angle by PI/4 */
- angle = 4.0f * angle / (float)M_PI;
-
- /* now take residue */
- res = angle - floorf(angle);
-
- /* residue decides how close we are at a certain angle */
- if (res <= 0.5f) {
- angle = floorf(angle) * (float)M_PI_4;
- }
- else {
- angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
- }
-
- mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
- mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
- }
+ if (stroke->constrain_line) {
+ float line[2];
+ float angle, len, res;
+
+ sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
+ angle = atan2f(line[1], line[0]);
+ len = len_v2(line);
+
+ /* divide angle by PI/4 */
+ angle = 4.0f * angle / (float)M_PI;
+
+ /* now take residue */
+ res = angle - floorf(angle);
+
+ /* residue decides how close we are at a certain angle */
+ if (res <= 0.5f) {
+ angle = floorf(angle) * (float)M_PI_4;
+ }
+ else {
+ angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
+ }
+
+ mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
+ mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
+ }
}
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- ePaintMode mode = BKE_paintmode_get_active_from_context(C);
- PaintStroke *stroke = op->customdata;
- Brush *br = stroke->brush;
- PaintSample sample_average;
- float mouse[2];
- bool first_dab = false;
- bool first_modal = false;
- bool redraw = false;
- float pressure;
-
- /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
- pressure = (
- (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
- 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL));
-
- paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
- paint_stroke_sample_average(stroke, &sample_average);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ ePaintMode mode = BKE_paintmode_get_active_from_context(C);
+ PaintStroke *stroke = op->customdata;
+ Brush *br = stroke->brush;
+ PaintSample sample_average;
+ float mouse[2];
+ bool first_dab = false;
+ bool first_modal = false;
+ bool redraw = false;
+ float pressure;
+
+ /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
+ pressure = ((br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
+ 1.0f :
+ WM_event_tablet_data(event, &stroke->pen_flip, NULL));
+
+ paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
+ paint_stroke_sample_average(stroke, &sample_average);
#ifdef WITH_INPUT_NDOF
- /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
- * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
- * since the 2D deltas are zero -- code in this file needs to be updated to use the
- * post-NDOF_MOTION MOUSEMOVE */
- if (event->type == NDOF_MOTION)
- return OPERATOR_PASS_THROUGH;
+ /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
+ * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
+ * since the 2D deltas are zero -- code in this file needs to be updated to use the
+ * post-NDOF_MOTION MOUSEMOVE */
+ if (event->type == NDOF_MOTION)
+ return OPERATOR_PASS_THROUGH;
#endif
- /* one time initialization */
- if (!stroke->stroke_init) {
- if (paint_stroke_curve_end(C, op, stroke))
- return OPERATOR_FINISHED;
-
- if (paint_supports_smooth_stroke(br, mode))
- stroke->stroke_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- paint_poll, paint_draw_smooth_cursor, stroke);
-
- stroke->stroke_init = true;
- first_modal = true;
- }
-
- /* one time stroke initialization */
- if (!stroke->stroke_started) {
- stroke->last_pressure = sample_average.pressure;
- copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
- stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
- BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
-
- if (stroke->stroke_started) {
- if (br->flag & BRUSH_AIRBRUSH)
- stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
-
- if (br->flag & BRUSH_LINE) {
- stroke->stroke_cursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_TYPE_ANY, RGN_TYPE_ANY,
- paint_poll, paint_draw_line_cursor, stroke);
- }
-
- first_dab = true;
- }
- }
-
- /* Cancel */
- if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
- if (op->type->cancel) {
- op->type->cancel(C, op);
- }
- else {
- paint_stroke_cancel(C, op);
- }
- return OPERATOR_CANCELLED;
- }
-
- if (event->type == stroke->event_type && !first_modal) {
- if (event->val == KM_RELEASE) {
- copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
- paint_stroke_line_constrain(stroke, mouse);
- paint_stroke_line_end(C, op, stroke, mouse);
- stroke_done(C, op);
- return OPERATOR_FINISHED;
- }
- }
- else if (ELEM(event->type, RETKEY, SPACEKEY)) {
- paint_stroke_line_end(C, op, stroke, sample_average.mouse);
- stroke_done(C, op);
- return OPERATOR_FINISHED;
- }
- else if (br->flag & BRUSH_LINE) {
- if (event->alt)
- stroke->constrain_line = true;
- else
- stroke->constrain_line = false;
-
- copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
- paint_stroke_line_constrain(stroke, mouse);
-
- if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
- if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
- }
- paint_calculate_rake_rotation(stroke->ups, br, mouse);
- }
- }
- else if (first_modal ||
- /* regular dabs */
- (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
- /* airbrush */
- ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
- {
- if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
- if (stroke->stroke_started) {
- if (paint_space_stroke_enabled(br, mode)) {
- if (paint_space_stroke(C, op, mouse, pressure))
- redraw = true;
- }
- else {
- float dmouse[2];
- sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
- stroke->stroke_distance += len_v2(dmouse);
- paint_brush_stroke_add_step(C, op, mouse, pressure);
- redraw = true;
- }
- }
- }
- }
-
- /* we want the stroke to have the first daub at the start location
- * instead of waiting till we have moved the space distance */
- if (first_dab &&
- paint_space_stroke_enabled(br, mode) &&
- !(br->flag & BRUSH_SMOOTH_STROKE))
- {
- stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
- paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
- redraw = true;
- }
-
- /* do updates for redraw. if event is inbetween mousemove there are more
- * coming, so postpone potentially slow redraw updates until all are done */
- if (event->type != INBETWEEN_MOUSEMOVE) {
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
-
- /* At the very least, invalidate the cursor */
- if (ar && (p->flags & PAINT_SHOW_BRUSH))
- WM_paint_cursor_tag_redraw(window, ar);
-
- if (redraw && stroke->redraw)
- stroke->redraw(C, stroke, false);
- }
-
- return OPERATOR_RUNNING_MODAL;
+ /* one time initialization */
+ if (!stroke->stroke_init) {
+ if (paint_stroke_curve_end(C, op, stroke))
+ return OPERATOR_FINISHED;
+
+ if (paint_supports_smooth_stroke(br, mode))
+ stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ paint_poll,
+ paint_draw_smooth_cursor,
+ stroke);
+
+ stroke->stroke_init = true;
+ first_modal = true;
+ }
+
+ /* one time stroke initialization */
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = sample_average.pressure;
+ copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
+ stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
+ BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
+
+ if (stroke->stroke_started) {
+ if (br->flag & BRUSH_AIRBRUSH)
+ stroke->timer = WM_event_add_timer(
+ CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
+
+ if (br->flag & BRUSH_LINE) {
+ stroke->stroke_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
+ SPACE_TYPE_ANY,
+ RGN_TYPE_ANY,
+ paint_poll,
+ paint_draw_line_cursor,
+ stroke);
+ }
+
+ first_dab = true;
+ }
+ }
+
+ /* Cancel */
+ if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
+ if (op->type->cancel) {
+ op->type->cancel(C, op);
+ }
+ else {
+ paint_stroke_cancel(C, op);
+ }
+ return OPERATOR_CANCELLED;
+ }
+
+ if (event->type == stroke->event_type && !first_modal) {
+ if (event->val == KM_RELEASE) {
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+ paint_stroke_line_end(C, op, stroke, mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, RETKEY, SPACEKEY)) {
+ paint_stroke_line_end(C, op, stroke, sample_average.mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ else if (br->flag & BRUSH_LINE) {
+ if (event->alt)
+ stroke->constrain_line = true;
+ else
+ stroke->constrain_line = false;
+
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+
+ if (stroke->stroke_started &&
+ (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
+ (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ }
+ paint_calculate_rake_rotation(stroke->ups, br, mouse);
+ }
+ }
+ else if (first_modal ||
+ /* regular dabs */
+ (!(br->flag & (BRUSH_AIRBRUSH)) &&
+ (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
+ /* airbrush */
+ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER &&
+ event->customdata == stroke->timer)) {
+ if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
+ if (stroke->stroke_started) {
+ if (paint_space_stroke_enabled(br, mode)) {
+ if (paint_space_stroke(C, op, mouse, pressure))
+ redraw = true;
+ }
+ else {
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
+ stroke->stroke_distance += len_v2(dmouse);
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
+ redraw = true;
+ }
+ }
+ }
+ }
+
+ /* we want the stroke to have the first daub at the start location
+ * instead of waiting till we have moved the space distance */
+ if (first_dab && paint_space_stroke_enabled(br, mode) && !(br->flag & BRUSH_SMOOTH_STROKE)) {
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
+ redraw = true;
+ }
+
+ /* do updates for redraw. if event is inbetween mousemove there are more
+ * coming, so postpone potentially slow redraw updates until all are done */
+ if (event->type != INBETWEEN_MOUSEMOVE) {
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* At the very least, invalidate the cursor */
+ if (ar && (p->flags & PAINT_SHOW_BRUSH))
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ if (redraw && stroke->redraw)
+ stroke->redraw(C, stroke, false);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
}
int paint_stroke_exec(bContext *C, wmOperator *op)
{
- PaintStroke *stroke = op->customdata;
+ PaintStroke *stroke = op->customdata;
- /* only when executed for the first time */
- if (stroke->stroke_started == 0) {
- PropertyRNA *strokeprop;
- PointerRNA firstpoint;
- float mouse[2];
+ /* only when executed for the first time */
+ if (stroke->stroke_started == 0) {
+ PropertyRNA *strokeprop;
+ PointerRNA firstpoint;
+ float mouse[2];
- strokeprop = RNA_struct_find_property(op->ptr, "stroke");
+ strokeprop = RNA_struct_find_property(op->ptr, "stroke");
- if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
- RNA_float_get_array(&firstpoint, "mouse", mouse);
- stroke->stroke_started = stroke->test_start(C, op, mouse);
- }
- }
+ if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
+ RNA_float_get_array(&firstpoint, "mouse", mouse);
+ stroke->stroke_started = stroke->test_start(C, op, mouse);
+ }
+ }
- if (stroke->stroke_started) {
- RNA_BEGIN (op->ptr, itemptr, "stroke")
- {
- stroke->update_step(C, stroke, &itemptr);
- }
- RNA_END;
- }
+ if (stroke->stroke_started) {
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ stroke->update_step(C, stroke, &itemptr);
+ }
+ RNA_END;
+ }
- bool ok = (stroke->stroke_started != 0);
+ bool ok = (stroke->stroke_started != 0);
- stroke_done(C, op);
+ stroke_done(C, op);
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void paint_stroke_cancel(bContext *C, wmOperator *op)
{
- stroke_done(C, op);
+ stroke_done(C, op);
}
ViewContext *paint_stroke_view_context(PaintStroke *stroke)
{
- return &stroke->vc;
+ return &stroke->vc;
}
void *paint_stroke_mode_data(struct PaintStroke *stroke)
{
- return stroke->mode_data;
+ return stroke->mode_data;
}
bool paint_stroke_flipped(struct PaintStroke *stroke)
{
- return stroke->pen_flip;
+ return stroke->pen_flip;
}
bool paint_stroke_inverted(struct PaintStroke *stroke)
{
- return stroke->stroke_mode == BRUSH_STROKE_INVERT;
+ return stroke->stroke_mode == BRUSH_STROKE_INVERT;
}
float paint_stroke_distance_get(struct PaintStroke *stroke)
{
- return stroke->stroke_distance;
+ return stroke->stroke_distance;
}
void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
{
- stroke->mode_data = mode_data;
+ stroke->mode_data = mode_data;
}
bool paint_poll(bContext *C)
{
- Paint *p = BKE_paint_get_active_from_context(C);
- Object *ob = CTX_data_active_object(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
-
- if (p && ob && BKE_paint_brush(p) &&
- (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
- (ar && ar->regiontype == RGN_TYPE_WINDOW))
- {
- /* Check the current tool is a brush. */
- bToolRef *tref = sa->runtime.tool;
- if (tref && tref->runtime && tref->runtime->data_block[0]) {
- return true;
- }
- }
- return false;
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Object *ob = CTX_data_active_object(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (p && ob && BKE_paint_brush(p) && (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
+ (ar && ar->regiontype == RGN_TYPE_WINDOW)) {
+ /* Check the current tool is a brush. */
+ bToolRef *tref = sa->runtime.tool;
+ if (tref && tref->runtime && tref->runtime->data_block[0]) {
+ return true;
+ }
+ }
+ return false;
}