Blender  V3.3
gpencil_weight_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_armature_types.h"
17 #include "DNA_brush_types.h"
18 #include "DNA_gpencil_types.h"
19 
20 #include "BKE_action.h"
21 #include "BKE_brush.h"
22 #include "BKE_colortools.h"
23 #include "BKE_context.h"
24 #include "BKE_deform.h"
25 #include "BKE_gpencil.h"
26 #include "BKE_main.h"
27 #include "BKE_modifier.h"
28 #include "BKE_object_deform.h"
29 #include "BKE_report.h"
30 #include "DNA_meshdata_types.h"
31 
32 #include "WM_api.h"
33 #include "WM_types.h"
34 
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37 #include "RNA_prototypes.h"
38 
39 #include "UI_view2d.h"
40 
41 #include "ED_gpencil.h"
42 #include "ED_screen.h"
43 #include "ED_view3d.h"
44 
45 #include "DEG_depsgraph.h"
46 #include "DEG_depsgraph_query.h"
47 
48 #include "gpencil_intern.h"
49 
50 /* ************************************************ */
51 /* General Brush Editing Context */
52 #define GP_SELECT_BUFFER_CHUNK 256
53 
54 /* Grid of Colors for Smear. */
55 typedef struct tGP_Grid {
57  float bottom[2];
59  float top[2];
61  float color[4];
63  int totcol;
64 
66 
67 /* List of points affected by brush. */
68 typedef struct tGP_Selected {
70  bGPDstroke *gps;
72  int pt_index;
74  int pc[2];
76  float color[4];
78 
79 /* Context for brush operators */
80 typedef struct tGP_BrushWeightpaintData {
81  struct Main *bmain;
84 
86 
87  /* Current GPencil datablock */
89 
91 
92  /* Space Conversion Data */
94 
95  /* Is the brush currently painting? */
97 
98  /* Start of new paint */
99  bool first;
100 
101  /* Is multi-frame editing enabled, and are we using falloff for that? */
104 
105  /* active vertex group */
106  int vrgroup;
107 
108  /* Brush Runtime Data: */
109  /* - position and pressure
110  * - the *_prev variants are the previous values
111  */
112  float mval[2], mval_prev[2];
114 
115  /* - Effect 2D vector */
116  float dvec[2];
117 
118  /* - multi-frame falloff factor. */
119  float mf_falloff;
120 
121  /* brush geometry (bounding box). */
123 
124  /* Temp data to save selected points */
132 
133 /* Ensure the buffer to hold temp selected point size is enough to save all points selected. */
135  int *buffer_size,
136  int *buffer_used,
137  const bool clear)
138 {
139  tGP_Selected *p = NULL;
140 
141  /* By default a buffer is created with one block with a predefined number of free slots,
142  * if the size is not enough, the cache is reallocated adding a new block of free slots.
143  * This is done in order to keep cache small and improve speed. */
144  if (*buffer_used + 1 > *buffer_size) {
145  if ((*buffer_size == 0) || (buffer_array == NULL)) {
146  p = MEM_callocN(sizeof(struct tGP_Selected) * GP_SELECT_BUFFER_CHUNK, __func__);
147  *buffer_size = GP_SELECT_BUFFER_CHUNK;
148  }
149  else {
150  *buffer_size += GP_SELECT_BUFFER_CHUNK;
151  p = MEM_recallocN(buffer_array, sizeof(struct tGP_Selected) * *buffer_size);
152  }
153 
154  if (p == NULL) {
155  *buffer_size = *buffer_used = 0;
156  }
157 
158  buffer_array = p;
159  }
160 
161  /* clear old data */
162  if (clear) {
163  *buffer_used = 0;
164  if (buffer_array != NULL) {
165  memset(buffer_array, 0, sizeof(tGP_Selected) * *buffer_size);
166  }
167  }
168 
169  return buffer_array;
170 }
171 
172 /* Brush Operations ------------------------------- */
173 
174 /* Compute strength of effect. */
175 static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radius, const int co[2])
176 {
177  Brush *brush = gso->brush;
178 
179  /* basic strength factor from brush settings */
180  float influence = brush->alpha;
181 
182  /* use pressure? */
184  influence *= gso->pressure;
185  }
186 
187  /* distance fading */
188  int mval_i[2];
189  round_v2i_v2fl(mval_i, gso->mval);
190  float distance = (float)len_v2v2_int(mval_i, co);
191  influence *= 1.0f - (distance / max_ff(radius, 1e-8));
192 
193  /* Apply Brush curve. */
194  float brush_falloff = BKE_brush_curve_strength(brush, distance, (float)radius);
195  influence *= brush_falloff;
196 
197  /* apply multi-frame falloff */
198  influence *= gso->mf_falloff;
199 
200  /* return influence */
201  return influence;
202 }
203 
204 /* Compute effect vector for directional brushes. */
206 {
207  gso->dvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
208  gso->dvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
209 
210  normalize_v2(gso->dvec);
211 }
212 
213 /* ************************************************ */
214 /* Brush Callbacks
215  * This section defines the callbacks used by each brush to perform their magic.
216  * These are called on each point within the brush's radius. */
217 
218 /* Draw Brush */
220  bGPDstroke *gps,
221  int pt_index,
222  const int radius,
223  const int co[2])
224 {
225  /* create dvert */
227 
228  MDeformVert *dvert = gps->dvert + pt_index;
229  float inf;
230 
231  /* Compute strength of effect */
232  inf = brush_influence_calc(gso, radius, co);
233 
234  /* need a vertex group */
235  if (gso->vrgroup == -1) {
236  if (gso->object) {
238  if ((ob_armature != NULL)) {
239  Bone *actbone = ((bArmature *)ob_armature->data)->act_bone;
240  if (actbone != NULL) {
241  bPoseChannel *pchan = BKE_pose_channel_find_name(ob_armature->pose, actbone->name);
242  if (pchan != NULL) {
244  if (dg == NULL) {
245  dg = BKE_object_defgroup_add_name(gso->object, pchan->name);
246  }
247  }
248  }
249  }
250  else {
252  }
254  gso->vrgroup = 0;
255  }
256  }
257  else {
258  bDeformGroup *defgroup = BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup);
259  if (defgroup->flag & DG_LOCK_WEIGHT) {
260  return false;
261  }
262  }
263  /* Get current weight and blend. */
265  if (dw) {
266  dw->weight = interpf(gso->brush->weight, dw->weight, inf);
267  CLAMP(dw->weight, 0.0f, 1.0f);
268  }
269  return true;
270 }
271 
272 /* ************************************************ */
273 /* Header Info */
275 {
276  ED_workspace_status_text(C, TIP_("GPencil Weight Paint: LMB to paint | RMB/Escape to Exit"));
277 }
278 
279 /* ************************************************ */
280 /* Grease Pencil Weight Paint Operator */
281 
282 /* Init/Exit ----------------------------------------------- */
283 
285 {
289  Paint *paint = &ts->gp_weightpaint->paint;
290 
291  /* set the brush using the tool */
293 
294  /* setup operator data */
295  gso = MEM_callocN(sizeof(tGP_BrushWeightpaintData), "tGP_BrushWeightpaintData");
296  op->customdata = gso;
297 
298  gso->bmain = CTX_data_main(C);
299 
300  gso->brush = paint->brush;
302 
303  gso->is_painting = false;
304  gso->first = true;
305 
306  gso->pbuffer = NULL;
307  gso->pbuffer_size = 0;
308  gso->pbuffer_used = 0;
309 
311  gso->scene = scene;
312  gso->object = ob;
313  if (ob) {
314  gso->vrgroup = gso->gpd->vertex_group_active_index - 1;
315  if (!BLI_findlink(&gso->gpd->vertex_group_names, gso->vrgroup)) {
316  gso->vrgroup = -1;
317  }
318  }
319  else {
320  gso->vrgroup = -1;
321  }
322 
323  gso->region = CTX_wm_region(C);
324 
325  /* Multi-frame settings. */
328 
329  /* Init multi-edit falloff curve data before doing anything,
330  * so we won't have to do it again later. */
331  if (gso->is_multiframe) {
333  }
334 
335  /* Setup space conversions. */
337 
338  /* Update header. */
340 
341  return true;
342 }
343 
345 {
347 
348  /* Disable headerprints. */
350 
351  /* Free operator data */
352  MEM_SAFE_FREE(gso->pbuffer);
353  MEM_SAFE_FREE(gso);
354  op->customdata = NULL;
355 }
356 
357 /* Poll callback for stroke weight paint operator. */
359 {
360  /* NOTE: this is a bit slower, but is the most accurate... */
361  return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
362 }
363 
364 /* Helper to save the points selected by the brush. */
366  bGPDstroke *gps,
367  int index,
368  int pc[2])
369 {
370  tGP_Selected *selected;
371  bGPDspoint *pt = &gps->points[index];
372 
373  /* Ensure the array to save the list of selected points is big enough. */
375  gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, false);
376 
377  selected = &gso->pbuffer[gso->pbuffer_used];
378  selected->gps = gps;
379  selected->pt_index = index;
380  copy_v2_v2_int(selected->pc, pc);
381  copy_v4_v4(selected->color, pt->vert_color);
382 
383  gso->pbuffer_used++;
384 }
385 
386 /* Select points in this stroke and add to an array to be used later. */
388  bGPDstroke *gps,
389  const float diff_mat[4][4],
390  const float bound_mat[4][4])
391 {
392  GP_SpaceConversion *gsc = &gso->gsc;
393  rcti *rect = &gso->brush_rect;
394  Brush *brush = gso->brush;
395  const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
396  gso->brush->size;
397  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
398  bGPDspoint *pt_active = NULL;
399 
400  bGPDspoint *pt1, *pt2;
401  bGPDspoint *pt = NULL;
402  int pc1[2] = {0};
403  int pc2[2] = {0};
404  int i;
405  int index;
406  bool include_last = false;
407 
408  /* Check if the stroke collide with brush. */
409  if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
410  return;
411  }
412 
413  if (gps->totpoints == 1) {
414  bGPDspoint pt_temp;
415  pt = &gps->points[0];
416  gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
417  gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
418 
419  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
420  /* Do bound-box check first. */
421  if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
422  /* only check if point is inside */
423  int mval_i[2];
424  round_v2i_v2fl(mval_i, gso->mval);
425  if (len_v2v2_int(mval_i, pc1) <= radius) {
426  /* apply operation to this point */
427  if (pt_active != NULL) {
428  gpencil_save_selected_point(gso, gps_active, 0, pc1);
429  }
430  }
431  }
432  }
433  else {
434  /* Loop over the points in the stroke, checking for intersections
435  * - an intersection means that we touched the stroke
436  */
437  for (i = 0; (i + 1) < gps->totpoints; i++) {
438  /* Get points to work with */
439  pt1 = gps->points + i;
440  pt2 = gps->points + i + 1;
441 
442  bGPDspoint npt;
443  gpencil_point_to_parent_space(pt1, diff_mat, &npt);
444  gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
445 
446  gpencil_point_to_parent_space(pt2, diff_mat, &npt);
447  gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
448 
449  /* Check that point segment of the bound-box of the selection stroke */
450  if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
451  ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
452  /* Check if point segment of stroke had anything to do with
453  * brush region (either within stroke painted, or on its lines)
454  * - this assumes that line-width is irrelevant.
455  */
456  if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
457 
458  /* To each point individually... */
459  pt = &gps->points[i];
460  pt_active = pt->runtime.pt_orig;
461  if (pt_active != NULL) {
462  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
463  gpencil_save_selected_point(gso, gps_active, index, pc1);
464  }
465 
466  /* Only do the second point if this is the last segment,
467  * and it is unlikely that the point will get handled
468  * otherwise.
469  *
470  * NOTE: There is a small risk here that the second point wasn't really
471  * actually in-range. In that case, it only got in because
472  * the line linking the points was!
473  */
474  if (i + 1 == gps->totpoints - 1) {
475  pt = &gps->points[i + 1];
476  pt_active = pt->runtime.pt_orig;
477  if (pt_active != NULL) {
478  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
479  gpencil_save_selected_point(gso, gps_active, index, pc2);
480  include_last = false;
481  }
482  }
483  else {
484  include_last = true;
485  }
486  }
487  else if (include_last) {
488  /* This case is for cases where for whatever reason the second vert (1st here)
489  * doesn't get included because the whole edge isn't in bounds,
490  * but it would've qualified since it did with the previous step
491  * (but wasn't added then, to avoid double-ups).
492  */
493  pt = &gps->points[i];
494  pt_active = pt->runtime.pt_orig;
495  if (pt_active != NULL) {
496  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
497  gpencil_save_selected_point(gso, gps_active, index, pc1);
498 
499  include_last = false;
500  }
501  }
502  }
503  }
504  }
505 }
506 
507 /* Apply weight paint brushes to strokes in the given frame. */
510  bGPDlayer *gpl,
511  bGPDframe *gpf,
512  const float diff_mat[4][4],
513  const float bound_mat[4][4])
514 {
516  char tool = gso->brush->gpencil_weight_tool;
517  const int radius = (gso->brush->flag & GP_BRUSH_USE_PRESSURE) ?
518  gso->brush->size * gso->pressure :
519  gso->brush->size;
520  tGP_Selected *selected = NULL;
521  int i;
522 
523  /*---------------------------------------------------------------------
524  * First step: select the points affected. This step is required to have
525  * all selected points before apply the effect, because it could be
526  * required to do some step. Now is not used, but the operator is ready.
527  *--------------------------------------------------------------------- */
528  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
529  /* Skip strokes that are invalid for current view. */
530  if (ED_gpencil_stroke_can_use(C, gps) == false) {
531  continue;
532  }
533  /* Check if the color is editable. */
534  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
535  continue;
536  }
537 
538  /* Check points below the brush. */
539  gpencil_weightpaint_select_stroke(gso, gps, diff_mat, bound_mat);
540  }
541 
542  /*---------------------------------------------------------------------
543  * Second step: Apply effect.
544  *--------------------------------------------------------------------- */
545  bool changed = false;
546  for (i = 0; i < gso->pbuffer_used; i++) {
547  changed = true;
548  selected = &gso->pbuffer[i];
549 
550  switch (tool) {
551  case GPWEIGHT_TOOL_DRAW: {
552  brush_draw_apply(gso, selected->gps, selected->pt_index, radius, selected->pc);
553  changed |= true;
554  break;
555  }
556  default:
557  printf("ERROR: Unknown type of GPencil Weight Paint brush\n");
558  break;
559  }
560  }
561  /* Clear the selected array, but keep the memory allocation. */
563  gso->pbuffer, &gso->pbuffer_size, &gso->pbuffer_used, true);
564 
565  return changed;
566 }
567 
568 /* Apply brush effect to all layers. */
570 {
573  Object *obact = gso->object;
574  bool changed = false;
575 
576  Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
577  bGPdata *gpd = (bGPdata *)ob_eval->data;
578 
579  /* Find visible strokes, and perform operations on those if hit */
580  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
581  /* If locked or no active frame, don't do anything. */
582  if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
583  continue;
584  }
585 
586  /* Calculate transform matrix. */
587  float diff_mat[4][4], bound_mat[4][4];
588  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
589  copy_m4_m4(bound_mat, diff_mat);
590  mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
591 
592  /* Active Frame or MultiFrame? */
593  if (gso->is_multiframe) {
594  /* init multi-frame falloff options */
595  int f_init = 0;
596  int f_end = 0;
597 
598  if (gso->use_multiframe_falloff) {
599  BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
600  }
601 
602  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
603  /* Always do active frame; Otherwise, only include selected frames */
604  if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
605  /* Compute multi-frame falloff factor. */
606  if (gso->use_multiframe_falloff) {
607  /* Falloff depends on distance to active frame
608  * (relative to the overall frame range). */
610  gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
611  }
612  else {
613  /* No falloff */
614  gso->mf_falloff = 1.0f;
615  }
616 
617  /* affect strokes in this frame */
618  changed |= gpencil_weightpaint_brush_do_frame(C, gso, gpl, gpf, diff_mat, bound_mat);
619  }
620  }
621  }
622  else {
623  if (gpl->actframe != NULL) {
624  /* Apply to active frame's strokes */
625  gso->mf_falloff = 1.0f;
627  C, gso, gpl, gpl->actframe, diff_mat, bound_mat);
628  }
629  }
630  }
631 
632  return changed;
633 }
634 
635 /* Calculate settings for applying brush */
637 {
639  Brush *brush = gso->brush;
640  const int radius = ((brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
641  gso->brush->size);
642  float mousef[2];
643  int mouse[2];
644  bool changed = false;
645 
646  /* Get latest mouse coordinates */
647  RNA_float_get_array(itemptr, "mouse", mousef);
648  gso->mval[0] = mouse[0] = (int)(mousef[0]);
649  gso->mval[1] = mouse[1] = (int)(mousef[1]);
650 
651  gso->pressure = RNA_float_get(itemptr, "pressure");
652 
653  /* Store coordinates as reference, if operator just started running */
654  if (gso->first) {
655  gso->mval_prev[0] = gso->mval[0];
656  gso->mval_prev[1] = gso->mval[1];
657  gso->pressure_prev = gso->pressure;
658  }
659 
660  /* Update brush_rect, so that it represents the bounding rectangle of brush. */
661  gso->brush_rect.xmin = mouse[0] - radius;
662  gso->brush_rect.ymin = mouse[1] - radius;
663  gso->brush_rect.xmax = mouse[0] + radius;
664  gso->brush_rect.ymax = mouse[1] + radius;
665 
666  /* Calculate 2D direction vector and relative angle. */
667  brush_calc_dvec_2d(gso);
668 
670 
671  /* Updates */
672  if (changed) {
675  }
676 
677  /* Store values for next step */
678  gso->mval_prev[0] = gso->mval[0];
679  gso->mval_prev[1] = gso->mval[1];
680  gso->pressure_prev = gso->pressure;
681  gso->first = false;
682 }
683 
684 /* Running --------------------------------------------- */
685 
686 /* helper - a record stroke, and apply paint event */
688  wmOperator *op,
689  const wmEvent *event)
690 {
692  PointerRNA itemptr;
693  float mouse[2];
694 
695  mouse[0] = event->mval[0] + 1;
696  mouse[1] = event->mval[1] + 1;
697 
698  /* fill in stroke */
699  RNA_collection_add(op->ptr, "stroke", &itemptr);
700 
701  RNA_float_set_array(&itemptr, "mouse", mouse);
702  RNA_boolean_set(&itemptr, "pen_flip", event->modifier & KM_CTRL);
703  RNA_boolean_set(&itemptr, "is_start", gso->first);
704 
705  /* Handle pressure sensitivity (which is supplied by tablets). */
706  float pressure = event->tablet.pressure;
707  CLAMP(pressure, 0.0f, 1.0f);
708  RNA_float_set(&itemptr, "pressure", pressure);
709 
710  /* apply */
711  gpencil_weightpaint_brush_apply(C, op, &itemptr);
712 }
713 
714 /* reapply */
716 {
717  if (!gpencil_weightpaint_brush_init(C, op)) {
718  return OPERATOR_CANCELLED;
719  }
720 
721  RNA_BEGIN (op->ptr, itemptr, "stroke") {
722  gpencil_weightpaint_brush_apply(C, op, &itemptr);
723  }
724  RNA_END;
725 
727 
728  return OPERATOR_FINISHED;
729 }
730 
731 /* start modal painting */
733 {
735  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
736  const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
737 
738  /* the operator cannot work while play animation */
739  if (is_playing) {
740  BKE_report(op->reports, RPT_ERROR, "Cannot Paint while play animation");
741 
742  return OPERATOR_CANCELLED;
743  }
744 
745  /* init painting data */
746  if (!gpencil_weightpaint_brush_init(C, op)) {
747  return OPERATOR_CANCELLED;
748  }
749 
750  gso = op->customdata;
751 
752  /* register modal handler */
754 
755  /* start drawing immediately? */
756  if (is_modal == false) {
757  ARegion *region = CTX_wm_region(C);
758 
759  /* apply first dab... */
760  gso->is_painting = true;
762 
763  /* redraw view with feedback */
764  ED_region_tag_redraw(region);
765  }
766 
767  return OPERATOR_RUNNING_MODAL;
768 }
769 
770 /* painting - handle events */
772 {
774  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
775  bool redraw_region = false;
776  bool redraw_toolsettings = false;
777 
778  /* The operator can be in 2 states: Painting and Idling */
779  if (gso->is_painting) {
780  /* Painting. */
781  switch (event->type) {
782  /* Mouse Move = Apply somewhere else */
783  case MOUSEMOVE:
784  case INBETWEEN_MOUSEMOVE:
785  /* apply brush effect at new position */
787 
788  /* force redraw, so that the cursor will at least be valid */
789  redraw_region = true;
790  break;
791 
792  /* Painting mbut release = Stop painting (back to idle) */
793  case LEFTMOUSE:
794  if (is_modal) {
795  /* go back to idling... */
796  gso->is_painting = false;
797  }
798  else {
799  /* end painting, since we're not modal */
800  gso->is_painting = false;
801 
803  return OPERATOR_FINISHED;
804  }
805  break;
806 
807  /* Abort painting if any of the usual things are tried */
808  case MIDDLEMOUSE:
809  case RIGHTMOUSE:
810  case EVT_ESCKEY:
812  return OPERATOR_FINISHED;
813  }
814  }
815  else {
816  /* Idling */
817  BLI_assert(is_modal == true);
818 
819  switch (event->type) {
820  /* Painting mbut press = Start painting (switch to painting state) */
821  case LEFTMOUSE:
822  /* do initial "click" apply */
823  gso->is_painting = true;
824  gso->first = true;
825 
827  break;
828 
829  /* Exit modal operator, based on the "standard" ops */
830  case RIGHTMOUSE:
831  case EVT_ESCKEY:
833  return OPERATOR_FINISHED;
834 
835  /* MMB is often used for view manipulations */
836  case MIDDLEMOUSE:
837  return OPERATOR_PASS_THROUGH;
838 
839  /* Mouse movements should update the brush cursor - Just redraw the active region */
840  case MOUSEMOVE:
841  case INBETWEEN_MOUSEMOVE:
842  redraw_region = true;
843  break;
844 
845  /* Change Frame - Allowed */
846  case EVT_LEFTARROWKEY:
847  case EVT_RIGHTARROWKEY:
848  case EVT_UPARROWKEY:
849  case EVT_DOWNARROWKEY:
850  return OPERATOR_PASS_THROUGH;
851 
852  /* Camera/View Gizmo's - Allowed */
853  /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
854  case EVT_PAD0:
855  case EVT_PAD1:
856  case EVT_PAD2:
857  case EVT_PAD3:
858  case EVT_PAD4:
859  case EVT_PAD5:
860  case EVT_PAD6:
861  case EVT_PAD7:
862  case EVT_PAD8:
863  case EVT_PAD9:
864  return OPERATOR_PASS_THROUGH;
865 
866  /* Unhandled event */
867  default:
868  break;
869  }
870  }
871 
872  /* Redraw region? */
873  if (redraw_region) {
875  }
876 
877  /* Redraw toolsettings (brush settings)? */
878  if (redraw_toolsettings) {
881  }
882 
883  return OPERATOR_RUNNING_MODAL;
884 }
885 
887 {
888  /* identifiers */
889  ot->name = "Stroke Weight Paint";
890  ot->idname = "GPENCIL_OT_weight_paint";
891  ot->description = "Paint stroke points with a color";
892 
893  /* api callbacks */
899 
900  /* flags */
902 
903  /* properties */
904  PropertyRNA *prop;
905  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
907 
908  prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
910 }
typedef float(TangentPoint)[2]
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
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 Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
support for deformation groups and hooks.
struct MDeformWeight * BKE_defvert_ensure_index(struct MDeformVert *dv, int defgroup)
Definition: deform.c:748
struct bDeformGroup * BKE_object_defgroup_find_name(const struct Object *ob, const char *name)
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
void BKE_gpencil_dvert_ensure(struct bGPDstroke *gps)
Definition: gpencil.c:1891
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])
struct Object * BKE_modifiers_is_deformed_by_armature(struct Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
struct bDeformGroup * BKE_object_defgroup_add(struct Object *ob)
struct bDeformGroup * BKE_object_defgroup_add_name(struct Object *ob, const char *name)
Definition: object_deform.c:95
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
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE float interpf(float a, float b, float t)
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_int(int r[2], const int a[2])
MINLINE float normalize_v2(float r[2])
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
#define ELEM(...)
#define TIP_(msgid)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ GPWEIGHT_TOOL_DRAW
@ GP_BRUSH_USE_PRESSURE
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
@ GP_FRAME_SELECT
#define DG_LOCK_WEIGHT
@ GP_SCULPT_SETT_FLAG_FRAME_FALLOFF
@ 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
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
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
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_can_use(const bContext *C, const bGPDstroke *gps)
bGPdata * ED_gpencil_data_get_active(const bContext *C)
static void gpencil_weightpaint_brush_header_set(bContext *C)
static bool brush_draw_apply(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, int pt_index, const int radius, const int co[2])
static int gpencil_weightpaint_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int gpencil_weightpaint_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
static bool gpencil_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpaintData *gso)
static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radius, const int co[2])
static void gpencil_save_selected_point(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, int index, int pc[2])
void GPENCIL_OT_weight_paint(wmOperatorType *ot)
static tGP_Selected * gpencil_select_buffer_ensure(tGP_Selected *buffer_array, int *buffer_size, int *buffer_used, const bool clear)
static void gpencil_weightpaint_brush_exit(bContext *C, wmOperator *op)
struct tGP_BrushWeightpaintData tGP_BrushWeightpaintData
static bool gpencil_weightpaint_brush_poll(bContext *C)
#define GP_SELECT_BUFFER_CHUNK
static bool gpencil_weightpaint_brush_do_frame(bContext *C, tGP_BrushWeightpaintData *gso, bGPDlayer *gpl, bGPDframe *gpf, const float diff_mat[4][4], const float bound_mat[4][4])
static bool gpencil_weightpaint_brush_init(bContext *C, wmOperator *op)
static void gpencil_weightpaint_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, bGPDstroke *gps, const float diff_mat[4][4], const float bound_mat[4][4])
struct tGP_Grid tGP_Grid
static int gpencil_weightpaint_brush_exec(bContext *C, wmOperator *op)
static void brush_calc_dvec_2d(tGP_BrushWeightpaintData *gso)
struct tGP_Selected tGP_Selected
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
char name[64]
float alpha
char gpencil_weight_tool
struct CurveMapping * curve
struct BrushGpencilSettings * gpencil_settings
float weight
struct CurveMapping * cur_falloff
Definition: BKE_main.h:121
struct bPose * pose
void * data
struct Brush * brush
GpWeightPaint * gp_weightpaint
struct GP_Sculpt_Settings gp_sculpt
ListBase strokes
struct bGPDspoint * pt_orig
bGPDspoint_Runtime runtime
float vert_color[4]
struct bGPDstroke * gps_orig
bGPDspoint * points
bGPDstroke_Runtime runtime
struct MDeformVert * dvert
ListBase vertex_group_names
ListBase layers
int vertex_group_active_index
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
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