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