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