Blender  V3.3
gpencil_vertex_paint.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2015 Blender Foundation. */
3 
9 #include "MEM_guardedalloc.h"
10 
11 #include "BLI_blenlib.h"
12 #include "BLI_math.h"
13 
14 #include "BLT_translation.h"
15 
16 #include "DNA_brush_types.h"
17 #include "DNA_gpencil_types.h"
18 #include "DNA_material_types.h"
19 
20 #include "BKE_brush.h"
21 #include "BKE_colortools.h"
22 #include "BKE_context.h"
23 #include "BKE_gpencil.h"
24 #include "BKE_material.h"
25 #include "BKE_report.h"
26 
27 #include "WM_api.h"
28 #include "WM_types.h"
29 
30 #include "RNA_access.h"
31 #include "RNA_define.h"
32 #include "RNA_prototypes.h"
33 
34 #include "UI_view2d.h"
35 
36 #include "ED_gpencil.h"
37 #include "ED_screen.h"
38 #include "ED_view3d.h"
39 
40 #include "DEG_depsgraph.h"
41 #include "DEG_depsgraph_query.h"
42 
43 #include "gpencil_intern.h"
44 
45 /* ************************************************ */
46 /* General Brush Editing Context */
47 #define GP_SELECT_BUFFER_CHUNK 256
48 #define GP_GRID_PIXEL_SIZE 10.0f
49 
50 /* Temp Flags while Painting. */
51 typedef enum eGPDvertex_brush_Flag {
52  /* invert the effect of the brush */
54  /* temporary invert action */
57 
58 /* Grid of Colors for Smear. */
59 typedef struct tGP_Grid {
61  float bottom[2];
63  float top[2];
65  float color[4];
67  int totcol;
68 
70 
71 /* List of points affected by brush. */
72 typedef struct tGP_Selected {
76  int pt_index;
78  int pc[2];
80  float color[4];
82 
83 /* Context for brush operators */
84 typedef struct tGP_BrushVertexpaintData {
87 
89 
90  /* Current GPencil datablock */
92 
94  float linear_color[3];
97 
98  /* Space Conversion Data */
100 
101  /* Is the brush currently painting? */
103 
104  /* Start of new paint */
105  bool first;
106 
107  /* Is multiframe editing enabled, and are we using falloff for that? */
110 
111  /* Brush Runtime Data: */
112  /* - position and pressure
113  * - the *_prev variants are the previous values
114  */
115  float mval[2], mval_prev[2];
117 
118  /* - Effect 2D vector */
119  float dvec[2];
120 
121  /* - multiframe falloff factor */
122  float mf_falloff;
123 
124  /* brush geometry (bounding box) */
126 
127  /* Temp data to save selected points */
134 
140  int grid_len;
142  int grid_sample[2];
145 
147 
148 /* Ensure the buffer to hold temp selected point size is enough to save all points selected. */
150  int *buffer_size,
151  int *buffer_used,
152  const bool clear)
153 {
154  tGP_Selected *p = NULL;
155 
156  /* By default a buffer is created with one block with a predefined number of free slots,
157  * if the size is not enough, the cache is reallocated adding a new block of free slots.
158  * This is done in order to keep cache small and improve speed. */
159  if (*buffer_used + 1 > *buffer_size) {
160  if ((*buffer_size == 0) || (buffer_array == NULL)) {
161  p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__);
162  *buffer_size = GP_SELECT_BUFFER_CHUNK;
163  }
164  else {
165  *buffer_size += GP_SELECT_BUFFER_CHUNK;
166  p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size);
167  }
168 
169  if (p == NULL) {
170  *buffer_size = *buffer_used = 0;
171  }
172 
173  buffer_array = p;
174  }
175 
176  /* clear old data */
177  if (clear) {
178  *buffer_used = 0;
179  if (buffer_array != NULL) {
180  memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size);
181  }
182  }
183 
184  return buffer_array;
185 }
186 
187 /* Brush Operations ------------------------------- */
188 
189 /* Invert behavior of brush? */
191 {
192  /* The basic setting is no inverted */
193  bool invert = false;
194 
195  /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
196  if (gso->flag & GP_VERTEX_FLAG_INVERT) {
197  invert ^= true;
198  }
199 
200  return invert;
201 }
202 
203 /* Compute strength of effect. */
204 static float brush_influence_calc(tGP_BrushVertexpaintData *gso, const int radius, const int co[2])
205 {
206  Brush *brush = gso->brush;
207  float influence = brush->size;
208 
209  /* use pressure? */
211  influence *= gso->pressure;
212  }
213 
214  /* distance fading */
215  int mval_i[2];
216  round_v2i_v2fl(mval_i, gso->mval);
217  float distance = (float)len_v2v2_int(mval_i, co);
218 
219  /* Apply Brush curve. */
220  float brush_falloff = BKE_brush_curve_strength(brush, distance, (float)radius);
221  influence *= brush_falloff;
222 
223  /* apply multiframe falloff */
224  influence *= gso->mf_falloff;
225 
226  /* return influence */
227  return influence;
228 }
229 
230 /* Compute effect vector for directional brushes. */
232 {
233  gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
234  gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
235 
236  normalize_v2(gso->dvec);
237 }
238 
239 /* Init a grid of cells around mouse position.
240  *
241  * For each Cell.
242  *
243  * *--------* Top
244  * | |
245  * | |
246  * Bottom *--------*
247  *
248  * The number of cells is calculated using the brush size and a predefined
249  * number of pixels (see: GP_GRID_PIXEL_SIZE)
250  */
251 
253 {
254  tGP_Grid *grid;
255  float bottom[2];
256  float top[2];
257  int grid_index = 0;
258 
259  /* The grid center is (0,0). */
260  bottom[0] = gso->brush_rect.xmin - gso->mval[0];
261  bottom[1] = gso->brush_rect.ymax - GP_GRID_PIXEL_SIZE - gso->mval[1];
262 
263  /* Calc all cell of the grid from top/left. */
264  for (int y = gso->grid_size - 1; y >= 0; y--) {
265  top[1] = bottom[1] + GP_GRID_PIXEL_SIZE;
266 
267  for (int x = 0; x < gso->grid_size; x++) {
268  top[0] = bottom[0] + GP_GRID_PIXEL_SIZE;
269 
270  grid = &gso->grid[grid_index];
271 
272  copy_v2_v2(grid->bottom, bottom);
273  copy_v2_v2(grid->top, top);
274 
276 
277  grid_index++;
278  }
279 
280  /* Reset for new row. */
281  bottom[0] = gso->brush_rect.xmin - gso->mval[0];
283  }
284 }
285 
286 /* Get the index used in the grid base on dvec. */
288 {
289  /* Lower direction. */
290  if (gso->dvec[1] < 0.0f) {
291  if ((gso->dvec[0] >= -1.0f) && (gso->dvec[0] < -0.8f)) {
292  r_idx[0] = 0;
293  r_idx[1] = -1;
294  }
295  else if ((gso->dvec[0] >= -0.8f) && (gso->dvec[0] < -0.6f)) {
296  r_idx[0] = -1;
297  r_idx[1] = -1;
298  }
299  else if ((gso->dvec[0] >= -0.6f) && (gso->dvec[0] < 0.6f)) {
300  r_idx[0] = -1;
301  r_idx[1] = 0;
302  }
303  else if ((gso->dvec[0] >= 0.6f) && (gso->dvec[0] < 0.8f)) {
304  r_idx[0] = -1;
305  r_idx[1] = 1;
306  }
307  else if (gso->dvec[0] >= 0.8f) {
308  r_idx[0] = 0;
309  r_idx[1] = 1;
310  }
311  }
312  /* Upper direction. */
313  else {
314  if ((gso->dvec[0] >= -1.0f) && (gso->dvec[0] < -0.8f)) {
315  r_idx[0] = 0;
316  r_idx[1] = -1;
317  }
318  else if ((gso->dvec[0] >= -0.8f) && (gso->dvec[0] < -0.6f)) {
319  r_idx[0] = 1;
320  r_idx[1] = -1;
321  }
322  else if ((gso->dvec[0] >= -0.6f) && (gso->dvec[0] < 0.6f)) {
323  r_idx[0] = 1;
324  r_idx[1] = 0;
325  }
326  else if ((gso->dvec[0] >= 0.6f) && (gso->dvec[0] < 0.8f)) {
327  r_idx[0] = 1;
328  r_idx[1] = 1;
329  }
330  else if (gso->dvec[0] >= 0.8f) {
331  r_idx[0] = 0;
332  r_idx[1] = 1;
333  }
334  }
335 }
336 
337 static int gpencil_grid_cell_index_get(tGP_BrushVertexpaintData *gso, const int pc[2])
338 {
339  float bottom[2], top[2];
340 
341  for (int i = 0; i < gso->grid_len; i++) {
342  tGP_Grid *grid = &gso->grid[i];
343  add_v2_v2v2(bottom, grid->bottom, gso->mval);
344  add_v2_v2v2(top, grid->top, gso->mval);
345 
346  if (pc[0] >= bottom[0] && pc[0] <= top[0] && pc[1] >= bottom[1] && pc[1] <= top[1]) {
347  return i;
348  }
349  }
350 
351  return -1;
352 }
353 
354 /* Fill the grid with the color in each cell and assign point cell index. */
356 {
357  tGP_Selected *selected = NULL;
358  bGPDstroke *gps_selected = NULL;
359  bGPDspoint *pt = NULL;
360  tGP_Grid *grid = NULL;
361 
362  /* Don't calculate again. */
363  if (gso->grid_ready) {
364  return;
365  }
366 
367  /* Extract colors by cell. */
368  for (int i = 0; i < gso->pbuffer_used; i++) {
369  selected = &gso->pbuffer[i];
370  gps_selected = selected->gps;
371  pt = &gps_selected->points[selected->pt_index];
372  int grid_index = gpencil_grid_cell_index_get(gso, selected->pc);
373 
374  if (grid_index > -1) {
375  grid = &gso->grid[grid_index];
376  /* Add stroke mix color (only if used). */
377  if (pt->vert_color[3] > 0.0f) {
378  add_v3_v3(grid->color, selected->color);
379  grid->color[3] = 1.0f;
380  grid->totcol++;
381  }
382  }
383  }
384 
385  /* Average colors. */
386  for (int i = 0; i < gso->grid_len; i++) {
387  grid = &gso->grid[i];
388  if (grid->totcol > 0) {
389  mul_v3_fl(grid->color, (1.0f / (float)grid->totcol));
390  }
391  }
392 
393  /* Save sample position. */
394  round_v2i_v2fl(gso->grid_sample, gso->mval);
395 
396  gso->grid_ready = true;
397 }
398 
399 /* ************************************************ */
400 /* Brush Callbacks
401  * This section defines the callbacks used by each brush to perform their magic.
402  * These are called on each point within the brush's radius. */
403 
404 /* Tint Brush */
406  bGPDstroke *gps,
407  int pt_index,
408  const int radius,
409  const int co[2])
410 {
411  Brush *brush = gso->brush;
412 
413  /* Attenuate factor to get a smoother tinting. */
414  float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
415  100.0f;
416  float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
417 
418  CLAMP(inf, 0.0f, 1.0f);
419  CLAMP(inf_fill, 0.0f, 1.0f);
420 
421  /* Apply color to Stroke point. */
422  if (GPENCIL_TINT_VERTEX_COLOR_STROKE(brush) && (pt_index > -1)) {
423  bGPDspoint *pt = &gps->points[pt_index];
424  if (brush_invert_check(gso)) {
425  pt->vert_color[3] -= inf;
426  CLAMP_MIN(pt->vert_color[3], 0.0f);
427  }
428  else {
429  /* Pre-multiply. */
430  mul_v3_fl(pt->vert_color, pt->vert_color[3]);
431  /* "Alpha over" blending. */
432  interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf);
433  pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf;
434  /* Un pre-multiply. */
435  if (pt->vert_color[3] > 0.0f) {
436  mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]);
437  }
438  }
439  }
440 
441  /* Apply color to Fill area (all with same color and factor). */
442  if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
443  if (brush_invert_check(gso)) {
444  gps->vert_color_fill[3] -= inf_fill;
445  CLAMP_MIN(gps->vert_color_fill[3], 0.0f);
446  }
447  else {
448  /* Pre-multiply. */
450  /* "Alpha over" blending. */
451  interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill);
452  gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill;
453  /* Un pre-multiply. */
454  if (gps->vert_color_fill[3] > 0.0f) {
455  mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]);
456  }
457  }
458  }
459 
460  return true;
461 }
462 
463 /* Replace Brush (Don't use pressure or invert). */
464 static bool brush_replace_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index)
465 {
466  Brush *brush = gso->brush;
467  bGPDspoint *pt = &gps->points[pt_index];
468 
469  /* Apply color to Stroke point. */
471  if (pt->vert_color[3] > 0.0f) {
473  }
474  }
475 
476  /* Apply color to Fill area (all with same color and factor). */
477  if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
478  if (gps->vert_color_fill[3] > 0.0f) {
480  }
481  }
482 
483  return true;
484 }
485 
486 /* Get surrounding color. */
488  bGPDstroke *gps,
489  int pt_index,
490  float r_color[3])
491 {
492  tGP_Selected *selected = NULL;
493  bGPDstroke *gps_selected = NULL;
494  bGPDspoint *pt = NULL;
495 
496  int totcol = 0;
497  zero_v3(r_color);
498 
499  /* Average the surrounding points except current one. */
500  for (int i = 0; i < gso->pbuffer_used; i++) {
501  selected = &gso->pbuffer[i];
502  gps_selected = selected->gps;
503  /* current point is not evaluated. */
504  if ((gps_selected == gps) && (selected->pt_index == pt_index)) {
505  continue;
506  }
507 
508  pt = &gps_selected->points[selected->pt_index];
509 
510  /* Add stroke mix color (only if used). */
511  if (pt->vert_color[3] > 0.0f) {
512  add_v3_v3(r_color, selected->color);
513  totcol++;
514  }
515  }
516  if (totcol > 0) {
517  mul_v3_fl(r_color, (1.0f / (float)totcol));
518  return true;
519  }
520 
521  return false;
522 }
523 
524 /* Blur Brush */
526  bGPDstroke *gps,
527  int pt_index,
528  const int radius,
529  const int co[2])
530 {
531  Brush *brush = gso->brush;
532 
533  /* Attenuate factor to get a smoother tinting. */
534  float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
535  100.0f;
536  float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
537 
538  bGPDspoint *pt = &gps->points[pt_index];
539 
540  /* Get surrounding color. */
541  float blur_color[3];
542  if (get_surrounding_color(gso, gps, pt_index, blur_color)) {
543  /* Apply color to Stroke point. */
545  interp_v3_v3v3(pt->vert_color, pt->vert_color, blur_color, inf);
546  }
547 
548  /* Apply color to Fill area (all with same color and factor). */
549  if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
550  interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, blur_color, inf_fill);
551  }
552  return true;
553  }
554 
555  return false;
556 }
557 
558 /* Average Brush */
560  bGPDstroke *gps,
561  int pt_index,
562  const int radius,
563  const int co[2],
564  float average_color[3])
565 {
566  Brush *brush = gso->brush;
567 
568  /* Attenuate factor to get a smoother tinting. */
569  float inf = (brush_influence_calc(gso, radius, co) * brush->gpencil_settings->draw_strength) /
570  100.0f;
571  float inf_fill = (gso->pressure * brush->gpencil_settings->draw_strength) / 1000.0f;
572 
573  bGPDspoint *pt = &gps->points[pt_index];
574 
575  float alpha = pt->vert_color[3];
576  float alpha_fill = gps->vert_color_fill[3];
577 
578  if (brush_invert_check(gso)) {
579  alpha -= inf;
580  alpha_fill -= inf_fill;
581  }
582  else {
583  alpha += inf;
584  alpha_fill += inf_fill;
585  }
586 
587  /* Apply color to Stroke point. */
589  CLAMP(alpha, 0.0f, 1.0f);
590  interp_v3_v3v3(pt->vert_color, pt->vert_color, average_color, inf);
591  pt->vert_color[3] = alpha;
592  }
593 
594  /* Apply color to Fill area (all with same color and factor). */
595  if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
596  CLAMP(alpha_fill, 0.0f, 1.0f);
597  copy_v3_v3(gps->vert_color_fill, average_color);
598  gps->vert_color_fill[3] = alpha_fill;
599  }
600 
601  return true;
602 }
603 
604 /* Smear Brush */
606  bGPDstroke *gps,
607  int pt_index,
608  tGP_Selected *selected)
609 {
610  Brush *brush = gso->brush;
611  tGP_Grid *grid = NULL;
612  int average_idx[2];
613  ARRAY_SET_ITEMS(average_idx, 0, 0);
614 
615  bool changed = false;
616 
617  /* Need some movement, so first input is not done. */
618  if (gso->first) {
619  return false;
620  }
621 
622  bGPDspoint *pt = &gps->points[pt_index];
623 
624  /* Need get average colors in the grid. */
625  if ((!gso->grid_ready) && (gso->pbuffer_used > 0)) {
627  }
628 
629  /* The influence is equal to strength and no decay around brush radius. */
630  float inf = brush->gpencil_settings->draw_strength;
631  if (brush->flag & GP_BRUSH_USE_PRESSURE) {
632  inf *= gso->pressure;
633  }
634 
635  /* Calc distance from initial sample location and add a falloff effect. */
636  int mval_i[2];
637  round_v2i_v2fl(mval_i, gso->mval);
638  float distance = (float)len_v2v2_int(mval_i, gso->grid_sample);
639  float fac = 1.0f - (distance / (float)(brush->size * 2));
640  CLAMP(fac, 0.0f, 1.0f);
641  inf *= fac;
642 
643  /* Retry row and col for average color. */
644  gpencil_grid_cell_average_color_idx_get(gso, average_idx);
645 
646  /* Retry average color cell. */
647  int grid_index = gpencil_grid_cell_index_get(gso, selected->pc);
648  if (grid_index > -1) {
649  int row = grid_index / gso->grid_size;
650  int col = grid_index - (gso->grid_size * row);
651  row += average_idx[0];
652  col += average_idx[1];
653  CLAMP(row, 0, gso->grid_size);
654  CLAMP(col, 0, gso->grid_size);
655 
656  int new_index = (row * gso->grid_size) + col;
657  CLAMP(new_index, 0, gso->grid_len - 1);
658  grid = &gso->grid[new_index];
659  }
660 
661  /* Apply color to Stroke point. */
663  if (grid_index > -1) {
664  if (grid->color[3] > 0.0f) {
665  // copy_v3_v3(pt->vert_color, grid->color);
666  interp_v3_v3v3(pt->vert_color, pt->vert_color, grid->color, inf);
667  changed = true;
668  }
669  }
670  }
671 
672  /* Apply color to Fill area (all with same color and factor). */
673  if (GPENCIL_TINT_VERTEX_COLOR_FILL(brush)) {
674  if (grid_index > -1) {
675  if (grid->color[3] > 0.0f) {
676  interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, grid->color, inf);
677  changed = true;
678  }
679  }
680  }
681 
682  return changed;
683 }
684 
685 /* ************************************************ */
686 /* Header Info */
688 {
690  TIP_("GPencil Vertex Paint: LMB to paint | RMB/Escape to Exit"
691  " | Ctrl to Invert Action"));
692 }
693 
694 /* ************************************************ */
695 /* Grease Pencil Vertex Paint Operator */
696 
697 /* Init/Exit ----------------------------------------------- */
698 
700 {
704  Paint *paint = ob->mode == OB_MODE_VERTEX_GPENCIL ? &ts->gp_vertexpaint->paint :
705  &ts->gp_paint->paint;
706 
707  /* set the brush using the tool */
709 
710  /* setup operator data */
711  gso = MEM_callocN(sizeof(tGP_BrushVertexpaintData), "tGP_BrushVertexpaintData");
712  op->customdata = gso;
713 
714  gso->brush = paint->brush;
717 
718  gso->is_painting = false;
719  gso->first = true;
720 
721  gso->pbuffer = NULL;
722  gso->pbuffer_size = 0;
723  gso->pbuffer_used = 0;
724 
725  /* Alloc grid array */
726  gso->grid_size = (int)(((gso->brush->size * 2.0f) / GP_GRID_PIXEL_SIZE) + 1.0);
727  /* Square value. */
728  gso->grid_len = gso->grid_size * gso->grid_size;
729  gso->grid = MEM_callocN(sizeof(tGP_Grid) * gso->grid_len, "tGP_Grid");
730  gso->grid_ready = false;
731 
733  gso->scene = scene;
734  gso->object = ob;
735 
736  gso->region = CTX_wm_region(C);
737 
738  /* Save mask. */
739  gso->mask = ts->gpencil_selectmode_vertex;
740 
741  /* Multi-frame settings. */
744 
745  /* Init multi-edit falloff curve data before doing anything,
746  * so we won't have to do it again later. */
747  if (gso->is_multiframe) {
749  }
750 
751  /* Setup space conversions. */
753 
754  /* Update header. */
756 
757  return true;
758 }
759 
761 {
763 
764  /* Disable headerprints. */
766 
767  /* Disable temp invert flag. */
769 
770  /* Free operator data */
771  MEM_SAFE_FREE(gso->pbuffer);
772  MEM_SAFE_FREE(gso->grid);
773  MEM_SAFE_FREE(gso);
774  op->customdata = NULL;
775 }
776 
777 /* Poll callback for stroke vertex paint operator. */
779 {
780  /* NOTE: this is a bit slower, but is the most accurate... */
781  return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
782 }
783 
784 /* Helper to save the points selected by the brush. */
786  bGPDstroke *gps,
787  int index,
788  int pc[2])
789 {
790  tGP_Selected *selected;
791  bGPDspoint *pt = &gps->points[index];
792 
793  /* Ensure the array to save the list of selected points is big enough. */
795  gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false);
796 
797  selected = &gso->pbuffer[gso->pbuffer_used];
798  selected->gps = gps;
799  selected->pt_index = index;
800  /* Check the index is not a special case for fill. */
801  if (index > -1) {
802  copy_v2_v2_int(selected->pc, pc);
803  copy_v4_v4(selected->color, pt->vert_color);
804  }
805  gso->pbuffer_used++;
806 }
807 
808 /* Select points in this stroke and add to an array to be used later.
809  * Returns true if any point was hit and got saved */
811  bGPDstroke *gps,
812  const char tool,
813  const float diff_mat[4][4],
814  const float bound_mat[4][4])
815 {
816  GP_SpaceConversion *gsc = &gso->gsc;
817  rcti *rect = &gso->brush_rect;
818  Brush *brush = gso->brush;
819  const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
820  gso->brush->size;
821  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
822  bGPDspoint *pt_active = NULL;
823 
824  bGPDspoint *pt1, *pt2;
825  bGPDspoint *pt = NULL;
826  int pc1[2] = {0};
827  int pc2[2] = {0};
828  int i;
829  int index;
830  bool include_last = false;
831 
832  bool saved = false;
833 
834  /* Check stroke masking. */
835  if (GPENCIL_ANY_VERTEX_MASK(gso->mask)) {
836  if ((gps->flag & GP_STROKE_SELECT) == 0) {
837  return false;
838  }
839  }
840 
841  /* Check if the stroke collide with brush. */
842  if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
843  return false;
844  }
845 
846  if (gps->totpoints == 1) {
847  bGPDspoint pt_temp;
848  pt = &gps->points[0];
849  gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
850  gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
851 
852  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
853  /* Do bound-box check first. */
854  if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
855  /* only check if point is inside */
856  int mval_i[2];
857  round_v2i_v2fl(mval_i, gso->mval);
858  if (len_v2v2_int(mval_i, pc1) <= radius) {
859  /* apply operation to this point */
860  if (pt_active != NULL) {
861  gpencil_save_selected_point(gso, gps_active, 0, pc1);
862  saved = true;
863  }
864  }
865  }
866  }
867  else {
868  /* Loop over the points in the stroke, checking for intersections
869  * - an intersection means that we touched the stroke
870  */
871  bool hit = false;
872  for (i = 0; (i + 1) < gps->totpoints; i++) {
873  /* Get points to work with */
874  pt1 = gps->points + i;
875  pt2 = gps->points + i + 1;
876 
877  /* Skip if neither one is selected
878  * (and we are only allowed to edit/consider selected points) */
879  if (GPENCIL_ANY_VERTEX_MASK(gso->mask)) {
880  if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
881  include_last = false;
882  continue;
883  }
884  }
885 
886  bGPDspoint npt;
887  gpencil_point_to_parent_space(pt1, diff_mat, &npt);
888  gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
889 
890  gpencil_point_to_parent_space(pt2, diff_mat, &npt);
891  gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
892 
893  /* Check that point segment of the bound-box of the selection stroke. */
894  if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
895  ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
896  /* Check if point segment of stroke had anything to do with
897  * brush region (either within stroke painted, or on its lines)
898  * - this assumes that line-width is irrelevant.
899  */
900  if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
901 
902  /* To each point individually... */
903  pt = &gps->points[i];
904  pt_active = pt->runtime.pt_orig;
905  if (pt_active != NULL) {
906  /* If masked and the point is not selected, skip it. */
907  if (GPENCIL_ANY_VERTEX_MASK(gso->mask) &&
908  ((pt_active->flag & GP_SPOINT_SELECT) == 0)) {
909  continue;
910  }
911  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
912  hit = true;
913  gpencil_save_selected_point(gso, gps_active, index, pc1);
914  saved = true;
915  }
916 
917  /* Only do the second point if this is the last segment,
918  * and it is unlikely that the point will get handled
919  * otherwise.
920  *
921  * NOTE: There is a small risk here that the second point wasn't really
922  * actually in-range. In that case, it only got in because
923  * the line linking the points was!
924  */
925  if (i + 1 == gps->totpoints - 1) {
926  pt = &gps->points[i + 1];
927  pt_active = pt->runtime.pt_orig;
928  if (pt_active != NULL) {
929  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
930  hit = true;
931  gpencil_save_selected_point(gso, gps_active, index, pc2);
932  include_last = false;
933  saved = true;
934  }
935  }
936  else {
937  include_last = true;
938  }
939  }
940  else if (include_last) {
941  /* This case is for cases where for whatever reason the second vert (1st here)
942  * doesn't get included because the whole edge isn't in bounds,
943  * but it would've qualified since it did with the previous step
944  * (but wasn't added then, to avoid double-ups).
945  */
946  pt = &gps->points[i];
947  pt_active = pt->runtime.pt_orig;
948  if (pt_active != NULL) {
949  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
950  hit = true;
951  gpencil_save_selected_point(gso, gps_active, index, pc1);
952  include_last = false;
953  saved = true;
954  }
955  }
956  }
957  }
958 
959  /* If nothing hit, check if the mouse is inside any filled stroke. */
960  if ((!hit) && (ELEM(tool, GPAINT_TOOL_TINT, GPVERTEX_TOOL_DRAW))) {
962  gps_active->mat_nr + 1);
963  if (gp_style->flag & GP_MATERIAL_FILL_SHOW) {
964  int mval[2];
965  round_v2i_v2fl(mval, gso->mval);
966  bool hit_fill = ED_gpencil_stroke_point_is_inside(gps_active, gsc, mval, diff_mat);
967  if (hit_fill) {
968  /* Need repeat the effect because if we don't do that the tint process
969  * is very slow. */
970  for (int repeat = 0; repeat < 50; repeat++) {
971  gpencil_save_selected_point(gso, gps_active, -1, NULL);
972  }
973  saved = true;
974  }
975  }
976  }
977  }
978 
979  return saved;
980 }
981 
982 /* Apply vertex paint brushes to strokes in the given frame. */
985  bGPDlayer *gpl,
986  bGPDframe *gpf,
987  const float diff_mat[4][4],
988  const float bound_mat[4][4])
989 {
991  const char tool = ob->mode == OB_MODE_VERTEX_GPENCIL ? gso->brush->gpencil_vertex_tool :
992  gso->brush->gpencil_tool;
993  const int radius = (gso->brush->flag & GP_BRUSH_USE_PRESSURE) ?
994  gso->brush->size * gso->pressure :
995  gso->brush->size;
996  tGP_Selected *selected = NULL;
997  int i;
998 
999  /*---------------------------------------------------------------------
1000  * First step: select the points affected. This step is required to have
1001  * all selected points before apply the effect, because it could be
1002  * required to average data.
1003  *--------------------------------------------------------------------- */
1004  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1005  /* Skip strokes that are invalid for current view. */
1006  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1007  continue;
1008  }
1009  /* Check if the color is editable. */
1010  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
1011  continue;
1012  }
1013 
1014  /* Check points below the brush. */
1015  bool hit = gpencil_vertexpaint_select_stroke(gso, gps, tool, diff_mat, bound_mat);
1016 
1017  /* If stroke was hit and has an editcurve the curve needs an update. */
1018  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
1019  if (gps_active->editcurve != NULL && hit) {
1021  }
1022  }
1023 
1024  /* For Average tool, need calculate the average resulting color from all colors
1025  * under the brush. */
1026  float average_color[3] = {0};
1027  int totcol = 0;
1028  if ((tool == GPVERTEX_TOOL_AVERAGE) && (gso->pbuffer_used > 0)) {
1029  for (i = 0; i < gso->pbuffer_used; i++) {
1030  selected = &gso->pbuffer[i];
1031  bGPDstroke *gps = selected->gps;
1032  bGPDspoint *pt = &gps->points[selected->pt_index];
1033 
1034  /* Add stroke mix color (only if used). */
1035  if (pt->vert_color[3] > 0.0f) {
1036  add_v3_v3(average_color, pt->vert_color);
1037  totcol++;
1038  }
1039 
1040  /* If Fill color mix, add to average. */
1041  if (gps->vert_color_fill[3] > 0.0f) {
1042  add_v3_v3(average_color, gps->vert_color_fill);
1043  totcol++;
1044  }
1045  }
1046 
1047  /* Get average. */
1048  if (totcol > 0) {
1049  mul_v3_fl(average_color, (1.0f / (float)totcol));
1050  }
1051  }
1052 
1053  /*---------------------------------------------------------------------
1054  * Second step: Apply effect.
1055  *--------------------------------------------------------------------- */
1056  bool changed = false;
1057  for (i = 0; i < gso->pbuffer_used; i++) {
1058  changed = true;
1059  selected = &gso->pbuffer[i];
1060 
1061  switch (tool) {
1062  case GPAINT_TOOL_TINT:
1063  case GPVERTEX_TOOL_DRAW: {
1064  brush_tint_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
1065  changed |= true;
1066  break;
1067  }
1068  case GPVERTEX_TOOL_BLUR: {
1069  brush_blur_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
1070  changed |= true;
1071  break;
1072  }
1073  case GPVERTEX_TOOL_AVERAGE: {
1075  gso, selected->gps, selected->pt_index, radius, selected->pc, average_color);
1076  changed |= true;
1077  break;
1078  }
1079  case GPVERTEX_TOOL_SMEAR: {
1080  brush_smear_apply(gso, selected->gps, selected->pt_index, selected);
1081  changed |= true;
1082  break;
1083  }
1084  case GPVERTEX_TOOL_REPLACE: {
1085  brush_replace_apply(gso, selected->gps, selected->pt_index);
1086  changed |= true;
1087  break;
1088  }
1089 
1090  default:
1091  printf("ERROR: Unknown type of GPencil Vertex Paint brush\n");
1092  break;
1093  }
1094  }
1095  /* Clear the selected array, but keep the memory allocation. */
1097  gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true);
1098 
1099  return changed;
1100 }
1101 
1102 /* Apply brush effect to all layers. */
1104 {
1107  Object *obact = gso->object;
1108  bool changed = false;
1109 
1110  Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
1111  bGPdata *gpd = (bGPdata *)ob_eval->data;
1112 
1113  /* Find visible strokes, and perform operations on those if hit */
1114  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1115  /* If locked or no active frame, don't do anything. */
1116  if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
1117  continue;
1118  }
1119 
1120  /* Calculate transform matrix. */
1121  float diff_mat[4][4], bound_mat[4][4];
1122  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
1123  copy_m4_m4(bound_mat, diff_mat);
1124  mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
1125 
1126  /* Active Frame or MultiFrame? */
1127  if (gso->is_multiframe) {
1128  /* init multiframe falloff options */
1129  int f_init = 0;
1130  int f_end = 0;
1131 
1132  if (gso->use_multiframe_falloff) {
1133  BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
1134  }
1135 
1136  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1137  /* Always do active frame; Otherwise, only include selected frames */
1138  if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
1139  /* Compute multi-frame falloff factor. */
1140  if (gso->use_multiframe_falloff) {
1141  /* Falloff depends on distance to active frame (relative to the overall frame range) */
1143  gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
1144  }
1145  else {
1146  /* No falloff */
1147  gso->mf_falloff = 1.0f;
1148  }
1149 
1150  /* affect strokes in this frame */
1151  changed |= gpencil_vertexpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat);
1152  }
1153  }
1154  }
1155  else {
1156  /* Apply to active frame's strokes */
1157  if (gpl->actframe != NULL) {
1158  gso->mf_falloff = 1.0f;
1160  C, gso, gpl, gpl->actframe, diff_mat, bound_mat);
1161  }
1162  }
1163  }
1164 
1165  return changed;
1166 }
1167 
1168 /* Calculate settings for applying brush */
1170 {
1172  Brush *brush = gso->brush;
1173  const int radius = ((brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
1174  gso->brush->size);
1175  float mousef[2];
1176  int mouse[2];
1177  bool changed = false;
1178 
1179  /* Get latest mouse coordinates */
1180  RNA_float_get_array(itemptr, "mouse", mousef);
1181  gso->mval[0] = mouse[0] = (int)(mousef[0]);
1182  gso->mval[1] = mouse[1] = (int)(mousef[1]);
1183 
1184  gso->pressure = RNA_float_get(itemptr, "pressure");
1185 
1186  if (RNA_boolean_get(itemptr, "pen_flip")) {
1187  gso->flag |= GP_VERTEX_FLAG_INVERT;
1188  }
1189  else {
1190  gso->flag &= ~GP_VERTEX_FLAG_INVERT;
1191  }
1192 
1193  /* Store coordinates as reference, if operator just started running */
1194  if (gso->first) {
1195  gso->mval_prev[0] = gso->mval[0];
1196  gso->mval_prev[1] = gso->mval[1];
1197  gso->pressure_prev = gso->pressure;
1198  }
1199 
1200  /* Update brush_rect, so that it represents the bounding rectangle of brush. */
1201  gso->brush_rect.xmin = mouse[0] - radius;
1202  gso->brush_rect.ymin = mouse[1] - radius;
1203  gso->brush_rect.xmax = mouse[0] + radius;
1204  gso->brush_rect.ymax = mouse[1] + radius;
1205 
1206  /* Calc 2D direction vector and relative angle. */
1207  brush_calc_dvec_2d(gso);
1208 
1209  /* Calc grid for smear tool. */
1211 
1213 
1214  /* Updates */
1215  if (changed) {
1218  }
1219 
1220  /* Store values for next step */
1221  gso->mval_prev[0] = gso->mval[0];
1222  gso->mval_prev[1] = gso->mval[1];
1223  gso->pressure_prev = gso->pressure;
1224  gso->first = false;
1225 }
1226 
1227 /* Running --------------------------------------------- */
1228 
1229 /* helper - a record stroke, and apply paint event */
1231  wmOperator *op,
1232  const wmEvent *event)
1233 {
1235  PointerRNA itemptr;
1236  float mouse[2];
1237 
1238  mouse[0] = event->mval[0] + 1;
1239  mouse[1] = event->mval[1] + 1;
1240 
1241  /* fill in stroke */
1242  RNA_collection_add(op->ptr, "stroke", &itemptr);
1243 
1244  RNA_float_set_array(&itemptr, "mouse", mouse);
1245  RNA_boolean_set(&itemptr, "pen_flip", event->modifier & KM_CTRL);
1246  RNA_boolean_set(&itemptr, "is_start", gso->first);
1247 
1248  /* Handle pressure sensitivity (which is supplied by tablets). */
1249  float pressure = event->tablet.pressure;
1250  CLAMP(pressure, 0.0f, 1.0f);
1251  RNA_float_set(&itemptr, "pressure", pressure);
1252 
1253  /* apply */
1254  gpencil_vertexpaint_brush_apply(C, op, &itemptr);
1255 }
1256 
1257 /* reapply */
1259 {
1260  if (!gpencil_vertexpaint_brush_init(C, op)) {
1261  return OPERATOR_CANCELLED;
1262  }
1263 
1264  RNA_BEGIN (op->ptr, itemptr, "stroke") {
1265  gpencil_vertexpaint_brush_apply(C, op, &itemptr);
1266  }
1267  RNA_END;
1268 
1270 
1271  return OPERATOR_FINISHED;
1272 }
1273 
1274 /* start modal painting */
1276 {
1278  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1279  const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
1280 
1281  /* the operator cannot work while play animation */
1282  if (is_playing) {
1283  BKE_report(op->reports, RPT_ERROR, "Cannot Paint while play animation");
1284 
1285  return OPERATOR_CANCELLED;
1286  }
1287 
1288  /* init painting data */
1289  if (!gpencil_vertexpaint_brush_init(C, op)) {
1290  return OPERATOR_CANCELLED;
1291  }
1292 
1293  gso = op->customdata;
1294 
1295  /* register modal handler */
1297 
1298  /* start drawing immediately? */
1299  if (is_modal == false) {
1300  ARegion *region = CTX_wm_region(C);
1301 
1302  /* apply first dab... */
1303  gso->is_painting = true;
1305 
1306  /* redraw view with feedback */
1307  ED_region_tag_redraw(region);
1308  }
1309 
1310  return OPERATOR_RUNNING_MODAL;
1311 }
1312 
1313 /* painting - handle events */
1315 {
1317  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1318  bool redraw_region = false;
1319  bool redraw_toolsettings = false;
1320 
1321  /* The operator can be in 2 states: Painting and Idling */
1322  if (gso->is_painting) {
1323  /* Painting. */
1324  switch (event->type) {
1325  /* Mouse Move = Apply somewhere else */
1326  case MOUSEMOVE:
1327  case INBETWEEN_MOUSEMOVE:
1328  /* apply brush effect at new position */
1330 
1331  /* force redraw, so that the cursor will at least be valid */
1332  redraw_region = true;
1333  break;
1334 
1335  /* Painting mbut release = Stop painting (back to idle) */
1336  case LEFTMOUSE:
1337  if (is_modal) {
1338  /* go back to idling... */
1339  gso->is_painting = false;
1340  }
1341  else {
1342  /* end painting, since we're not modal */
1343  gso->is_painting = false;
1344 
1346  return OPERATOR_FINISHED;
1347  }
1348  break;
1349 
1350  /* Abort painting if any of the usual things are tried */
1351  case MIDDLEMOUSE:
1352  case RIGHTMOUSE:
1353  case EVT_ESCKEY:
1355  return OPERATOR_FINISHED;
1356  }
1357  }
1358  else {
1359  /* Idling */
1360  BLI_assert(is_modal == true);
1361 
1362  switch (event->type) {
1363  /* Painting mbut press = Start painting (switch to painting state) */
1364  case LEFTMOUSE:
1365  /* do initial "click" apply */
1366  gso->is_painting = true;
1367  gso->first = true;
1368 
1370  break;
1371 
1372  /* Exit modal operator, based on the "standard" ops */
1373  case RIGHTMOUSE:
1374  case EVT_ESCKEY:
1376  return OPERATOR_FINISHED;
1377 
1378  /* MMB is often used for view manipulations */
1379  case MIDDLEMOUSE:
1380  return OPERATOR_PASS_THROUGH;
1381 
1382  /* Mouse movements should update the brush cursor - Just redraw the active region */
1383  case MOUSEMOVE:
1384  case INBETWEEN_MOUSEMOVE:
1385  redraw_region = true;
1386  break;
1387 
1388  /* Change Frame - Allowed */
1389  case EVT_LEFTARROWKEY:
1390  case EVT_RIGHTARROWKEY:
1391  case EVT_UPARROWKEY:
1392  case EVT_DOWNARROWKEY:
1393  return OPERATOR_PASS_THROUGH;
1394 
1395  /* Camera/View Gizmo's - Allowed */
1396  /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
1397  case EVT_PAD0:
1398  case EVT_PAD1:
1399  case EVT_PAD2:
1400  case EVT_PAD3:
1401  case EVT_PAD4:
1402  case EVT_PAD5:
1403  case EVT_PAD6:
1404  case EVT_PAD7:
1405  case EVT_PAD8:
1406  case EVT_PAD9:
1407  return OPERATOR_PASS_THROUGH;
1408 
1409  /* Unhandled event */
1410  default:
1411  break;
1412  }
1413  }
1414 
1415  /* Redraw region? */
1416  if (redraw_region) {
1418  }
1419 
1420  /* Redraw toolsettings (brush settings)? */
1421  if (redraw_toolsettings) {
1424  }
1425 
1426  return OPERATOR_RUNNING_MODAL;
1427 }
1428 
1430 {
1431  /* identifiers */
1432  ot->name = "Stroke Vertex Paint";
1433  ot->idname = "GPENCIL_OT_vertex_paint";
1434  ot->description = "Paint stroke points with a color";
1435 
1436  /* api callbacks */
1442 
1443  /* flags */
1445 
1446  /* properties */
1447  PropertyRNA *prop;
1448  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1450 
1451  prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1453 }
typedef float(TangentPoint)[2]
float BKE_brush_curve_strength(const struct Brush *br, float p, float len)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
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
#define CTX_DATA_COUNT(C, member)
Definition: BKE_context.h:290
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
float BKE_gpencil_multiframe_falloff_calc(struct bGPDframe *gpf, int actnum, int f_init, int f_end, struct CurveMapping *cur_falloff)
Definition: gpencil.c:1917
#define GPENCIL_TINT_VERTEX_COLOR_STROKE(brush)
Definition: BKE_gpencil.h:66
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe)
Definition: gpencil.c:1900
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
#define GPENCIL_TINT_VERTEX_COLOR_FILL(brush)
Definition: BKE_gpencil.h:69
General operations, lookup, etc. for materials.
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:805
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
MINLINE void srgb_to_linearrgb_v3_v3(float linear[3], const float srgb[3])
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_v2v2_int(const int v1[2], const int v2[2])
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_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v3(float r[3])
MINLINE float normalize_v2(float r[2])
MINLINE void add_v3_v3(float r[3], const float a[3])
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
#define ARRAY_SET_ITEMS(...)
#define ELEM(...)
#define CLAMP_MIN(a, b)
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ GPAINT_TOOL_TINT
@ GPVERTEX_TOOL_AVERAGE
@ GPVERTEX_TOOL_REPLACE
@ GPVERTEX_TOOL_DRAW
@ GPVERTEX_TOOL_BLUR
@ GPVERTEX_TOOL_SMEAR
@ GP_BRUSH_USE_PRESSURE
#define GPENCIL_ANY_VERTEX_MASK(flag)
@ GP_CURVE_NEEDS_STROKE_UPDATE
@ GP_STROKE_SELECT
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
@ GP_FRAME_SELECT
@ GP_SPOINT_SELECT
@ GP_MATERIAL_FILL_SHOW
@ OB_MODE_VERTEX_GPENCIL
@ GP_SCULPT_SETT_FLAG_FRAME_FALLOFF
enum eGP_vertex_SelectMaskFlag eGP_Vertex_SelectMaskFlag
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
bScreen * ED_screen_animation_playing(const struct wmWindowManager *wm)
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
_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
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble top
_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 GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble bottom
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:543
#define RNA_END
Definition: RNA_access.h:550
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
#define C
Definition: RandGen.cpp:25
#define V2D_IS_CLIPPED
Definition: UI_view2d.h:25
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_DATA
Definition: WM_types.h:456
#define NC_SCENE
Definition: WM_types.h:328
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
@ KM_CTRL
Definition: WM_types.h:239
Scene scene
const Depsgraph * depsgraph
void gpencil_point_conversion_init(struct bContext *C, GP_SpaceConversion *r_gsc)
void gpencil_point_to_parent_space(const bGPDspoint *pt, const float diff_mat[4][4], bGPDspoint *r_pt)
bool gpencil_stroke_inside_circle(const float mval[2], int rad, int x0, int y0, int x1, int y1)
void gpencil_point_to_xy(const GP_SpaceConversion *gsc, const struct bGPDstroke *gps, const struct bGPDspoint *pt, int *r_x, int *r_y)
bool ED_gpencil_stroke_material_editable(Object *ob, const bGPDlayer *gpl, const bGPDstroke *gps)
bool ED_gpencil_stroke_check_collision(const GP_SpaceConversion *gsc, bGPDstroke *gps, const float mval[2], const int radius, const float diff_mat[4][4])
bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps, const GP_SpaceConversion *gsc, const int mval[2], const float diff_mat[4][4])
bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
static void gpencil_vertexpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
static bool gpencil_vertexpaint_brush_do_frame(bContext *C, tGP_BrushVertexpaintData *gso, bGPDlayer *gpl, bGPDframe *gpf, const float diff_mat[4][4], const float bound_mat[4][4])
static int gpencil_vertexpaint_brush_exec(bContext *C, wmOperator *op)
static bool brush_blur_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
static int gpencil_vertexpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_vertexpaint_brush_exit(bContext *C, wmOperator *op)
static bool brush_invert_check(tGP_BrushVertexpaintData *gso)
static bool brush_replace_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index)
static tGP_Selected * gpencil_select_buffer_ensure(tGP_Selected *buffer_array, int *buffer_size, int *buffer_used, const bool clear)
static void brush_calc_dvec_2d(tGP_BrushVertexpaintData *gso)
#define GP_SELECT_BUFFER_CHUNK
static int gpencil_vertexpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool brush_smear_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index, tGP_Selected *selected)
static void gpencil_grid_cells_init(tGP_BrushVertexpaintData *gso)
#define GP_GRID_PIXEL_SIZE
static void gpencil_vertexpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
static void gpencil_save_selected_point(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int index, int pc[2])
static bool gpencil_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpaintData *gso)
static bool brush_average_apply(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2], float average_color[3])
static bool get_surrounding_color(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, int pt_index, float r_color[3])
static void gpencil_grid_cell_average_color_idx_get(tGP_BrushVertexpaintData *gso, int r_idx[2])
static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, bGPDstroke *gps, const char tool, const float diff_mat[4][4], const float bound_mat[4][4])
void GPENCIL_OT_vertex_paint(wmOperatorType *ot)
struct tGP_Grid tGP_Grid
static void gpencil_grid_colors_calc(tGP_BrushVertexpaintData *gso)
static void gpencil_vertexpaint_brush_header_set(bContext *C)
static int gpencil_grid_cell_index_get(tGP_BrushVertexpaintData *gso, const int pc[2])
struct tGP_Selected tGP_Selected
eGPDvertex_brush_Flag
@ GP_VERTEX_FLAG_TMP_INVERT
@ GP_VERTEX_FLAG_INVERT
static float brush_influence_calc(tGP_BrushVertexpaintData *gso, const int radius, const int co[2])
static bool gpencil_vertexpaint_brush_init(bContext *C, wmOperator *op)
static bool gpencil_vertexpaint_brush_poll(bContext *C)
struct tGP_BrushVertexpaintData tGP_BrushVertexpaintData
uint col
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
static void clear(Message *msg)
Definition: msgfmt.c:278
T distance(const T &a, const T &b)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
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
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4221
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
struct CurveMapping * curve
char gpencil_vertex_tool
float rgb[3]
struct BrushGpencilSettings * gpencil_settings
char gpencil_tool
struct CurveMapping * cur_falloff
void * data
struct Brush * brush
char gpencil_selectmode_vertex
GpPaint * gp_paint
struct GP_Sculpt_Settings gp_sculpt
GpVertexPaint * gp_vertexpaint
ListBase strokes
struct bGPDspoint * pt_orig
bGPDspoint_Runtime runtime
float vert_color[4]
struct bGPDstroke * gps_orig
bGPDspoint * points
float vert_color_fill[4]
bGPDstroke_Runtime runtime
struct bGPDcurve * editcurve
ListBase layers
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
eGPDvertex_brush_Flag flag
eGP_Vertex_SelectMaskFlag mask
bGPDstroke * gps
uint8_t modifier
Definition: WM_types.h:693
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_PAD8
@ EVT_PAD2
@ RIGHTMOUSE
@ EVT_PAD4
@ EVT_PAD0
@ EVT_PAD9
@ EVT_DOWNARROWKEY
@ EVT_PAD3
@ EVT_RIGHTARROWKEY
@ EVT_PAD6
@ EVT_PAD5
@ MOUSEMOVE
@ EVT_UPARROWKEY
@ LEFTMOUSE
@ EVT_LEFTARROWKEY
@ MIDDLEMOUSE
@ EVT_ESCKEY
@ INBETWEEN_MOUSEMOVE
@ EVT_PAD1
@ EVT_PAD7
wmOperatorType * ot
Definition: wm_files.c:3479