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