1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2009 by Nicholas Bishop
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edsculpt
22 */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_listbase.h"
27 #include "BLI_math.h"
28 #include "BLI_rand.h"
29 #include "BLI_utildefines.h"
30
31 #include "PIL_time.h"
32
33 #include "DNA_brush_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "RNA_access.h"
39
40 #include "BKE_brush.h"
41 #include "BKE_colortools.h"
42 #include "BKE_context.h"
43 #include "BKE_curve.h"
44 #include "BKE_image.h"
45 #include "BKE_paint.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "GPU_immediate.h"
51 #include "GPU_state.h"
52
53 #include "ED_screen.h"
54 #include "ED_view3d.h"
55
56 #include "IMB_imbuf_types.h"
57
58 #include "paint_intern.h"
59 #include "sculpt_intern.h"
60
61 #include <float.h>
62 #include <math.h>
63
64 //#define DEBUG_TIME
65
66 #ifdef DEBUG_TIME
67 # include "PIL_time_utildefines.h"
68 #endif
69
70 typedef struct PaintSample {
71 float mouse[2];
72 float pressure;
73 } PaintSample;
74
75 typedef struct PaintStroke {
76 void *mode_data;
77 void *stroke_cursor;
78 wmTimer *timer;
79 struct RNG *rng;
80
81 /* Cached values */
82 ViewContext vc;
83 Brush *brush;
84 UnifiedPaintSettings *ups;
85
86 /* used for lines and curves */
87 ListBase line;
88
89 /* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
90 * to smooth the stroke */
91 PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
92 int num_samples;
93 int cur_sample;
94 int tot_samples;
95
96 float last_mouse_position[2];
97 float last_world_space_position[3];
98 bool stroke_over_mesh;
99 /* space distance covered so far */
100 float stroke_distance;
101
102 /* Set whether any stroke step has yet occurred
103 * e.g. in sculpt mode, stroke doesn't start until cursor
104 * passes over the mesh */
105 bool stroke_started;
106 /* Set when enough motion was found for rake rotation */
107 bool rake_started;
108 /* event that started stroke, for modal() return */
109 int event_type;
110 /* check if stroke variables have been initialized */
111 bool stroke_init;
112 /* check if various brush mapping variables have been initialized */
113 bool brush_init;
114 float initial_mouse[2];
115 /* cached_pressure stores initial pressure for size pressure influence mainly */
116 float cached_size_pressure;
117 /* last pressure will store last pressure value for use in interpolation for space strokes */
118 float last_pressure;
119 int stroke_mode;
120
121 float last_tablet_event_pressure;
122
123 float zoom_2d;
124 int pen_flip;
125
126 /* Tilt, as read from the event. */
127 float x_tilt;
128 float y_tilt;
129
130 /* line constraint */
131 bool constrain_line;
132 float constrained_pos[2];
133
134 StrokeGetLocation get_location;
135 StrokeTestStart test_start;
136 StrokeUpdateStep update_step;
137 StrokeRedraw redraw;
138 StrokeDone done;
139 } PaintStroke;
140
141 /*** Cursors ***/
paint_draw_smooth_cursor(bContext * C,int x,int y,void * customdata)142 static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
143 {
144 Paint *paint = BKE_paint_get_active_from_context(C);
145 Brush *brush = BKE_paint_brush(paint);
146 PaintStroke *stroke = customdata;
147
148 if (stroke && brush) {
149 GPU_line_smooth(true);
150 GPU_blend(GPU_BLEND_ALPHA);
151
152 ARegion *region = stroke->vc.region;
153
154 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
155 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
156 immUniformColor4ubv(paint->paint_cursor_col);
157
158 immBegin(GPU_PRIM_LINES, 2);
159 immVertex2f(pos, x, y);
160 immVertex2f(pos,
161 stroke->last_mouse_position[0] + region->winrct.xmin,
162 stroke->last_mouse_position[1] + region->winrct.ymin);
163
164 immEnd();
165
166 immUnbindProgram();
167
168 GPU_blend(GPU_BLEND_NONE);
169 GPU_line_smooth(false);
170 }
171 }
172
paint_draw_line_cursor(bContext * C,int x,int y,void * customdata)173 static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
174 {
175 Paint *paint = BKE_paint_get_active_from_context(C);
176 PaintStroke *stroke = customdata;
177
178 GPU_line_smooth(true);
179
180 uint shdr_pos = GPU_vertformat_attr_add(
181 immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
182
183 immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
184
185 float viewport_size[4];
186 GPU_viewport_size_get_f(viewport_size);
187 immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
188
189 immUniform1i("colors_len", 2); /* "advanced" mode */
190 const float alpha = (float)paint->paint_cursor_col[3] / 255.0f;
191 immUniformArray4fv(
192 "colors", (float *)(float[][4]){{0.0f, 0.0f, 0.0f, alpha}, {1.0f, 1.0f, 1.0f, alpha}}, 2);
193 immUniform1f("dash_width", 6.0f);
194 immUniform1f("dash_factor", 0.5f);
195
196 immBegin(GPU_PRIM_LINES, 2);
197
198 ARegion *region = stroke->vc.region;
199
200 if (stroke->constrain_line) {
201 immVertex2f(shdr_pos,
202 stroke->last_mouse_position[0] + region->winrct.xmin,
203 stroke->last_mouse_position[1] + region->winrct.ymin);
204
205 immVertex2f(shdr_pos,
206 stroke->constrained_pos[0] + region->winrct.xmin,
207 stroke->constrained_pos[1] + region->winrct.ymin);
208 }
209 else {
210 immVertex2f(shdr_pos,
211 stroke->last_mouse_position[0] + region->winrct.xmin,
212 stroke->last_mouse_position[1] + region->winrct.ymin);
213
214 immVertex2f(shdr_pos, x, y);
215 }
216
217 immEnd();
218
219 immUnbindProgram();
220
221 GPU_line_smooth(false);
222 }
223
paint_tool_require_location(Brush * brush,ePaintMode mode)224 static bool paint_tool_require_location(Brush *brush, ePaintMode mode)
225 {
226 switch (mode) {
227 case PAINT_MODE_SCULPT:
228 if (ELEM(brush->sculpt_tool,
229 SCULPT_TOOL_GRAB,
230 SCULPT_TOOL_ELASTIC_DEFORM,
231 SCULPT_TOOL_POSE,
232 SCULPT_TOOL_BOUNDARY,
233 SCULPT_TOOL_ROTATE,
234 SCULPT_TOOL_SNAKE_HOOK,
235 SCULPT_TOOL_THUMB)) {
236 return false;
237 }
238 else if (SCULPT_is_cloth_deform_brush(brush)) {
239 return false;
240 }
241 else {
242 return true;
243 }
244 default:
245 break;
246 }
247
248 return true;
249 }
250
paint_stroke_use_scene_spacing(Brush * brush,ePaintMode mode)251 static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode)
252 {
253 switch (mode) {
254 case PAINT_MODE_SCULPT:
255 return brush->flag & BRUSH_SCENE_SPACING;
256 default:
257 break;
258 }
259 return false;
260 }
261
paint_tool_require_inbetween_mouse_events(Brush * brush,ePaintMode mode)262 static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode)
263 {
264 if (brush->flag & BRUSH_ANCHORED) {
265 return false;
266 }
267
268 switch (mode) {
269 case PAINT_MODE_SCULPT:
270 if (ELEM(brush->sculpt_tool,
271 SCULPT_TOOL_GRAB,
272 SCULPT_TOOL_ROTATE,
273 SCULPT_TOOL_THUMB,
274 SCULPT_TOOL_SNAKE_HOOK,
275 SCULPT_TOOL_ELASTIC_DEFORM,
276 SCULPT_TOOL_CLOTH,
277 SCULPT_TOOL_BOUNDARY,
278 SCULPT_TOOL_POSE)) {
279 return false;
280 }
281 else {
282 return true;
283 }
284 default:
285 break;
286 }
287
288 return true;
289 }
290
291 /* Initialize the stroke cache variants from operator properties */
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)292 static bool paint_brush_update(bContext *C,
293 Brush *brush,
294 ePaintMode mode,
295 struct PaintStroke *stroke,
296 const float mouse_init[2],
297 float mouse[2],
298 float pressure,
299 float r_location[3],
300 bool *r_location_is_set)
301 {
302 Scene *scene = CTX_data_scene(C);
303 UnifiedPaintSettings *ups = stroke->ups;
304 bool location_sampled = false;
305 bool location_success = false;
306 /* Use to perform all operations except applying the stroke,
307 * needed for operations that require cursor motion (rake). */
308 bool is_dry_run = false;
309 bool do_random = false;
310 bool do_random_mask = false;
311 *r_location_is_set = false;
312 /* XXX: Use pressure value from first brush step for brushes which don't
313 * support strokes (grab, thumb). They depends on initial state and
314 * brush coord/pressure/etc.
315 * It's more an events design issue, which doesn't split coordinate/pressure/angle
316 * changing events. We should avoid this after events system re-design */
317 if (!stroke->brush_init) {
318 copy_v2_v2(stroke->initial_mouse, mouse);
319 copy_v2_v2(ups->last_rake, mouse);
320 copy_v2_v2(ups->tex_mouse, mouse);
321 copy_v2_v2(ups->mask_tex_mouse, mouse);
322 stroke->cached_size_pressure = pressure;
323
324 ups->do_linear_conversion = false;
325 ups->colorspace = NULL;
326
327 /* check here if color sampling the main brush should do color conversion. This is done here
328 * to avoid locking up to get the image buffer during sampling */
329 if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
330 ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(
331 brush->mtex.tex->ima, &brush->mtex.tex->iuser, NULL);
332 if (tex_ibuf && tex_ibuf->rect_float == NULL) {
333 ups->do_linear_conversion = true;
334 ups->colorspace = tex_ibuf->rect_colorspace;
335 }
336 BKE_image_pool_release_ibuf(brush->mtex.tex->ima, tex_ibuf, NULL);
337 }
338
339 stroke->brush_init = true;
340 }
341
342 if (paint_supports_dynamic_size(brush, mode)) {
343 copy_v2_v2(ups->tex_mouse, mouse);
344 copy_v2_v2(ups->mask_tex_mouse, mouse);
345 stroke->cached_size_pressure = pressure;
346 }
347
348 /* Truly temporary data that isn't stored in properties */
349
350 ups->stroke_active = true;
351 ups->size_pressure_value = stroke->cached_size_pressure;
352
353 ups->pixel_radius = BKE_brush_size_get(scene, brush);
354 ups->initial_pixel_radius = BKE_brush_size_get(scene, brush);
355
356 if (BKE_brush_use_size_pressure(brush) && paint_supports_dynamic_size(brush, mode)) {
357 ups->pixel_radius *= stroke->cached_size_pressure;
358 }
359
360 if (paint_supports_dynamic_tex_coords(brush, mode)) {
361
362 if (ELEM(brush->mtex.brush_map_mode,
363 MTEX_MAP_MODE_VIEW,
364 MTEX_MAP_MODE_AREA,
365 MTEX_MAP_MODE_RANDOM)) {
366 do_random = true;
367 }
368
369 if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
370 BKE_brush_randomize_texture_coords(ups, false);
371 }
372 else {
373 copy_v2_v2(ups->tex_mouse, mouse);
374 }
375
376 /* take care of mask texture, if any */
377 if (brush->mask_mtex.tex) {
378
379 if (ELEM(brush->mask_mtex.brush_map_mode,
380 MTEX_MAP_MODE_VIEW,
381 MTEX_MAP_MODE_AREA,
382 MTEX_MAP_MODE_RANDOM)) {
383 do_random_mask = true;
384 }
385
386 if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
387 BKE_brush_randomize_texture_coords(ups, true);
388 }
389 else {
390 copy_v2_v2(ups->mask_tex_mouse, mouse);
391 }
392 }
393 }
394
395 if (brush->flag & BRUSH_ANCHORED) {
396 bool hit = false;
397 float halfway[2];
398
399 const float dx = mouse[0] - stroke->initial_mouse[0];
400 const float dy = mouse[1] - stroke->initial_mouse[1];
401
402 ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
403
404 ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
405
406 if (brush->flag & BRUSH_EDGE_TO_EDGE) {
407 halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
408 halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
409
410 if (stroke->get_location) {
411 if (stroke->get_location(C, r_location, halfway)) {
412 hit = true;
413 location_sampled = true;
414 location_success = true;
415 *r_location_is_set = true;
416 }
417 else if (!paint_tool_require_location(brush, mode)) {
418 hit = true;
419 }
420 }
421 else {
422 hit = true;
423 }
424 }
425 if (hit) {
426 copy_v2_v2(ups->anchored_initial_mouse, halfway);
427 copy_v2_v2(ups->tex_mouse, halfway);
428 copy_v2_v2(ups->mask_tex_mouse, halfway);
429 copy_v2_v2(mouse, halfway);
430 ups->anchored_size /= 2.0f;
431 ups->pixel_radius /= 2.0f;
432 stroke->stroke_distance = ups->pixel_radius;
433 }
434 else {
435 copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
436 copy_v2_v2(mouse, stroke->initial_mouse);
437 stroke->stroke_distance = ups->pixel_radius;
438 }
439 ups->pixel_radius /= stroke->zoom_2d;
440 ups->draw_anchored = true;
441 }
442 else {
443 /* here we are using the initial mouse coordinate because we do not want the rake
444 * result to depend on jittering */
445 if (!stroke->brush_init) {
446 copy_v2_v2(ups->last_rake, mouse_init);
447 }
448 /* curve strokes do their own rake calculation */
449 else if (!(brush->flag & BRUSH_CURVE)) {
450 if (!paint_calculate_rake_rotation(ups, brush, mouse_init)) {
451 /* Not enough motion to define an angle. */
452 if (!stroke->rake_started) {
453 is_dry_run = true;
454 }
455 }
456 else {
457 stroke->rake_started = true;
458 }
459 }
460 }
461
462 if ((do_random || do_random_mask) && stroke->rng == NULL) {
463 /* Lazy initialization. */
464 uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
465 rng_seed ^= (uint)POINTER_AS_INT(brush);
466 stroke->rng = BLI_rng_new(rng_seed);
467 }
468
469 if (do_random) {
470 if (brush->mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
471 ups->brush_rotation += -brush->mtex.random_angle / 2.0f +
472 brush->mtex.random_angle * BLI_rng_get_float(stroke->rng);
473 }
474 }
475
476 if (do_random_mask) {
477 if (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RANDOM) {
478 ups->brush_rotation_sec += -brush->mask_mtex.random_angle / 2.0f +
479 brush->mask_mtex.random_angle * BLI_rng_get_float(stroke->rng);
480 }
481 }
482
483 if (!location_sampled) {
484 if (stroke->get_location) {
485 if (stroke->get_location(C, r_location, mouse)) {
486 location_success = true;
487 *r_location_is_set = true;
488 }
489 else if (!paint_tool_require_location(brush, mode)) {
490 location_success = true;
491 }
492 }
493 else {
494 zero_v3(r_location);
495 location_success = true;
496 /* don't set 'r_location_is_set', since we don't want to use the value. */
497 }
498 }
499
500 return location_success && (is_dry_run == false);
501 }
502
paint_stroke_use_dash(Brush * brush)503 static bool paint_stroke_use_dash(Brush *brush)
504 {
505 /* Only these stroke modes support dash lines */
506 return brush->flag & BRUSH_SPACE || brush->flag & BRUSH_LINE || brush->flag & BRUSH_CURVE;
507 }
508
paint_stroke_use_jitter(ePaintMode mode,Brush * brush,bool invert)509 static bool paint_stroke_use_jitter(ePaintMode mode, Brush *brush, bool invert)
510 {
511 bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ? (brush->jitter_absolute != 0) :
512 (brush->jitter != 0);
513
514 /* jitter-ed brush gives weird and unpredictable result for this
515 * kinds of stroke, so manually disable jitter usage (sergey) */
516 use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
517 use_jitter &= (!ELEM(mode, PAINT_MODE_TEXTURE_2D, PAINT_MODE_TEXTURE_3D) ||
518 !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
519
520 return use_jitter;
521 }
522
523 /* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
paint_brush_stroke_add_step(bContext * C,wmOperator * op,const float mouse_in[2],float pressure)524 static void paint_brush_stroke_add_step(bContext *C,
525 wmOperator *op,
526 const float mouse_in[2],
527 float pressure)
528 {
529 Scene *scene = CTX_data_scene(C);
530 Paint *paint = BKE_paint_get_active_from_context(C);
531 ePaintMode mode = BKE_paintmode_get_active_from_context(C);
532 Brush *brush = BKE_paint_brush(paint);
533 PaintStroke *stroke = op->customdata;
534 UnifiedPaintSettings *ups = stroke->ups;
535 float mouse_out[2];
536 PointerRNA itemptr;
537 float location[3];
538
539 /* the following code is adapted from texture paint. It may not be needed but leaving here
540 * just in case for reference (code in texpaint removed as part of refactoring).
541 * It's strange that only texpaint had these guards. */
542 #if 0
543 /* special exception here for too high pressure values on first touch in
544 * windows for some tablets, then we just skip first touch .. */
545 if (tablet && (pressure >= 0.99f) &&
546 ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
547 BKE_brush_use_alpha_pressure(pop->s.brush) ||
548 BKE_brush_use_size_pressure(pop->s.brush))) {
549 return;
550 }
551
552 /* This can be removed once fixed properly in
553 * BKE_brush_painter_paint(
554 * BrushPainter *painter, BrushFunc func,
555 * float *pos, double time, float pressure, void *user);
556 * at zero pressure we should do nothing 1/2^12 is 0.0002
557 * which is the sensitivity of the most sensitive pen tablet available */
558 if (tablet && (pressure < 0.0002f) &&
559 ((pop->s.brush->flag & BRUSH_SPACING_PRESSURE) ||
560 BKE_brush_use_alpha_pressure(pop->s.brush) ||
561 BKE_brush_use_size_pressure(pop->s.brush))) {
562 return;
563 }
564 #endif
565
566 /* copy last position -before- jittering, or space fill code
567 * will create too many dabs */
568 copy_v2_v2(stroke->last_mouse_position, mouse_in);
569 stroke->last_pressure = pressure;
570
571 if (paint_stroke_use_scene_spacing(brush, mode)) {
572 SCULPT_stroke_get_location(C, stroke->last_world_space_position, stroke->last_mouse_position);
573 mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
574 }
575
576 if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
577 float delta[2];
578 float factor = stroke->zoom_2d;
579
580 if (brush->flag & BRUSH_JITTER_PRESSURE) {
581 factor *= pressure;
582 }
583
584 BKE_brush_jitter_pos(scene, brush, mouse_in, mouse_out);
585
586 /* XXX: meh, this is round about because
587 * BKE_brush_jitter_pos isn't written in the best way to
588 * be reused here */
589 if (factor != 1.0f) {
590 sub_v2_v2v2(delta, mouse_out, mouse_in);
591 mul_v2_fl(delta, factor);
592 add_v2_v2v2(mouse_out, mouse_in, delta);
593 }
594 }
595 else {
596 copy_v2_v2(mouse_out, mouse_in);
597 }
598
599 bool is_location_is_set;
600 ups->last_hit = paint_brush_update(
601 C, brush, mode, stroke, mouse_in, mouse_out, pressure, location, &is_location_is_set);
602 if (is_location_is_set) {
603 copy_v3_v3(ups->last_location, location);
604 }
605 if (!ups->last_hit) {
606 return;
607 }
608
609 /* Dash */
610 bool add_step = true;
611 if (paint_stroke_use_dash(brush)) {
612 int dash_samples = stroke->tot_samples % brush->dash_samples;
613 float dash = (float)dash_samples / (float)brush->dash_samples;
614 if (dash > brush->dash_ratio) {
615 add_step = false;
616 }
617 }
618
619 /* Add to stroke */
620 if (add_step) {
621 RNA_collection_add(op->ptr, "stroke", &itemptr);
622 RNA_float_set(&itemptr, "size", ups->pixel_radius);
623 RNA_float_set_array(&itemptr, "location", location);
624 /* Mouse coordinates modified by the stroke type options. */
625 RNA_float_set_array(&itemptr, "mouse", mouse_out);
626 /* Original mouse coordinates. */
627 RNA_float_set_array(&itemptr, "mouse_event", mouse_in);
628 RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
629 RNA_float_set(&itemptr, "pressure", pressure);
630 RNA_float_set(&itemptr, "x_tilt", stroke->x_tilt);
631 RNA_float_set(&itemptr, "y_tilt", stroke->y_tilt);
632
633 stroke->update_step(C, stroke, &itemptr);
634
635 /* don't record this for now, it takes up a lot of memory when doing long
636 * strokes with small brush size, and operators have register disabled */
637 RNA_collection_clear(op->ptr, "stroke");
638 }
639
640 stroke->tot_samples++;
641 }
642
643 /* Returns zero if no sculpt changes should be made, non-zero otherwise */
paint_smooth_stroke(PaintStroke * stroke,const PaintSample * sample,ePaintMode mode,float r_mouse[2],float * r_pressure)644 static bool paint_smooth_stroke(PaintStroke *stroke,
645 const PaintSample *sample,
646 ePaintMode mode,
647 float r_mouse[2],
648 float *r_pressure)
649 {
650 if (paint_supports_smooth_stroke(stroke->brush, mode)) {
651 float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
652 float u = stroke->brush->smooth_stroke_factor;
653
654 /* If the mouse is moving within the radius of the last move,
655 * don't update the mouse position. This allows sharp turns. */
656 if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < square_f(radius)) {
657 return false;
658 }
659
660 interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u);
661 *r_pressure = interpf(sample->pressure, stroke->last_pressure, u);
662 }
663 else {
664 r_mouse[0] = sample->mouse[0];
665 r_mouse[1] = sample->mouse[1];
666 *r_pressure = sample->pressure;
667 }
668
669 return true;
670 }
671
paint_space_stroke_spacing(bContext * C,const Scene * scene,PaintStroke * stroke,float size_pressure,float spacing_pressure)672 static float paint_space_stroke_spacing(bContext *C,
673 const Scene *scene,
674 PaintStroke *stroke,
675 float size_pressure,
676 float spacing_pressure)
677 {
678 Paint *paint = BKE_paint_get_active_from_context(C);
679 ePaintMode mode = BKE_paintmode_get_active_from_context(C);
680 Brush *brush = BKE_paint_brush(paint);
681 float size_clamp = 0.0f;
682 float size = BKE_brush_size_get(scene, stroke->brush) * size_pressure;
683 if (paint_stroke_use_scene_spacing(brush, mode)) {
684 if (!BKE_brush_use_locked_size(scene, brush)) {
685 float last_object_space_position[3];
686 mul_v3_m4v3(
687 last_object_space_position, stroke->vc.obact->imat, stroke->last_world_space_position);
688 size_clamp = paint_calc_object_space_radius(&stroke->vc, last_object_space_position, size);
689 }
690 else {
691 size_clamp = BKE_brush_unprojected_radius_get(scene, brush) * size_pressure;
692 }
693 }
694 else {
695 /* brushes can have a minimum size of 1.0 but with pressure it can be smaller than a pixel
696 * causing very high step sizes, hanging blender T32381. */
697 size_clamp = max_ff(1.0f, size);
698 }
699
700 float spacing = stroke->brush->spacing;
701
702 /* apply spacing pressure */
703 if (stroke->brush->flag & BRUSH_SPACING_PRESSURE) {
704 spacing = spacing * (1.5f - spacing_pressure);
705 }
706
707 if (SCULPT_is_cloth_deform_brush(brush)) {
708 /* The spacing in tools that use the cloth solver should not be affected by the brush radius to
709 * avoid affecting the simulation update rate when changing the radius of the brush.
710 * With a value of 100 and the brush default of 10 for spacing, a simulation step runs every 2
711 * pixels movement of the cursor. */
712 size_clamp = 100.0f;
713 }
714
715 /* stroke system is used for 2d paint too, so we need to account for
716 * the fact that brush can be scaled there. */
717 spacing *= stroke->zoom_2d;
718
719 if (paint_stroke_use_scene_spacing(brush, mode)) {
720 return max_ff(0.001f, size_clamp * spacing / 50.f);
721 }
722 return max_ff(stroke->zoom_2d, size_clamp * spacing / 50.0f);
723 }
724
paint_stroke_overlapped_curve(Brush * br,float x,float spacing)725 static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
726 {
727 const int n = 100 / spacing;
728 const float h = spacing / 50.0f;
729 const float x0 = x - 1;
730
731 float sum = 0;
732 for (int i = 0; i < n; i++) {
733 float xx;
734
735 xx = fabsf(x0 + i * h);
736
737 if (xx < 1.0f) {
738 sum += BKE_brush_curve_strength(br, xx, 1);
739 }
740 }
741
742 return sum;
743 }
744
paint_stroke_integrate_overlap(Brush * br,float factor)745 static float paint_stroke_integrate_overlap(Brush *br, float factor)
746 {
747 float spacing = br->spacing * factor;
748
749 if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100))) {
750 return 1.0;
751 }
752
753 int m = 10;
754 float g = 1.0f / m;
755 float max = 0;
756 for (int i = 0; i < m; i++) {
757 float overlap = fabs(paint_stroke_overlapped_curve(br, i * g, spacing));
758
759 if (overlap > max) {
760 max = overlap;
761 }
762 }
763
764 if (max == 0.0f) {
765 return 1.0f;
766 }
767 return 1.0f / max;
768 }
769
paint_space_stroke_spacing_variable(bContext * C,const Scene * scene,PaintStroke * stroke,float pressure,float dpressure,float length)770 static float paint_space_stroke_spacing_variable(bContext *C,
771 const Scene *scene,
772 PaintStroke *stroke,
773 float pressure,
774 float dpressure,
775 float length)
776 {
777 if (BKE_brush_use_size_pressure(stroke->brush)) {
778 /* use pressure to modify size. set spacing so that at 100%, the circles
779 * are aligned nicely with no overlap. for this the spacing needs to be
780 * the average of the previous and next size. */
781 float s = paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
782 float q = s * dpressure / (2.0f * length);
783 float pressure_fac = (1.0f + q) / (1.0f - q);
784
785 float last_size_pressure = stroke->last_pressure;
786 float new_size_pressure = stroke->last_pressure * pressure_fac;
787
788 /* average spacing */
789 float last_spacing = paint_space_stroke_spacing(
790 C, scene, stroke, last_size_pressure, pressure);
791 float new_spacing = paint_space_stroke_spacing(C, scene, stroke, new_size_pressure, pressure);
792
793 return 0.5f * (last_spacing + new_spacing);
794 }
795
796 /* no size pressure */
797 return paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
798 }
799
800 /* For brushes with stroke spacing enabled, moves mouse in steps
801 * towards the final mouse location. */
paint_space_stroke(bContext * C,wmOperator * op,const float final_mouse[2],float final_pressure)802 static int paint_space_stroke(bContext *C,
803 wmOperator *op,
804 const float final_mouse[2],
805 float final_pressure)
806 {
807 const Scene *scene = CTX_data_scene(C);
808 ARegion *region = CTX_wm_region(C);
809 PaintStroke *stroke = op->customdata;
810 UnifiedPaintSettings *ups = stroke->ups;
811 Paint *paint = BKE_paint_get_active_from_context(C);
812 ePaintMode mode = BKE_paintmode_get_active_from_context(C);
813 Brush *brush = BKE_paint_brush(paint);
814 int cnt = 0;
815
816 const bool use_scene_spacing = paint_stroke_use_scene_spacing(brush, mode);
817 float d_world_space_position[3] = {0.0f};
818
819 float no_pressure_spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
820 float pressure = stroke->last_pressure;
821 float dpressure = final_pressure - stroke->last_pressure;
822
823 float dmouse[2];
824 sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
825 float length = normalize_v2(dmouse);
826
827 if (use_scene_spacing) {
828 float world_space_position[3];
829 bool hit = SCULPT_stroke_get_location(C, world_space_position, final_mouse);
830 mul_m4_v3(stroke->vc.obact->obmat, world_space_position);
831 if (hit && stroke->stroke_over_mesh) {
832 sub_v3_v3v3(d_world_space_position, world_space_position, stroke->last_world_space_position);
833 length = len_v3(d_world_space_position);
834 stroke->stroke_over_mesh = true;
835 }
836 else {
837 length = 0.0f;
838 zero_v3(d_world_space_position);
839 stroke->stroke_over_mesh = hit;
840 if (stroke->stroke_over_mesh) {
841 copy_v3_v3(stroke->last_world_space_position, world_space_position);
842 }
843 }
844 }
845
846 while (length > 0.0f) {
847 float spacing = paint_space_stroke_spacing_variable(
848 C, scene, stroke, pressure, dpressure, length);
849 float mouse[3];
850
851 if (length >= spacing) {
852 if (use_scene_spacing) {
853 float final_world_space_position[3];
854 normalize_v3(d_world_space_position);
855 mul_v3_v3fl(final_world_space_position, d_world_space_position, spacing);
856 add_v3_v3v3(final_world_space_position,
857 stroke->last_world_space_position,
858 final_world_space_position);
859 ED_view3d_project(region, final_world_space_position, mouse);
860 }
861 else {
862 mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
863 mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
864 }
865 pressure = stroke->last_pressure + (spacing / length) * dpressure;
866
867 ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
868 spacing / no_pressure_spacing);
869
870 stroke->stroke_distance += spacing / stroke->zoom_2d;
871 paint_brush_stroke_add_step(C, op, mouse, pressure);
872
873 length -= spacing;
874 pressure = stroke->last_pressure;
875 dpressure = final_pressure - stroke->last_pressure;
876
877 cnt++;
878 }
879 else {
880 break;
881 }
882 }
883
884 return cnt;
885 }
886
887 /**** Public API ****/
888
paint_stroke_new(bContext * C,wmOperator * op,StrokeGetLocation get_location,StrokeTestStart test_start,StrokeUpdateStep update_step,StrokeRedraw redraw,StrokeDone done,int event_type)889 PaintStroke *paint_stroke_new(bContext *C,
890 wmOperator *op,
891 StrokeGetLocation get_location,
892 StrokeTestStart test_start,
893 StrokeUpdateStep update_step,
894 StrokeRedraw redraw,
895 StrokeDone done,
896 int event_type)
897 {
898 struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
899 PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
900 ToolSettings *toolsettings = CTX_data_tool_settings(C);
901 UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
902 Paint *p = BKE_paint_get_active_from_context(C);
903 Brush *br = stroke->brush = BKE_paint_brush(p);
904 RegionView3D *rv3d = CTX_wm_region_view3d(C);
905 float zoomx, zoomy;
906
907 ED_view3d_viewcontext_init(C, &stroke->vc, depsgraph);
908
909 stroke->get_location = get_location;
910 stroke->test_start = test_start;
911 stroke->update_step = update_step;
912 stroke->redraw = redraw;
913 stroke->done = done;
914 stroke->event_type = event_type; /* for modal, return event */
915 stroke->ups = ups;
916 stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
917
918 get_imapaint_zoom(C, &zoomx, &zoomy);
919 stroke->zoom_2d = max_ff(zoomx, zoomy);
920
921 if (stroke->stroke_mode == BRUSH_STROKE_INVERT) {
922 if (br->flag & BRUSH_CURVE) {
923 RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
924 }
925 }
926 /* initialize here */
927 ups->overlap_factor = 1.0;
928 ups->stroke_active = true;
929
930 if (rv3d) {
931 rv3d->rflag |= RV3D_PAINTING;
932 }
933
934 zero_v3(ups->average_stroke_accum);
935 ups->average_stroke_counter = 0;
936
937 /* initialize here to avoid initialization conflict with threaded strokes */
938 BKE_curvemapping_init(br->curve);
939 if (p->flags & PAINT_USE_CAVITY_MASK) {
940 BKE_curvemapping_init(p->cavity_curve);
941 }
942
943 BKE_paint_set_overlay_override(br->overlay_flags);
944
945 return stroke;
946 }
947
paint_stroke_free(bContext * C,wmOperator * op)948 void paint_stroke_free(bContext *C, wmOperator *op)
949 {
950 RegionView3D *rv3d = CTX_wm_region_view3d(C);
951 if (rv3d) {
952 rv3d->rflag &= ~RV3D_PAINTING;
953 }
954
955 BKE_paint_set_overlay_override(0);
956
957 PaintStroke *stroke = op->customdata;
958 if (stroke == NULL) {
959 return;
960 }
961
962 UnifiedPaintSettings *ups = stroke->ups;
963 ups->draw_anchored = false;
964 ups->stroke_active = false;
965
966 if (stroke->timer) {
967 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
968 }
969
970 if (stroke->rng) {
971 BLI_rng_free(stroke->rng);
972 }
973
974 if (stroke->stroke_cursor) {
975 WM_paint_cursor_end(stroke->stroke_cursor);
976 }
977
978 BLI_freelistN(&stroke->line);
979
980 MEM_SAFE_FREE(op->customdata);
981 }
982
stroke_done(bContext * C,wmOperator * op)983 static void stroke_done(bContext *C, wmOperator *op)
984 {
985 PaintStroke *stroke = op->customdata;
986 UnifiedPaintSettings *ups = stroke->ups;
987
988 /* reset rotation here to avoid doing so in cursor display */
989 if (!(stroke->brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
990 ups->brush_rotation = 0.0f;
991 }
992
993 if (!(stroke->brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
994 ups->brush_rotation_sec = 0.0f;
995 }
996
997 if (stroke->stroke_started) {
998 if (stroke->redraw) {
999 stroke->redraw(C, stroke, true);
1000 }
1001
1002 if (stroke->done) {
1003 stroke->done(C, stroke);
1004 }
1005 }
1006
1007 paint_stroke_free(C, op);
1008 }
1009
1010 /* Returns zero if the stroke dots should not be spaced, non-zero otherwise */
paint_space_stroke_enabled(Brush * br,ePaintMode mode)1011 bool paint_space_stroke_enabled(Brush *br, ePaintMode mode)
1012 {
1013 if ((br->flag & BRUSH_SPACE) == 0) {
1014 return false;
1015 }
1016
1017 if (br->sculpt_tool == SCULPT_TOOL_CLOTH || SCULPT_is_cloth_deform_brush(br)) {
1018 /* The Cloth Brush is a special case for stroke spacing. Even if it has grab modes which do
1019 * not support dynamic size, stroke spacing needs to be enabled so it is possible to control
1020 * whether the simulation runs constantly or only when the brush moves when using the cloth
1021 * grab brushes. */
1022 return true;
1023 }
1024
1025 return paint_supports_dynamic_size(br, mode);
1026 }
1027
sculpt_is_grab_tool(Brush * br)1028 static bool sculpt_is_grab_tool(Brush *br)
1029 {
1030
1031 if (br->sculpt_tool == SCULPT_TOOL_CLOTH && br->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB) {
1032 return true;
1033 }
1034 return ELEM(br->sculpt_tool,
1035 SCULPT_TOOL_GRAB,
1036 SCULPT_TOOL_ELASTIC_DEFORM,
1037 SCULPT_TOOL_POSE,
1038 SCULPT_TOOL_BOUNDARY,
1039 SCULPT_TOOL_THUMB,
1040 SCULPT_TOOL_ROTATE,
1041 SCULPT_TOOL_SNAKE_HOOK);
1042 }
1043
1044 /* return true if the brush size can change during paint (normally used for pressure) */
paint_supports_dynamic_size(Brush * br,ePaintMode mode)1045 bool paint_supports_dynamic_size(Brush *br, ePaintMode mode)
1046 {
1047 if (br->flag & BRUSH_ANCHORED) {
1048 return false;
1049 }
1050
1051 switch (mode) {
1052 case PAINT_MODE_SCULPT:
1053 if (sculpt_is_grab_tool(br)) {
1054 return false;
1055 }
1056 break;
1057
1058 case PAINT_MODE_TEXTURE_2D: /* fall through */
1059 case PAINT_MODE_TEXTURE_3D:
1060 if ((br->imagepaint_tool == PAINT_TOOL_FILL) && (br->flag & BRUSH_USE_GRADIENT)) {
1061 return false;
1062 }
1063 break;
1064
1065 default:
1066 break;
1067 }
1068 return true;
1069 }
1070
paint_supports_smooth_stroke(Brush * br,ePaintMode mode)1071 bool paint_supports_smooth_stroke(Brush *br, ePaintMode mode)
1072 {
1073 if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
1074 (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE))) {
1075 return false;
1076 }
1077
1078 switch (mode) {
1079 case PAINT_MODE_SCULPT:
1080 if (sculpt_is_grab_tool(br)) {
1081 return false;
1082 }
1083 break;
1084 default:
1085 break;
1086 }
1087 return true;
1088 }
1089
paint_supports_texture(ePaintMode mode)1090 bool paint_supports_texture(ePaintMode mode)
1091 {
1092 /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
1093 return ELEM(
1094 mode, PAINT_MODE_SCULPT, PAINT_MODE_VERTEX, PAINT_MODE_TEXTURE_3D, PAINT_MODE_TEXTURE_2D);
1095 }
1096
1097 /* return true if the brush size can change during paint (normally used for pressure) */
paint_supports_dynamic_tex_coords(Brush * br,ePaintMode mode)1098 bool paint_supports_dynamic_tex_coords(Brush *br, ePaintMode mode)
1099 {
1100 if (br->flag & BRUSH_ANCHORED) {
1101 return false;
1102 }
1103
1104 switch (mode) {
1105 case PAINT_MODE_SCULPT:
1106 if (sculpt_is_grab_tool(br)) {
1107 return false;
1108 }
1109 break;
1110 default:
1111 break;
1112 }
1113 return true;
1114 }
1115
1116 #define PAINT_STROKE_MODAL_CANCEL 1
1117
1118 /* called in paint_ops.c, on each regeneration of keymaps */
paint_stroke_modal_keymap(struct wmKeyConfig * keyconf)1119 struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf)
1120 {
1121 static struct EnumPropertyItem modal_items[] = {
1122 {PAINT_STROKE_MODAL_CANCEL, "CANCEL", 0, "Cancel", "Cancel and undo a stroke in progress"},
1123
1124 {0}};
1125
1126 static const char *name = "Paint Stroke Modal";
1127
1128 struct wmKeyMap *keymap = WM_modalkeymap_find(keyconf, name);
1129
1130 /* this function is called for each spacetype, only needs to add map once */
1131 if (!keymap) {
1132 keymap = WM_modalkeymap_ensure(keyconf, name, modal_items);
1133 }
1134
1135 return keymap;
1136 }
1137
paint_stroke_add_sample(const Paint * paint,PaintStroke * stroke,float x,float y,float pressure)1138 static void paint_stroke_add_sample(
1139 const Paint *paint, PaintStroke *stroke, float x, float y, float pressure)
1140 {
1141 PaintSample *sample = &stroke->samples[stroke->cur_sample];
1142 int max_samples = CLAMPIS(paint->num_input_samples, 1, PAINT_MAX_INPUT_SAMPLES);
1143
1144 sample->mouse[0] = x;
1145 sample->mouse[1] = y;
1146 sample->pressure = pressure;
1147
1148 stroke->cur_sample++;
1149 if (stroke->cur_sample >= max_samples) {
1150 stroke->cur_sample = 0;
1151 }
1152 if (stroke->num_samples < max_samples) {
1153 stroke->num_samples++;
1154 }
1155 }
1156
paint_stroke_sample_average(const PaintStroke * stroke,PaintSample * average)1157 static void paint_stroke_sample_average(const PaintStroke *stroke, PaintSample *average)
1158 {
1159 memset(average, 0, sizeof(*average));
1160
1161 BLI_assert(stroke->num_samples > 0);
1162
1163 for (int i = 0; i < stroke->num_samples; i++) {
1164 add_v2_v2(average->mouse, stroke->samples[i].mouse);
1165 average->pressure += stroke->samples[i].pressure;
1166 }
1167
1168 mul_v2_fl(average->mouse, 1.0f / stroke->num_samples);
1169 average->pressure /= stroke->num_samples;
1170
1171 // printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);
1172 }
1173
1174 /**
1175 * Slightly different version of spacing for line/curve strokes,
1176 * makes sure the dabs stay on the line path.
1177 */
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])1178 static void paint_line_strokes_spacing(bContext *C,
1179 wmOperator *op,
1180 PaintStroke *stroke,
1181 float spacing,
1182 float *length_residue,
1183 const float old_pos[2],
1184 const float new_pos[2])
1185 {
1186 UnifiedPaintSettings *ups = stroke->ups;
1187
1188 float mouse[2], dmouse[2];
1189 float length;
1190
1191 sub_v2_v2v2(dmouse, new_pos, old_pos);
1192 copy_v2_v2(stroke->last_mouse_position, old_pos);
1193
1194 length = normalize_v2(dmouse);
1195
1196 BLI_assert(length >= 0.0f);
1197
1198 if (length == 0.0f) {
1199 return;
1200 }
1201
1202 while (length > 0.0f) {
1203 float spacing_final = spacing - *length_residue;
1204 length += *length_residue;
1205 *length_residue = 0.0;
1206
1207 if (length >= spacing) {
1208 mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
1209 mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
1210
1211 ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
1212
1213 stroke->stroke_distance += spacing / stroke->zoom_2d;
1214 paint_brush_stroke_add_step(C, op, mouse, 1.0);
1215
1216 length -= spacing;
1217 spacing_final = spacing;
1218 }
1219 else {
1220 break;
1221 }
1222 }
1223
1224 *length_residue = length;
1225 }
1226
paint_stroke_line_end(bContext * C,wmOperator * op,PaintStroke * stroke,const float mouse[2])1227 static void paint_stroke_line_end(bContext *C,
1228 wmOperator *op,
1229 PaintStroke *stroke,
1230 const float mouse[2])
1231 {
1232 Brush *br = stroke->brush;
1233 if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
1234 stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
1235
1236 paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
1237 paint_space_stroke(C, op, mouse, 1.0);
1238 }
1239 }
1240
paint_stroke_curve_end(bContext * C,wmOperator * op,PaintStroke * stroke)1241 static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
1242 {
1243 Brush *br = stroke->brush;
1244
1245 if (br->flag & BRUSH_CURVE) {
1246 UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
1247 const Scene *scene = CTX_data_scene(C);
1248 const float spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f);
1249 PaintCurve *pc = br->paint_curve;
1250 PaintCurvePoint *pcp;
1251 float length_residue = 0.0f;
1252 int i;
1253
1254 if (!pc) {
1255 return true;
1256 }
1257
1258 #ifdef DEBUG_TIME
1259 TIMEIT_START_AVERAGED(whole_stroke);
1260 #endif
1261
1262 pcp = pc->points;
1263 stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
1264
1265 for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
1266 int j;
1267 float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
1268 float tangents[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
1269 PaintCurvePoint *pcp_next = pcp + 1;
1270 bool do_rake = false;
1271
1272 for (j = 0; j < 2; j++) {
1273 BKE_curve_forward_diff_bezier(pcp->bez.vec[1][j],
1274 pcp->bez.vec[2][j],
1275 pcp_next->bez.vec[0][j],
1276 pcp_next->bez.vec[1][j],
1277 data + j,
1278 PAINT_CURVE_NUM_SEGMENTS,
1279 sizeof(float[2]));
1280 }
1281
1282 if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
1283 (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
1284 do_rake = true;
1285 for (j = 0; j < 2; j++) {
1286 BKE_curve_forward_diff_tangent_bezier(pcp->bez.vec[1][j],
1287 pcp->bez.vec[2][j],
1288 pcp_next->bez.vec[0][j],
1289 pcp_next->bez.vec[1][j],
1290 tangents + j,
1291 PAINT_CURVE_NUM_SEGMENTS,
1292 sizeof(float[2]));
1293 }
1294 }
1295
1296 for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
1297 if (do_rake) {
1298 float rotation = atan2f(tangents[2 * j], tangents[2 * j + 1]);
1299 paint_update_brush_rake_rotation(ups, br, rotation);
1300 }
1301
1302 if (!stroke->stroke_started) {
1303 stroke->last_pressure = 1.0;
1304 copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
1305 stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
1306
1307 if (stroke->stroke_started) {
1308 paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
1309 paint_line_strokes_spacing(
1310 C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
1311 }
1312 }
1313 else {
1314 paint_line_strokes_spacing(
1315 C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
1316 }
1317 }
1318 }
1319
1320 stroke_done(C, op);
1321
1322 #ifdef DEBUG_TIME
1323 TIMEIT_END_AVERAGED(whole_stroke);
1324 #endif
1325
1326 return true;
1327 }
1328
1329 return false;
1330 }
1331
paint_stroke_line_constrain(PaintStroke * stroke,float mouse[2])1332 static void paint_stroke_line_constrain(PaintStroke *stroke, float mouse[2])
1333 {
1334 if (stroke->constrain_line) {
1335 float line[2];
1336 float angle, len, res;
1337
1338 sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
1339 angle = atan2f(line[1], line[0]);
1340 len = len_v2(line);
1341
1342 /* divide angle by PI/4 */
1343 angle = 4.0f * angle / (float)M_PI;
1344
1345 /* now take residue */
1346 res = angle - floorf(angle);
1347
1348 /* residue decides how close we are at a certain angle */
1349 if (res <= 0.5f) {
1350 angle = floorf(angle) * (float)M_PI_4;
1351 }
1352 else {
1353 angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
1354 }
1355
1356 mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
1357 mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
1358 }
1359 }
1360
paint_stroke_modal(bContext * C,wmOperator * op,const wmEvent * event)1361 int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
1362 {
1363 Paint *p = BKE_paint_get_active_from_context(C);
1364 ePaintMode mode = BKE_paintmode_get_active_from_context(C);
1365 PaintStroke *stroke = op->customdata;
1366 Brush *br = stroke->brush = BKE_paint_brush(p);
1367 PaintSample sample_average;
1368 float mouse[2];
1369 bool first_dab = false;
1370 bool first_modal = false;
1371 bool redraw = false;
1372 float pressure;
1373
1374 if (event->type == INBETWEEN_MOUSEMOVE && !paint_tool_require_inbetween_mouse_events(br, mode)) {
1375 return OPERATOR_RUNNING_MODAL;
1376 }
1377
1378 /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
1379 pressure = ((br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ?
1380 1.0f :
1381 WM_event_tablet_data(event, &stroke->pen_flip, NULL));
1382
1383 /* When processing a timer event the pressure from the event is 0, so use the last valid
1384 * pressure. */
1385 if (event->type == TIMER) {
1386 pressure = stroke->last_tablet_event_pressure;
1387 }
1388 else {
1389 stroke->last_tablet_event_pressure = pressure;
1390 }
1391
1392 paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
1393 paint_stroke_sample_average(stroke, &sample_average);
1394
1395 /* Tilt. */
1396 if (WM_event_is_tablet(event)) {
1397 stroke->x_tilt = event->tablet.x_tilt;
1398 stroke->y_tilt = event->tablet.y_tilt;
1399 }
1400
1401 #ifdef WITH_INPUT_NDOF
1402 /* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
1403 * this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
1404 * since the 2D deltas are zero -- code in this file needs to be updated to use the
1405 * post-NDOF_MOTION MOUSEMOVE */
1406 if (event->type == NDOF_MOTION) {
1407 return OPERATOR_PASS_THROUGH;
1408 }
1409 #endif
1410
1411 /* one time initialization */
1412 if (!stroke->stroke_init) {
1413 if (paint_stroke_curve_end(C, op, stroke)) {
1414 return OPERATOR_FINISHED;
1415 }
1416
1417 if (paint_supports_smooth_stroke(br, mode)) {
1418 stroke->stroke_cursor = WM_paint_cursor_activate(
1419 SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_smooth_cursor, stroke);
1420 }
1421
1422 stroke->stroke_init = true;
1423 first_modal = true;
1424 }
1425
1426 /* one time stroke initialization */
1427 if (!stroke->stroke_started) {
1428 stroke->last_pressure = sample_average.pressure;
1429 copy_v2_v2(stroke->last_mouse_position, sample_average.mouse);
1430 if (paint_stroke_use_scene_spacing(br, mode)) {
1431 stroke->stroke_over_mesh = SCULPT_stroke_get_location(
1432 C, stroke->last_world_space_position, sample_average.mouse);
1433 mul_m4_v3(stroke->vc.obact->obmat, stroke->last_world_space_position);
1434 }
1435 stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse);
1436 BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
1437
1438 if (stroke->stroke_started) {
1439 if (br->flag & BRUSH_AIRBRUSH) {
1440 stroke->timer = WM_event_add_timer(
1441 CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
1442 }
1443
1444 if (br->flag & BRUSH_LINE) {
1445 stroke->stroke_cursor = WM_paint_cursor_activate(
1446 SPACE_TYPE_ANY, RGN_TYPE_ANY, paint_poll, paint_draw_line_cursor, stroke);
1447 }
1448
1449 first_dab = true;
1450 }
1451 }
1452
1453 /* Cancel */
1454 if (event->type == EVT_MODAL_MAP && event->val == PAINT_STROKE_MODAL_CANCEL) {
1455 if (op->type->cancel) {
1456 op->type->cancel(C, op);
1457 }
1458 else {
1459 paint_stroke_cancel(C, op);
1460 }
1461 return OPERATOR_CANCELLED;
1462 }
1463
1464 if (event->type == stroke->event_type && !first_modal) {
1465 if (event->val == KM_RELEASE) {
1466 copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
1467 paint_stroke_line_constrain(stroke, mouse);
1468 paint_stroke_line_end(C, op, stroke, mouse);
1469 stroke_done(C, op);
1470 return OPERATOR_FINISHED;
1471 }
1472 }
1473 else if (ELEM(event->type, EVT_RETKEY, EVT_SPACEKEY)) {
1474 paint_stroke_line_end(C, op, stroke, sample_average.mouse);
1475 stroke_done(C, op);
1476 return OPERATOR_FINISHED;
1477 }
1478 else if (br->flag & BRUSH_LINE) {
1479 if (event->alt) {
1480 stroke->constrain_line = true;
1481 }
1482 else {
1483 stroke->constrain_line = false;
1484 }
1485
1486 copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
1487 paint_stroke_line_constrain(stroke, mouse);
1488
1489 if (stroke->stroke_started &&
1490 (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)))) {
1491 if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
1492 (br->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
1493 copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
1494 }
1495 paint_calculate_rake_rotation(stroke->ups, br, mouse);
1496 }
1497 }
1498 else if (first_modal ||
1499 /* regular dabs */
1500 (!(br->flag & BRUSH_AIRBRUSH) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
1501 /* airbrush */
1502 ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER &&
1503 event->customdata == stroke->timer)) {
1504 if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) {
1505 if (stroke->stroke_started) {
1506 if (paint_space_stroke_enabled(br, mode)) {
1507 if (paint_space_stroke(C, op, mouse, pressure)) {
1508 redraw = true;
1509 }
1510 }
1511 else {
1512 float dmouse[2];
1513 sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
1514 stroke->stroke_distance += len_v2(dmouse);
1515 paint_brush_stroke_add_step(C, op, mouse, pressure);
1516 redraw = true;
1517 }
1518 }
1519 }
1520 }
1521
1522 /* we want the stroke to have the first daub at the start location
1523 * instead of waiting till we have moved the space distance */
1524 if (first_dab && paint_space_stroke_enabled(br, mode) && !(br->flag & BRUSH_SMOOTH_STROKE)) {
1525 stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
1526 paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
1527 redraw = true;
1528 }
1529
1530 /* do updates for redraw. if event is in between mouse-move there are more
1531 * coming, so postpone potentially slow redraw updates until all are done */
1532 if (event->type != INBETWEEN_MOUSEMOVE) {
1533 wmWindow *window = CTX_wm_window(C);
1534 ARegion *region = CTX_wm_region(C);
1535
1536 /* At the very least, invalidate the cursor */
1537 if (region && (p->flags & PAINT_SHOW_BRUSH)) {
1538 WM_paint_cursor_tag_redraw(window, region);
1539 }
1540
1541 if (redraw && stroke->redraw) {
1542 stroke->redraw(C, stroke, false);
1543 }
1544 }
1545
1546 return OPERATOR_RUNNING_MODAL;
1547 }
1548
paint_stroke_exec(bContext * C,wmOperator * op)1549 int paint_stroke_exec(bContext *C, wmOperator *op)
1550 {
1551 PaintStroke *stroke = op->customdata;
1552
1553 /* only when executed for the first time */
1554 if (stroke->stroke_started == 0) {
1555 PropertyRNA *strokeprop;
1556 PointerRNA firstpoint;
1557 float mouse[2];
1558
1559 strokeprop = RNA_struct_find_property(op->ptr, "stroke");
1560
1561 if (RNA_property_collection_lookup_int(op->ptr, strokeprop, 0, &firstpoint)) {
1562 RNA_float_get_array(&firstpoint, "mouse", mouse);
1563 stroke->stroke_started = stroke->test_start(C, op, mouse);
1564 }
1565 }
1566
1567 if (stroke->stroke_started) {
1568 RNA_BEGIN (op->ptr, itemptr, "stroke") {
1569 stroke->update_step(C, stroke, &itemptr);
1570 }
1571 RNA_END;
1572 }
1573
1574 bool ok = (stroke->stroke_started != 0);
1575
1576 stroke_done(C, op);
1577
1578 return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1579 }
1580
paint_stroke_cancel(bContext * C,wmOperator * op)1581 void paint_stroke_cancel(bContext *C, wmOperator *op)
1582 {
1583 stroke_done(C, op);
1584 }
1585
paint_stroke_view_context(PaintStroke * stroke)1586 ViewContext *paint_stroke_view_context(PaintStroke *stroke)
1587 {
1588 return &stroke->vc;
1589 }
1590
paint_stroke_mode_data(struct PaintStroke * stroke)1591 void *paint_stroke_mode_data(struct PaintStroke *stroke)
1592 {
1593 return stroke->mode_data;
1594 }
1595
paint_stroke_flipped(struct PaintStroke * stroke)1596 bool paint_stroke_flipped(struct PaintStroke *stroke)
1597 {
1598 return stroke->pen_flip;
1599 }
1600
paint_stroke_inverted(struct PaintStroke * stroke)1601 bool paint_stroke_inverted(struct PaintStroke *stroke)
1602 {
1603 return stroke->stroke_mode == BRUSH_STROKE_INVERT;
1604 }
1605
paint_stroke_distance_get(struct PaintStroke * stroke)1606 float paint_stroke_distance_get(struct PaintStroke *stroke)
1607 {
1608 return stroke->stroke_distance;
1609 }
1610
paint_stroke_set_mode_data(PaintStroke * stroke,void * mode_data)1611 void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
1612 {
1613 stroke->mode_data = mode_data;
1614 }
1615
paint_poll(bContext * C)1616 bool paint_poll(bContext *C)
1617 {
1618 Paint *p = BKE_paint_get_active_from_context(C);
1619 Object *ob = CTX_data_active_object(C);
1620 ScrArea *area = CTX_wm_area(C);
1621 ARegion *region = CTX_wm_region(C);
1622
1623 if (p && ob && BKE_paint_brush(p) &&
1624 (area && ELEM(area->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
1625 (region && region->regiontype == RGN_TYPE_WINDOW)) {
1626 /* Check the current tool is a brush. */
1627 bToolRef *tref = area->runtime.tool;
1628 if (tref && tref->runtime && tref->runtime->data_block[0]) {
1629 return true;
1630 }
1631 }
1632 return false;
1633 }
1634