Blender  V2.93
gpencil_sculpt_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 <math.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_blenlib.h"
34 #include "BLI_ghash.h"
35 #include "BLI_math.h"
36 #include "BLI_rand.h"
37 #include "BLI_utildefines.h"
38 
39 #include "PIL_time.h"
40 
41 #include "BLT_translation.h"
42 
43 #include "DNA_gpencil_types.h"
44 #include "DNA_material_types.h"
45 #include "DNA_meshdata_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_screen_types.h"
49 #include "DNA_space_types.h"
50 #include "DNA_view3d_types.h"
51 
52 #include "BKE_brush.h"
53 #include "BKE_colortools.h"
54 #include "BKE_context.h"
55 #include "BKE_deform.h"
56 #include "BKE_gpencil.h"
57 #include "BKE_gpencil_geom.h"
58 #include "BKE_gpencil_modifier.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_object_deform.h"
62 #include "BKE_report.h"
63 
64 #include "UI_interface.h"
65 
66 #include "WM_api.h"
67 #include "WM_types.h"
68 
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71 #include "RNA_enum_types.h"
72 
73 #include "UI_view2d.h"
74 
75 #include "ED_gpencil.h"
76 #include "ED_keyframing.h"
77 #include "ED_screen.h"
78 #include "ED_view3d.h"
79 
80 #include "DEG_depsgraph.h"
81 #include "DEG_depsgraph_query.h"
82 
83 #include "gpencil_intern.h"
84 
85 /* ************************************************ */
86 /* General Brush Editing Context */
87 
88 /* Context for brush operators */
89 typedef struct tGP_BrushEditData {
90  /* Current editor/region/etc. */
95 
98 
99  /* Current GPencil datablock */
101 
102  /* Brush Settings */
106 
109 
110  /* Space Conversion Data */
112 
113  /* Is the brush currently painting? */
116 
117  /* Start of new sculpt stroke */
118  bool first;
119 
120  /* Is multiframe editing enabled, and are we using falloff for that? */
123 
124  /* Current frame */
125  int cfra;
126 
127  /* Brush Runtime Data: */
128  /* - position and pressure
129  * - the *_prev variants are the previous values
130  */
131  float mval[2], mval_prev[2];
133 
134  /* - effect vector (e.g. 2D/3D translation for grab brush) */
135  float dvec[3];
136 
137  /* rotation for evaluated data */
138  float rot_eval;
139 
140  /* - multiframe falloff factor */
141  float mf_falloff;
142 
143  /* active vertex group */
144  int vrgroup;
145 
146  /* brush geometry (bounding box) */
148 
149  /* Custom data for certain brushes */
150  /* - map from bGPDstroke's to structs containing custom data about those strokes */
152  /* - general customdata */
153  void *customdata;
154 
155  /* Timer for in-place accumulation of brush effect */
157  bool timerTick; /* is this event from a timer */
158 
159  /* Object invert matrix */
160  float inv_mat[4][4];
161 
164 
165 /* Callback for performing some brush operation on a single point */
166 typedef bool (*GP_BrushApplyCb)(tGP_BrushEditData *gso,
167  bGPDstroke *gps,
168  float rotation,
169  int pt_index,
170  const int radius,
171  const int co[2]);
172 
173 /* ************************************************ */
174 /* Utility Functions */
175 
176 /* apply lock axis reset */
178  bGPDspoint *pt,
179  const float save_pt[3])
180 {
181  const ToolSettings *ts = gso->scene->toolsettings;
182  const View3DCursor *cursor = &gso->scene->cursor;
183  const int axis = ts->gp_sculpt.lock_axis;
184 
185  /* lock axis control */
186  switch (axis) {
187  case GP_LOCKAXIS_X: {
188  pt->x = save_pt[0];
189  break;
190  }
191  case GP_LOCKAXIS_Y: {
192  pt->y = save_pt[1];
193  break;
194  }
195  case GP_LOCKAXIS_Z: {
196  pt->z = save_pt[2];
197  break;
198  }
199  case GP_LOCKAXIS_CURSOR: {
200  /* Compute a plane with cursor normal and position of the point before do the sculpt. */
201  const float scale[3] = {1.0f, 1.0f, 1.0f};
202  float plane_normal[3] = {0.0f, 0.0f, 1.0f};
203  float plane[4];
204  float mat[4][4];
205  float r_close[3];
206 
207  loc_eul_size_to_mat4(mat, cursor->location, cursor->rotation_euler, scale);
208 
209  mul_mat3_m4_v3(mat, plane_normal);
210  plane_from_point_normal_v3(plane, save_pt, plane_normal);
211 
212  /* find closest point to the plane with the new position */
213  closest_to_plane_v3(r_close, plane, &pt->x);
214  copy_v3_v3(&pt->x, r_close);
215  break;
216  }
217  default: {
218  break;
219  }
220  }
221 }
222 
223 /* Context ---------------------------------------- */
224 
225 /* Get the sculpting settings */
227 {
228  return &scene->toolsettings->gp_sculpt;
229 }
230 
231 /* Brush Operations ------------------------------- */
232 
233 /* Invert behavior of brush? */
235 {
236  /* The basic setting is the brush's setting (from the panel) */
239  /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */
240  if (gso->flag & GP_SCULPT_FLAG_INVERT) {
241  invert ^= true;
242  }
243 
244  /* set temporary status */
245  if (invert) {
247  }
248  else {
250  }
251 
252  return invert;
253 }
254 
255 /* Compute strength of effect */
257  const int radius,
258  const int co[2])
259 {
260  Brush *brush = gso->brush;
261 
262  /* basic strength factor from brush settings */
263  float influence = brush->alpha;
264 
265  /* use pressure? */
267  influence *= gso->pressure;
268  }
269 
270  /* distance fading */
271  int mval_i[2];
272  round_v2i_v2fl(mval_i, gso->mval);
273  float distance = (float)len_v2v2_int(mval_i, co);
274 
275  /* Apply Brush curve. */
276  float brush_falloff = BKE_brush_curve_strength(brush, distance, (float)radius);
277  influence *= brush_falloff;
278 
279  /* apply multiframe falloff */
280  influence *= gso->mf_falloff;
281 
282  /* return influence */
283  return influence;
284 }
285 
286 /* Tag stroke to be recalculated. */
288 {
289  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
290  gps_active->flag |= GP_STROKE_TAG;
291 }
292 
293 /* Recalc any stroke tagged. */
295 {
296  if (gpd == NULL) {
297  return;
298  }
299 
300  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
301  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
302  if ((gpl->actframe != gpf) && ((gpf->flag & GP_FRAME_SELECT) == 0)) {
303  continue;
304  }
305 
306  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
307  if (gps->flag & GP_STROKE_TAG) {
309  gps->flag &= ~GP_STROKE_TAG;
310  }
311  }
312  }
313  }
316 }
317 
318 /* ************************************************ */
319 /* Brush Callbacks */
320 /* This section defines the callbacks used by each brush to perform their magic.
321  * These are called on each point within the brush's radius.
322  */
323 
324 /* ----------------------------------------------- */
325 /* Smooth Brush */
326 
327 /* A simple (but slower + inaccurate)
328  * smooth-brush implementation to test the algorithm for stroke smoothing. */
330  bGPDstroke *gps,
331  float UNUSED(rot_eval),
332  int pt_index,
333  const int radius,
334  const int co[2])
335 {
336  float inf = gpencil_brush_influence_calc(gso, radius, co);
337 
338  /* perform smoothing */
340  BKE_gpencil_stroke_smooth(gps, pt_index, inf);
341  }
343  BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
344  }
346  BKE_gpencil_stroke_smooth_thickness(gps, pt_index, inf);
347  }
349  BKE_gpencil_stroke_smooth_uv(gps, pt_index, inf);
350  }
351 
352  return true;
353 }
354 
355 /* ----------------------------------------------- */
356 /* Line Thickness Brush */
357 
358 /* Make lines thicker or thinner by the specified amounts */
360  bGPDstroke *gps,
361  float UNUSED(rot_eval),
362  int pt_index,
363  const int radius,
364  const int co[2])
365 {
366  bGPDspoint *pt = gps->points + pt_index;
367  float inf;
368 
369  /* Compute strength of effect
370  * - We divide the strength by 10, so that users can set "sane" values.
371  * Otherwise, good default values are in the range of 0.093
372  */
373  inf = gpencil_brush_influence_calc(gso, radius, co) / 10.0f;
374 
375  /* apply */
376  /* XXX: this is much too strong,
377  * and it should probably do some smoothing with the surrounding stuff. */
378  if (gpencil_brush_invert_check(gso)) {
379  /* make line thinner - reduce stroke pressure */
380  pt->pressure -= inf;
381  }
382  else {
383  /* make line thicker - increase stroke pressure */
384  pt->pressure += inf;
385  }
386 
387  /* Pressure should stay within [0.0, 1.0]
388  * However, it is nice for volumetric strokes to be able to exceed
389  * the upper end of this range. Therefore, we don't actually clamp
390  * down on the upper end.
391  */
392  if (pt->pressure < 0.0f) {
393  pt->pressure = 0.0f;
394  }
395 
396  return true;
397 }
398 
399 /* ----------------------------------------------- */
400 /* Color Strength Brush */
401 
402 /* Make color more or less transparent by the specified amounts */
404  bGPDstroke *gps,
405  float UNUSED(rot_eval),
406  int pt_index,
407  const int radius,
408  const int co[2])
409 {
410  bGPDspoint *pt = gps->points + pt_index;
411  float inf;
412 
413  /* Compute strength of effect */
414  inf = gpencil_brush_influence_calc(gso, radius, co) * 0.125f;
415 
416  /* Invert effect. */
417  if (gpencil_brush_invert_check(gso)) {
418  inf *= -1.0f;
419  }
420 
421  pt->strength = clamp_f(pt->strength + inf, 0.0f, 1.0f);
422 
423  return true;
424 }
425 
426 /* ----------------------------------------------- */
427 /* Grab Brush */
428 
429 /* Custom data per stroke for the Grab Brush
430  *
431  * This basically defines the strength of the effect for each
432  * affected stroke point that was within the initial range of
433  * the brush region.
434  */
435 typedef struct tGPSB_Grab_StrokeData {
436  /* array of indices to corresponding points in the stroke */
437  int *points;
438  /* array of influence weights for each of the included points */
439  float *weights;
440  /* angles to calc transformation */
441  float *rot_eval;
442 
443  /* capacity of the arrays */
444  int capacity;
445  /* actual number of items currently stored */
446  int size;
448 
453 {
455 
456  BLI_assert(gps->totpoints > 0);
457 
458  /* Check if there are buffers already (from a prior run) */
459  if (BLI_ghash_haskey(gso->stroke_customdata, gps)) {
460  /* Ensure that the caches are empty
461  * - Since we reuse these between different strokes, we don't
462  * want the previous invocation's data polluting the arrays
463  */
465  BLI_assert(data != NULL);
466 
467  data->size = 0; /* minimum requirement - so that we can repopulate again */
468 
469  memset(data->points, 0, sizeof(int) * data->capacity);
470  memset(data->weights, 0, sizeof(float) * data->capacity);
471  memset(data->rot_eval, 0, sizeof(float) * data->capacity);
472  }
473  else {
474  /* Create new instance */
475  data = MEM_callocN(sizeof(tGPSB_Grab_StrokeData), "GP Stroke Grab Data");
476 
477  data->capacity = gps->totpoints;
478  data->size = 0;
479 
480  data->points = MEM_callocN(sizeof(int) * data->capacity, "GP Stroke Grab Indices");
481  data->weights = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Weights");
482  data->rot_eval = MEM_callocN(sizeof(float) * data->capacity, "GP Stroke Grab Rotations");
483 
484  /* hook up to the cache */
486  }
487 }
488 
489 /* store references to stroke points in the initial stage */
491  bGPDstroke *gps,
492  float rot_eval,
493  int pt_index,
494  const int radius,
495  const int co[2])
496 {
498  float inf = gpencil_brush_influence_calc(gso, radius, co);
499 
500  BLI_assert(data != NULL);
501  BLI_assert(data->size < data->capacity);
502 
503  /* insert this point into the set of affected points */
504  data->points[data->size] = pt_index;
505  data->weights[data->size] = inf;
506  data->rot_eval[data->size] = rot_eval;
507  data->size++;
508 
509  /* done */
510  return true;
511 }
512 
513 /* Compute effect vector for grab brush */
515 {
516  /* Convert mouse-movements to movement vector */
517  RegionView3D *rv3d = gso->region->regiondata;
518  float *rvec = gso->object->loc;
519  float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
520 
521  float mval_f[2];
522 
523  /* convert from 2D screenspace to 3D... */
524  mval_f[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
525  mval_f[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
526 
527  /* apply evaluated data transformation */
528  if (gso->rot_eval != 0.0f) {
529  const float cval = cos(gso->rot_eval);
530  const float sval = sin(gso->rot_eval);
531  float r[2];
532  r[0] = (mval_f[0] * cval) - (mval_f[1] * sval);
533  r[1] = (mval_f[0] * sval) + (mval_f[1] * cval);
534  copy_v2_v2(mval_f, r);
535  }
536 
537  ED_view3d_win_to_delta(gso->region, mval_f, gso->dvec, zfac);
538 }
539 
540 /* Apply grab transform to all relevant points of the affected strokes */
542  bGPDstroke *gps,
543  const float diff_mat[4][4])
544 {
546  /* If a new frame is created, could be impossible find the stroke. */
547  if (data == NULL) {
548  return;
549  }
550 
551  float inverse_diff_mat[4][4];
552  invert_m4_m4(inverse_diff_mat, diff_mat);
553 
554  /* Apply dvec to all of the stored points */
555  for (int i = 0; i < data->size; i++) {
556  bGPDspoint *pt = &gps->points[data->points[i]];
557  float delta[3] = {0.0f};
558 
559  /* get evaluated transformation */
560  gso->rot_eval = data->rot_eval[i];
562 
563  /* adjust the amount of displacement to apply */
564  mul_v3_v3fl(delta, gso->dvec, data->weights[i]);
565 
566  float fpt[3];
567  float save_pt[3];
568  copy_v3_v3(save_pt, &pt->x);
569  /* apply transformation */
570  mul_v3_m4v3(fpt, diff_mat, &pt->x);
571  /* apply */
572  add_v3_v3v3(&pt->x, fpt, delta);
573  /* undo transformation to the init parent position */
574  mul_m4_v3(inverse_diff_mat, &pt->x);
575 
576  /* compute lock axis */
577  gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
578  }
579 }
580 
581 /* free customdata used for handling this stroke */
583 {
585 
586  /* free arrays */
587  MEM_SAFE_FREE(data->points);
588  MEM_SAFE_FREE(data->weights);
589  MEM_SAFE_FREE(data->rot_eval);
590 
591  /* ... and this item itself, since it was also allocated */
592  MEM_freeN(data);
593 }
594 
595 /* ----------------------------------------------- */
596 /* Push Brush */
597 /* NOTE: Depends on gpencil_brush_grab_calc_dvec() */
599  bGPDstroke *gps,
600  float UNUSED(rot_eval),
601  int pt_index,
602  const int radius,
603  const int co[2])
604 {
605  bGPDspoint *pt = gps->points + pt_index;
606  float save_pt[3];
607  copy_v3_v3(save_pt, &pt->x);
608 
609  float inf = gpencil_brush_influence_calc(gso, radius, co);
610  float delta[3] = {0.0f};
611 
612  /* adjust the amount of displacement to apply */
613  mul_v3_v3fl(delta, gso->dvec, inf);
614 
615  /* apply */
616  mul_mat3_m4_v3(gso->inv_mat, delta); /* only rotation component */
617  add_v3_v3(&pt->x, delta);
618 
619  /* compute lock axis */
620  gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
621 
622  /* done */
623  return true;
624 }
625 
626 /* ----------------------------------------------- */
627 /* Pinch Brush */
628 /* Compute reference midpoint for the brush - this is what we'll be moving towards */
630 {
631  /* Convert mouse position to 3D space
632  * See: gpencil_paint.c :: gpencil_stroke_convertcoords()
633  */
634  RegionView3D *rv3d = gso->region->regiondata;
635  const float *rvec = gso->object->loc;
636  float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
637 
638  float mval_f[2];
639  copy_v2_v2(mval_f, gso->mval);
640  float mval_prj[2];
641  float dvec[3];
642 
643  if (ED_view3d_project_float_global(gso->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
644  V3D_PROJ_RET_OK) {
645  sub_v2_v2v2(mval_f, mval_prj, mval_f);
646  ED_view3d_win_to_delta(gso->region, mval_f, dvec, zfac);
647  sub_v3_v3v3(gso->dvec, rvec, dvec);
648  }
649  else {
650  zero_v3(gso->dvec);
651  }
652 }
653 
654 /* Shrink distance between midpoint and this point... */
656  bGPDstroke *gps,
657  float UNUSED(rot_eval),
658  int pt_index,
659  const int radius,
660  const int co[2])
661 {
662  bGPDspoint *pt = gps->points + pt_index;
663  float fac, inf;
664  float vec[3];
665  float save_pt[3];
666  copy_v3_v3(save_pt, &pt->x);
667 
668  /* Scale down standard influence value to get it more manageable...
669  * - No damping = Unmanageable at > 0.5 strength
670  * - Div 10 = Not enough effect
671  * - Div 5 = Happy medium... (by trial and error)
672  */
673  inf = gpencil_brush_influence_calc(gso, radius, co) / 5.0f;
674 
675  /* 1) Make this point relative to the cursor/midpoint (dvec) */
676  float fpt[3];
677  mul_v3_m4v3(fpt, gso->object->obmat, &pt->x);
678  sub_v3_v3v3(vec, fpt, gso->dvec);
679 
680  /* 2) Shrink the distance by pulling the point towards the midpoint
681  * (0.0 = at midpoint, 1 = at edge of brush region)
682  * OR
683  * Increase the distance (if inverting the brush action!)
684  */
685  if (gpencil_brush_invert_check(gso)) {
686  /* Inflate (inverse) */
687  fac = 1.0f + (inf * inf); /* squared to temper the effect... */
688  }
689  else {
690  /* Shrink (default) */
691  fac = 1.0f - (inf * inf); /* squared to temper the effect... */
692  }
693  mul_v3_fl(vec, fac);
694 
695  /* 3) Translate back to original space, with the shrinkage applied */
696  add_v3_v3v3(fpt, gso->dvec, vec);
697  mul_v3_m4v3(&pt->x, gso->object->imat, fpt);
698 
699  /* compute lock axis */
700  gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
701 
702  /* done */
703  return true;
704 }
705 
706 /* ----------------------------------------------- */
707 /* Twist Brush - Rotate Around midpoint */
708 /* Take the screenspace coordinates of the point, rotate this around the brush midpoint,
709  * convert the rotated point and convert it into "data" space
710  */
711 
713  bGPDstroke *gps,
714  float UNUSED(rot_eval),
715  int pt_index,
716  const int radius,
717  const int co[2])
718 {
719  bGPDspoint *pt = gps->points + pt_index;
720  float angle, inf;
721  float save_pt[3];
722  copy_v3_v3(save_pt, &pt->x);
723 
724  /* Angle to rotate by */
725  inf = gpencil_brush_influence_calc(gso, radius, co);
726  angle = DEG2RADF(1.0f) * inf;
727 
728  if (gpencil_brush_invert_check(gso)) {
729  /* invert angle that we rotate by */
730  angle *= -1;
731  }
732 
733  /* Rotate in 2D or 3D space? */
734  if (gps->flag & GP_STROKE_3DSPACE) {
735  /* Perform rotation in 3D space... */
736  RegionView3D *rv3d = gso->region->regiondata;
737  float rmat[3][3];
738  float axis[3];
739  float vec[3];
740 
741  /* Compute rotation matrix - rotate around view vector by angle */
742  negate_v3_v3(axis, rv3d->persinv[2]);
743  normalize_v3(axis);
744 
746 
747  /* Rotate point */
748  float fpt[3];
749  mul_v3_m4v3(fpt, gso->object->obmat, &pt->x);
750  sub_v3_v3v3(vec, fpt, gso->dvec); /* make relative to center
751  * (center is stored in dvec) */
752  mul_m3_v3(rmat, vec);
753  add_v3_v3v3(fpt, vec, gso->dvec); /* restore */
754  mul_v3_m4v3(&pt->x, gso->object->imat, fpt);
755 
756  /* compute lock axis */
757  gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
758  }
759  else {
760  const float axis[3] = {0.0f, 0.0f, 1.0f};
761  float vec[3] = {0.0f};
762  float rmat[3][3];
763 
764  /* Express position of point relative to cursor, ready to rotate */
765  /* XXX: There is still some offset here, but it's close to working as expected. */
766  vec[0] = (float)(co[0] - gso->mval[0]);
767  vec[1] = (float)(co[1] - gso->mval[1]);
768 
769  /* rotate point */
771  mul_m3_v3(rmat, vec);
772 
773  /* Convert back to screen-coordinates */
774  vec[0] += (float)gso->mval[0];
775  vec[1] += (float)gso->mval[1];
776 
777  /* Map from screen-coordinates to final coordinate space */
778  if (gps->flag & GP_STROKE_2DSPACE) {
779  View2D *v2d = gso->gsc.v2d;
780  UI_view2d_region_to_view(v2d, vec[0], vec[1], &pt->x, &pt->y);
781  }
782  else {
783  /* XXX */
784  copy_v2_v2(&pt->x, vec);
785  }
786  }
787 
788  /* done */
789  return true;
790 }
791 
792 /* ----------------------------------------------- */
793 /* Randomize Brush */
794 /* Apply some random jitter to the point */
796  bGPDstroke *gps,
797  float UNUSED(rot_eval),
798  int pt_index,
799  const int radius,
800  const int co[2])
801 {
802  bGPDspoint *pt = gps->points + pt_index;
803  float save_pt[3];
804  copy_v3_v3(save_pt, &pt->x);
805 
806  /* Amount of jitter to apply depends on the distance of the point to the cursor,
807  * as well as the strength of the brush
808  */
809  const float inf = gpencil_brush_influence_calc(gso, radius, co) / 2.0f;
810  const float fac = BLI_rng_get_float(gso->rng) * inf;
811 
812  /* apply random to position */
814  /* Jitter is applied perpendicular to the mouse movement vector
815  * - We compute all effects in screenspace (since it's easier)
816  * and then project these to get the points/distances in
817  * view-space as needed.
818  */
819  float mvec[2], svec[2];
820 
821  /* mouse movement in ints -> floats */
822  mvec[0] = (float)(gso->mval[0] - gso->mval_prev[0]);
823  mvec[1] = (float)(gso->mval[1] - gso->mval_prev[1]);
824 
825  /* rotate mvec by 90 degrees... */
826  svec[0] = -mvec[1];
827  svec[1] = mvec[0];
828 
829  /* scale the displacement by the random displacement, and apply */
830  if (BLI_rng_get_float(gso->rng) > 0.5f) {
831  mul_v2_fl(svec, -fac);
832  }
833  else {
834  mul_v2_fl(svec, fac);
835  }
836 
837  /* convert to dataspace */
838  if (gps->flag & GP_STROKE_3DSPACE) {
839  /* 3D: Project to 3D space */
840  bool flip;
841  RegionView3D *rv3d = gso->region->regiondata;
842  float zfac = ED_view3d_calc_zfac(rv3d, &pt->x, &flip);
843  if (flip == false) {
844  float dvec[3];
845  ED_view3d_win_to_delta(gso->gsc.region, svec, dvec, zfac);
846  add_v3_v3(&pt->x, dvec);
847  /* compute lock axis */
848  gpencil_sculpt_compute_lock_axis(gso, pt, save_pt);
849  }
850  }
851  }
852  /* apply random to strength */
854  if (BLI_rng_get_float(gso->rng) > 0.5f) {
855  pt->strength += fac;
856  }
857  else {
858  pt->strength -= fac;
859  }
860  CLAMP_MIN(pt->strength, 0.0f);
861  CLAMP_MAX(pt->strength, 1.0f);
862  }
863  /* apply random to thickness (use pressure) */
865  if (BLI_rng_get_float(gso->rng) > 0.5f) {
866  pt->pressure += fac;
867  }
868  else {
869  pt->pressure -= fac;
870  }
871  /* only limit lower value */
872  CLAMP_MIN(pt->pressure, 0.0f);
873  }
874  /* apply random to UV (use pressure) */
876  if (BLI_rng_get_float(gso->rng) > 0.5f) {
877  pt->uv_rot += fac;
878  }
879  else {
880  pt->uv_rot -= fac;
881  }
882  CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
883  }
884 
885  /* done */
886  return true;
887 }
888 
889 /* ************************************************ */
890 /* Non Callback-Based Brushes */
891 /* Clone Brush ------------------------------------- */
892 /* How this brush currently works:
893  * - If this is start of the brush stroke, paste immediately under the cursor
894  * by placing the midpoint of the buffer strokes under the cursor now
895  *
896  * - Otherwise, in:
897  * "Stamp Mode" - Move the newly pasted strokes so that their center follows the cursor
898  * "Continuous" - Repeatedly just paste new copies for where the brush is now
899  */
900 
901 /* Custom state data for clone brush */
902 typedef struct tGPSB_CloneBrushData {
903  /* midpoint of the strokes on the clipboard */
904  float buffer_midpoint[3];
905 
906  /* number of strokes in the paste buffer (and/or to be created each time) */
907  size_t totitems;
908 
909  /* for "stamp" mode, the currently pasted brushes */
911 
915 
916 /* Initialize "clone" brush data. */
918 {
920  bGPDstroke *gps;
921 
922  /* Initialize custom-data. */
923  gso->customdata = data = MEM_callocN(sizeof(tGPSB_CloneBrushData), "CloneBrushData");
924 
925  /* compute midpoint of strokes on clipboard */
926  for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) {
927  if (ED_gpencil_stroke_can_use(C, gps)) {
928  const float dfac = 1.0f / ((float)gps->totpoints);
929  float mid[3] = {0.0f};
930 
931  bGPDspoint *pt;
932  int i;
933 
934  /* compute midpoint of this stroke */
935  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
936  float co[3];
937 
938  mul_v3_v3fl(co, &pt->x, dfac);
939  add_v3_v3(mid, co);
940  }
941 
942  /* combine this stroke's data with the main data */
943  add_v3_v3(data->buffer_midpoint, mid);
944  data->totitems++;
945  }
946  }
947 
948  /* Divide the midpoint by the number of strokes, to finish averaging it */
949  if (data->totitems > 1) {
950  mul_v3_fl(data->buffer_midpoint, 1.0f / (float)data->totitems);
951  }
952 
953  /* Create a buffer for storing the current strokes */
954  if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
955  data->new_strokes = MEM_callocN(sizeof(bGPDstroke *) * data->totitems,
956  "cloned strokes ptr array");
957  }
958 
959  /* Init colormap for mapping between the pasted stroke's source color (names)
960  * and the final colors that will be used here instead.
961  */
963 }
964 
965 /* Free custom data used for "clone" brush */
967 {
969 
970  /* free strokes array */
971  if (data->new_strokes) {
972  MEM_freeN(data->new_strokes);
973  data->new_strokes = NULL;
974  }
975 
976  /* free copybuf colormap */
977  if (data->new_colors) {
978  BLI_ghash_free(data->new_colors, NULL, NULL);
979  data->new_colors = NULL;
980  }
981 
982  /* free the customdata itself */
983  MEM_freeN(data);
984  gso->customdata = NULL;
985 }
986 
987 /* Create new copies of the strokes on the clipboard */
989 {
991 
992  Object *ob = gso->object;
993  bGPdata *gpd = (bGPdata *)ob->data;
994  Scene *scene = gso->scene;
995  bGPDstroke *gps;
996 
997  float delta[3];
998  size_t strokes_added = 0;
999 
1000  /* Compute amount to offset the points by */
1001  /* NOTE: This assumes that screenspace strokes are NOT used in the 3D view... */
1002 
1003  gpencil_brush_calc_midpoint(gso); /* this puts the cursor location into gso->dvec */
1004  sub_v3_v3v3(delta, gso->dvec, data->buffer_midpoint);
1005 
1006  /* Copy each stroke into the layer */
1007  for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) {
1008  if (ED_gpencil_stroke_can_use(C, gps)) {
1009  bGPDstroke *new_stroke;
1010  bGPDspoint *pt;
1011  int i;
1012 
1013  bGPDlayer *gpl = NULL;
1014  /* Try to use original layer. */
1015  if (gps->runtime.tmp_layerinfo[0] != '\0') {
1017  }
1018 
1019  /* if not available, use active layer. */
1020  if (gpl == NULL) {
1022  }
1025  if (gpf == NULL) {
1026  continue;
1027  }
1028 
1029  /* Make a new stroke */
1030  new_stroke = BKE_gpencil_stroke_duplicate(gps, true, true);
1031 
1032  new_stroke->next = new_stroke->prev = NULL;
1033  BLI_addtail(&gpf->strokes, new_stroke);
1034 
1035  /* Fix color references */
1036  Material *ma = BLI_ghash_lookup(data->new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
1037  new_stroke->mat_nr = BKE_gpencil_object_material_index_get(ob, ma);
1038  if (!ma || new_stroke->mat_nr < 0) {
1039  new_stroke->mat_nr = 0;
1040  }
1041  /* Adjust all the stroke's points, so that the strokes
1042  * get pasted relative to where the cursor is now
1043  */
1044  for (i = 0, pt = new_stroke->points; i < new_stroke->totpoints; i++, pt++) {
1045  /* Rotate around center new position */
1046  mul_mat3_m4_v3(gso->object->obmat, &pt->x); /* only rotation component */
1047 
1048  /* assume that the delta can just be applied, and then everything works */
1049  add_v3_v3(&pt->x, delta);
1050  mul_m4_v3(gso->object->imat, &pt->x);
1051  }
1052 
1053  /* Store ref for later */
1054  if ((data->new_strokes) && (strokes_added < data->totitems)) {
1055  data->new_strokes[strokes_added] = new_stroke;
1056  strokes_added++;
1057  }
1058  }
1059  }
1060 }
1061 
1062 /* Move newly-added strokes around - "Stamp" mode of the Clone brush */
1064 {
1066  size_t snum;
1067 
1068  /* Compute the amount of movement to apply (overwrites dvec) */
1069  gso->rot_eval = 0.0f;
1071 
1072  /* For each of the stored strokes, apply the offset to each point */
1073  /* NOTE: Again this assumes that in the 3D view,
1074  * we only have 3d space and not screenspace strokes... */
1075  for (snum = 0; snum < data->totitems; snum++) {
1076  bGPDstroke *gps = data->new_strokes[snum];
1077  bGPDspoint *pt;
1078  int i;
1079 
1080  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1081  /* "Smudge" Effect falloff */
1082  float delta[3] = {0.0f};
1083  int sco[2] = {0};
1084  float influence;
1085 
1086  /* compute influence on point */
1087  gpencil_point_to_xy(&gso->gsc, gps, pt, &sco[0], &sco[1]);
1088  influence = gpencil_brush_influence_calc(gso, gso->brush->size, sco);
1089 
1090  /* adjust the amount of displacement to apply */
1091  mul_v3_v3fl(delta, gso->dvec, influence);
1092 
1093  /* apply */
1094  add_v3_v3(&pt->x, delta);
1095  }
1096  }
1097 }
1098 
1099 /* Entrypoint for applying "clone" brush */
1101 {
1102  /* Which "mode" are we operating in? */
1103  if (gso->first) {
1104  /* Create initial clones */
1105  gpencil_brush_clone_add(C, gso);
1106  }
1107  else {
1108  /* Stamp or Continuous Mode */
1109  if (1 /*gso->brush->mode == GP_EDITBRUSH_CLONE_MODE_STAMP*/) {
1110  /* Stamp - Proceed to translate the newly added strokes */
1112  }
1113  else {
1114  /* Continuous - Just keep pasting every time we move. */
1115  /* TODO: The spacing of repeat should be controlled using a
1116  * "stepsize" or similar property? */
1117  gpencil_brush_clone_add(C, gso);
1118  }
1119  }
1120 
1121  return true;
1122 }
1123 
1124 /* ************************************************ */
1125 /* Header Info for GPencil Sculpt */
1126 
1128 {
1129  Brush *brush = gso->brush;
1130  char str[UI_MAX_DRAW_STR] = "";
1131 
1132  BLI_snprintf(str,
1133  sizeof(str),
1134  TIP_("GPencil Sculpt: %s Stroke | LMB to paint | RMB/Escape to Exit"
1135  " | Ctrl to Invert Action | Wheel Up/Down for Size "
1136  " | Shift-Wheel Up/Down for Strength"),
1137  brush->id.name + 2);
1138 
1140 }
1141 
1142 /* ************************************************ */
1143 /* Grease Pencil Sculpting Operator */
1144 
1145 /* Init/Exit ----------------------------------------------- */
1146 
1148 {
1152 
1153  /* set the brush using the tool */
1154  tGP_BrushEditData *gso;
1155 
1156  /* setup operator data */
1157  gso = MEM_callocN(sizeof(tGP_BrushEditData), "tGP_BrushEditData");
1158  op->customdata = gso;
1159 
1161  gso->bmain = CTX_data_main(C);
1162  /* store state */
1164 
1165  /* Random generator, only init once. */
1166  uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
1167  rng_seed ^= POINTER_AS_UINT(gso);
1168  gso->rng = BLI_rng_new(rng_seed);
1169 
1170  gso->is_painting = false;
1171  gso->first = true;
1172 
1174  gso->cfra = INT_MAX; /* NOTE: So that first stroke will get handled in init_stroke() */
1175 
1176  gso->scene = scene;
1177  gso->object = ob;
1178  if (ob) {
1179  invert_m4_m4(gso->inv_mat, ob->obmat);
1180  gso->vrgroup = ob->actdef - 1;
1181  if (!BLI_findlink(&ob->defbase, gso->vrgroup)) {
1182  gso->vrgroup = -1;
1183  }
1184  /* Check if some modifier can transform the stroke. */
1186  }
1187  else {
1188  unit_m4(gso->inv_mat);
1189  gso->vrgroup = -1;
1190  gso->is_transformed = false;
1191  }
1192 
1193  gso->area = CTX_wm_area(C);
1194  gso->region = CTX_wm_region(C);
1195 
1196  Paint *paint = &ts->gp_sculptpaint->paint;
1197  gso->brush = paint->brush;
1199 
1200  /* save mask */
1201  gso->mask = ts->gpencil_selectmode_sculpt;
1202 
1203  /* multiframe settings */
1204  gso->is_multiframe = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd);
1206 
1207  /* Init multi-edit falloff curve data before doing anything,
1208  * so we won't have to do it again later. */
1209  if (gso->is_multiframe) {
1211  }
1212 
1213  /* Initialize custom data for brushes. */
1214  char tool = gso->brush->gpencil_sculpt_tool;
1215  switch (tool) {
1216  case GPSCULPT_TOOL_CLONE: {
1217  bGPDstroke *gps;
1218  bool found = false;
1219 
1220  /* check that there are some usable strokes in the buffer */
1221  for (gps = gpencil_strokes_copypastebuf.first; gps; gps = gps->next) {
1222  if (ED_gpencil_stroke_can_use(C, gps)) {
1223  found = true;
1224  break;
1225  }
1226  }
1227 
1228  if (found == false) {
1229  /* STOP HERE! Nothing to paste! */
1230  BKE_report(op->reports,
1231  RPT_ERROR,
1232  "Copy some strokes to the clipboard before using the Clone brush to paste "
1233  "copies of them");
1234 
1235  MEM_freeN(gso);
1236  op->customdata = NULL;
1237  return false;
1238  }
1239  /* Initialize custom-data. */
1241  break;
1242  }
1243 
1244  case GPSCULPT_TOOL_GRAB: {
1245  /* Initialize the cache needed for this brush. */
1246  gso->stroke_customdata = BLI_ghash_ptr_new("GP Grab Brush - Strokes Hash");
1247  break;
1248  }
1249 
1250  /* Others - No customdata needed */
1251  default:
1252  break;
1253  }
1254 
1255  /* setup space conversions */
1257 
1258  /* update header */
1260 
1261  return true;
1262 }
1263 
1265 {
1266  tGP_BrushEditData *gso = op->customdata;
1267  wmWindow *win = CTX_wm_window(C);
1268  char tool = gso->brush->gpencil_sculpt_tool;
1269 
1270  /* free brush-specific data */
1271  switch (tool) {
1272  case GPSCULPT_TOOL_GRAB: {
1273  /* Free per-stroke customdata
1274  * - Keys don't need to be freed, as those are the strokes
1275  * - Values assigned to those keys do, as they are custom structs
1276  */
1278  break;
1279  }
1280 
1281  case GPSCULPT_TOOL_CLONE: {
1282  /* Free customdata */
1284  break;
1285  }
1286 
1287  default:
1288  break;
1289  }
1290 
1291  /* unregister timer (only used for realtime) */
1292  if (gso->timer) {
1294  }
1295 
1296  if (gso->rng != NULL) {
1297  BLI_rng_free(gso->rng);
1298  }
1299 
1300  /* Disable headerprints. */
1302 
1303  /* disable temp invert flag */
1305 
1306  /* Update geometry data for tagged strokes. */
1308 
1309  /* free operator data */
1310  MEM_freeN(gso);
1311  op->customdata = NULL;
1312 }
1313 
1314 /* poll callback for stroke sculpting operator(s) */
1316 {
1317  ScrArea *area = CTX_wm_area(C);
1318  if (area && area->spacetype != SPACE_VIEW3D) {
1319  return false;
1320  }
1321 
1322  /* NOTE: this is a bit slower, but is the most accurate... */
1323  return CTX_DATA_COUNT(C, editable_gpencil_strokes) != 0;
1324 }
1325 
1326 /* Init Sculpt Stroke ---------------------------------- */
1327 
1329 {
1330  bGPdata *gpd = gso->gpd;
1331 
1332  Scene *scene = gso->scene;
1333  int cfra = CFRA;
1334 
1335  /* only try to add a new frame if this is the first stroke, or the frame has changed */
1336  if ((gpd == NULL) || (cfra == gso->cfra)) {
1337  return;
1338  }
1339 
1340  /* go through each layer, and ensure that we've got a valid frame to use */
1341  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1342  if (!IS_AUTOKEY_ON(scene) && (gpl->actframe == NULL)) {
1343  continue;
1344  }
1345 
1346  /* only editable and visible layers are considered */
1347  if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
1348  bGPDframe *gpf = gpl->actframe;
1349 
1350  /* Make a new frame to work on if the layer's frame
1351  * and the current scene frame don't match up:
1352  * - This is useful when animating as it saves that "uh-oh" moment when you realize you've
1353  * spent too much time editing the wrong frame.
1354  */
1355  if ((IS_AUTOKEY_ON(scene)) && (gpf->framenum != cfra)) {
1356  BKE_gpencil_frame_addcopy(gpl, cfra);
1357  /* Need tag to recalculate evaluated data to avoid crashes. */
1360  }
1361  }
1362  }
1363 
1364  /* save off new current frame, so that next update works fine */
1365  gso->cfra = cfra;
1366 }
1367 
1368 /* Apply ----------------------------------------------- */
1369 
1370 /* Get angle of the segment relative to the original segment before any transformation
1371  * For strokes with one point only this is impossible to calculate because there isn't a
1372  * valid reference point.
1373  */
1375  bGPDstroke *gps_eval,
1376  bGPDspoint *pt_eval,
1377  int idx_eval)
1378 {
1379  /* If multiframe or no modifiers, return 0. */
1380  if ((GPENCIL_MULTIEDIT_SESSIONS_ON(gso->gpd)) || (!gso->is_transformed)) {
1381  return 0.0f;
1382  }
1383 
1384  GP_SpaceConversion *gsc = &gso->gsc;
1385  bGPDstroke *gps_orig = (gps_eval->runtime.gps_orig) ? gps_eval->runtime.gps_orig : gps_eval;
1386  bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig];
1387  bGPDspoint *pt_prev_eval = NULL;
1388  bGPDspoint *pt_orig_prev = NULL;
1389  if (idx_eval != 0) {
1390  pt_prev_eval = &gps_eval->points[idx_eval - 1];
1391  }
1392  else {
1393  if (gps_eval->totpoints > 1) {
1394  pt_prev_eval = &gps_eval->points[idx_eval + 1];
1395  }
1396  else {
1397  return 0.0f;
1398  }
1399  }
1400 
1401  if (pt_eval->runtime.idx_orig != 0) {
1402  pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig - 1];
1403  }
1404  else {
1405  if (gps_orig->totpoints > 1) {
1406  pt_orig_prev = &gps_orig->points[pt_eval->runtime.idx_orig + 1];
1407  }
1408  else {
1409  return 0.0f;
1410  }
1411  }
1412 
1413  /* create 2D vectors of the stroke segments */
1414  float v_orig_a[2], v_orig_b[2], v_eval_a[2], v_eval_b[2];
1415 
1416  gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig->x, v_orig_a);
1417  gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_orig_prev->x, v_orig_b);
1418  sub_v2_v2(v_orig_a, v_orig_b);
1419 
1420  gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_eval->x, v_eval_a);
1421  gpencil_point_3d_to_xy(gsc, GP_STROKE_3DSPACE, &pt_prev_eval->x, v_eval_b);
1422  sub_v2_v2(v_eval_a, v_eval_b);
1423 
1424  return angle_v2v2(v_orig_a, v_eval_a);
1425 }
1426 
1427 /* Apply brush operation to points in this stroke */
1429  bGPDstroke *gps,
1430  const float diff_mat[4][4],
1431  GP_BrushApplyCb apply)
1432 {
1433  GP_SpaceConversion *gsc = &gso->gsc;
1434  rcti *rect = &gso->brush_rect;
1435  Brush *brush = gso->brush;
1436  char tool = gso->brush->gpencil_sculpt_tool;
1437  const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
1438  gso->brush->size;
1439 
1440  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
1441  bGPDspoint *pt_active = NULL;
1442 
1443  bGPDspoint *pt1, *pt2;
1444  bGPDspoint *pt = NULL;
1445  int pc1[2] = {0};
1446  int pc2[2] = {0};
1447  int i;
1448  int index;
1449  bool include_last = false;
1450  bool changed = false;
1451  float rot_eval = 0.0f;
1452 
1453  if (gps->totpoints == 1) {
1454  bGPDspoint pt_temp;
1455  pt = &gps->points[0];
1456  gpencil_point_to_parent_space(gps->points, diff_mat, &pt_temp);
1457  gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]);
1458 
1459  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
1460  /* do boundbox check first */
1461  if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
1462  /* only check if point is inside */
1463  int mval_i[2];
1464  round_v2i_v2fl(mval_i, gso->mval);
1465  if (len_v2v2_int(mval_i, pc1) <= radius) {
1466  /* apply operation to this point */
1467  if (pt_active != NULL) {
1468  rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, 0);
1469  changed = apply(gso, gps_active, rot_eval, 0, radius, pc1);
1470  }
1471  }
1472  }
1473  }
1474  else {
1475  /* Loop over the points in the stroke, checking for intersections
1476  * - an intersection means that we touched the stroke
1477  */
1478  for (i = 0; (i + 1) < gps->totpoints; i++) {
1479  /* Get points to work with */
1480  pt1 = gps->points + i;
1481  pt2 = gps->points + i + 1;
1482 
1483  /* Skip if neither one is selected
1484  * (and we are only allowed to edit/consider selected points) */
1485  if (GPENCIL_ANY_SCULPT_MASK(gso->mask)) {
1486  if (!(pt1->flag & GP_SPOINT_SELECT) && !(pt2->flag & GP_SPOINT_SELECT)) {
1487  include_last = false;
1488  continue;
1489  }
1490  }
1491  bGPDspoint npt;
1492  gpencil_point_to_parent_space(pt1, diff_mat, &npt);
1493  gpencil_point_to_xy(gsc, gps, &npt, &pc1[0], &pc1[1]);
1494 
1495  gpencil_point_to_parent_space(pt2, diff_mat, &npt);
1496  gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]);
1497 
1498  /* Check that point segment of the boundbox of the selection stroke */
1499  if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
1500  ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
1501  /* Check if point segment of stroke had anything to do with
1502  * brush region (either within stroke painted, or on its lines)
1503  * - this assumes that linewidth is irrelevant
1504  */
1505  if (gpencil_stroke_inside_circle(gso->mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
1506  /* Apply operation to these points */
1507  bool ok = false;
1508 
1509  /* To each point individually... */
1510  pt = &gps->points[i];
1511  if ((pt->runtime.pt_orig == NULL) && (tool != GPSCULPT_TOOL_GRAB)) {
1512  continue;
1513  }
1514  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
1515  /* If masked and the point is not selected, skip it. */
1516  if ((GPENCIL_ANY_SCULPT_MASK(gso->mask)) &&
1517  ((pt_active->flag & GP_SPOINT_SELECT) == 0)) {
1518  continue;
1519  }
1520  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
1521  if ((pt_active != NULL) && (index < gps_active->totpoints)) {
1522  rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i);
1523  ok = apply(gso, gps_active, rot_eval, index, radius, pc1);
1524  }
1525 
1526  /* Only do the second point if this is the last segment,
1527  * and it is unlikely that the point will get handled
1528  * otherwise.
1529  *
1530  * NOTE: There is a small risk here that the second point wasn't really
1531  * actually in-range. In that case, it only got in because
1532  * the line linking the points was!
1533  */
1534  if (i + 1 == gps->totpoints - 1) {
1535  pt = &gps->points[i + 1];
1536  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
1537  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i + 1;
1538  if ((pt_active != NULL) && (index < gps_active->totpoints)) {
1539  rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i + 1);
1540  ok |= apply(gso, gps_active, rot_eval, index, radius, pc2);
1541  include_last = false;
1542  }
1543  }
1544  else {
1545  include_last = true;
1546  }
1547 
1548  changed |= ok;
1549  }
1550  else if (include_last) {
1551  /* This case is for cases where for whatever reason the second vert (1st here)
1552  * doesn't get included because the whole edge isn't in bounds,
1553  * but it would've qualified since it did with the previous step
1554  * (but wasn't added then, to avoid double-ups).
1555  */
1556  pt = &gps->points[i];
1557  pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt;
1558  index = (pt->runtime.pt_orig) ? pt->runtime.idx_orig : i;
1559  if ((pt_active != NULL) && (index < gps_active->totpoints)) {
1560  rot_eval = gpencil_sculpt_rotation_eval_get(gso, gps, pt, i);
1561  changed |= apply(gso, gps_active, rot_eval, index, radius, pc1);
1562  include_last = false;
1563  }
1564  }
1565  }
1566  }
1567  }
1568 
1569  return changed;
1570 }
1571 
1572 /* Apply sculpt brushes to strokes in the given frame */
1574  tGP_BrushEditData *gso,
1575  bGPDlayer *gpl,
1576  bGPDframe *gpf,
1577  const float diff_mat[4][4])
1578 {
1579  bool changed = false;
1580  bool redo_geom = false;
1581  Object *ob = gso->object;
1582  bGPdata *gpd = ob->data;
1583  char tool = gso->brush->gpencil_sculpt_tool;
1584  GP_SpaceConversion *gsc = &gso->gsc;
1585  Brush *brush = gso->brush;
1586  const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
1587  gso->brush->size;
1588  /* Calc bound box matrix. */
1589  float bound_mat[4][4];
1590  BKE_gpencil_layer_transform_matrix_get(gso->depsgraph, gso->object, gpl, bound_mat);
1591 
1592  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1593  /* skip strokes that are invalid for current view */
1594  if (ED_gpencil_stroke_can_use(C, gps) == false) {
1595  continue;
1596  }
1597  /* check if the color is editable */
1598  if (ED_gpencil_stroke_material_editable(ob, gpl, gps) == false) {
1599  continue;
1600  }
1601 
1602  /* Check if the stroke collide with brush. */
1603  if (!ED_gpencil_stroke_check_collision(gsc, gps, gso->mval, radius, bound_mat)) {
1604  continue;
1605  }
1606 
1607  switch (tool) {
1608  case GPSCULPT_TOOL_SMOOTH: /* Smooth strokes */
1609  {
1610  changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_smooth_apply);
1611  redo_geom |= changed;
1612  break;
1613  }
1614 
1615  case GPSCULPT_TOOL_THICKNESS: /* Adjust stroke thickness */
1616  {
1617  changed |= gpencil_sculpt_brush_do_stroke(
1618  gso, gps, diff_mat, gpencil_brush_thickness_apply);
1619  break;
1620  }
1621 
1622  case GPSCULPT_TOOL_STRENGTH: /* Adjust stroke color strength */
1623  {
1624  changed |= gpencil_sculpt_brush_do_stroke(
1625  gso, gps, diff_mat, gpencil_brush_strength_apply);
1626  break;
1627  }
1628 
1629  case GPSCULPT_TOOL_GRAB: /* Grab points */
1630  {
1631  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
1632  if (gps_active != NULL) {
1633  if (gso->first) {
1634  /* First time this brush stroke is being applied:
1635  * 1) Prepare data buffers (init/clear) for this stroke
1636  * 2) Use the points now under the cursor
1637  */
1638  gpencil_brush_grab_stroke_init(gso, gps_active);
1639  changed |= gpencil_sculpt_brush_do_stroke(
1640  gso, gps_active, diff_mat, gpencil_brush_grab_store_points);
1641  }
1642  else {
1643  /* Apply effect to the stored points */
1644  gpencil_brush_grab_apply_cached(gso, gps_active, diff_mat);
1645  changed |= true;
1646  }
1647  }
1648  redo_geom |= changed;
1649  break;
1650  }
1651 
1652  case GPSCULPT_TOOL_PUSH: /* Push points */
1653  {
1654  changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_push_apply);
1655  redo_geom |= changed;
1656  break;
1657  }
1658 
1659  case GPSCULPT_TOOL_PINCH: /* Pinch points */
1660  {
1661  changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_pinch_apply);
1662  redo_geom |= changed;
1663  break;
1664  }
1665 
1666  case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */
1667  {
1668  changed |= gpencil_sculpt_brush_do_stroke(gso, gps, diff_mat, gpencil_brush_twist_apply);
1669  redo_geom |= changed;
1670  break;
1671  }
1672 
1673  case GPSCULPT_TOOL_RANDOMIZE: /* Apply jitter */
1674  {
1675  changed |= gpencil_sculpt_brush_do_stroke(
1676  gso, gps, diff_mat, gpencil_brush_randomize_apply);
1677  redo_geom |= changed;
1678  break;
1679  }
1680 
1681  default:
1682  printf("ERROR: Unknown type of GPencil Sculpt brush \n");
1683  break;
1684  }
1685 
1686  /* Triangulation must be calculated. */
1687  if (redo_geom) {
1688  bGPDstroke *gps_active = (gps->runtime.gps_orig) ? gps->runtime.gps_orig : gps;
1689  if (gpl->actframe == gpf) {
1690  MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
1691  /* Update active frame now, only if material has fill. */
1692  if (gp_style->flag & GP_MATERIAL_FILL_SHOW) {
1693  BKE_gpencil_stroke_geometry_update(gpd, gps_active);
1694  }
1695  else {
1696  gpencil_recalc_geometry_tag(gps_active);
1697  }
1698  }
1699  else {
1700  /* Delay a full recalculation for other frames. */
1701  gpencil_recalc_geometry_tag(gps_active);
1702  }
1703  }
1704  }
1705 
1706  return changed;
1707 }
1708 
1709 /* Perform two-pass brushes which modify the existing strokes */
1711 {
1712  ToolSettings *ts = gso->scene->toolsettings;
1713  Depsgraph *depsgraph = gso->depsgraph;
1714  Object *obact = gso->object;
1715  bool changed = false;
1716 
1717  Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &obact->id);
1718  bGPdata *gpd = (bGPdata *)ob_eval->data;
1719 
1720  /* Calculate brush-specific data which applies equally to all points */
1721  char tool = gso->brush->gpencil_sculpt_tool;
1722  switch (tool) {
1723  case GPSCULPT_TOOL_GRAB: /* Grab points */
1724  case GPSCULPT_TOOL_PUSH: /* Push points */
1725  {
1726  /* calculate amount of displacement to apply */
1727  gso->rot_eval = 0.0f;
1729  break;
1730  }
1731 
1732  case GPSCULPT_TOOL_PINCH: /* Pinch points */
1733  case GPSCULPT_TOOL_TWIST: /* Twist points around midpoint */
1734  {
1735  /* calculate midpoint of the brush (in data space) */
1737  break;
1738  }
1739 
1740  case GPSCULPT_TOOL_RANDOMIZE: /* Random jitter */
1741  {
1742  /* compute the displacement vector for the cursor (in data space) */
1743  gso->rot_eval = 0.0f;
1745  break;
1746  }
1747 
1748  default:
1749  break;
1750  }
1751 
1752  /* Find visible strokes, and perform operations on those if hit */
1753  LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1754  /* If no active frame, don't do anything... */
1755  if ((!BKE_gpencil_layer_is_editable(gpl)) || (gpl->actframe == NULL)) {
1756  continue;
1757  }
1758 
1759  /* calculate difference matrix */
1760  float diff_mat[4][4];
1761  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
1762  mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_invmat);
1763 
1764  /* Active Frame or MultiFrame? */
1765  if (gso->is_multiframe) {
1766  /* init multiframe falloff options */
1767  int f_init = 0;
1768  int f_end = 0;
1769 
1770  if (gso->use_multiframe_falloff) {
1771  BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
1772  }
1773 
1774  LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
1775  /* Always do active frame; Otherwise, only include selected frames */
1776  if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) {
1777  /* compute multiframe falloff factor */
1778  if (gso->use_multiframe_falloff) {
1779  /* Falloff depends on distance to active frame
1780  * (relative to the overall frame range). */
1782  gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
1783  }
1784  else {
1785  /* No falloff */
1786  gso->mf_falloff = 1.0f;
1787  }
1788 
1789  /* affect strokes in this frame */
1790  changed |= gpencil_sculpt_brush_do_frame(C, gso, gpl, gpf, diff_mat);
1791  }
1792  }
1793  }
1794  else {
1795  if (gpl->actframe != NULL) {
1796  /* Apply to active frame's strokes */
1797  gso->mf_falloff = 1.0f;
1798  changed |= gpencil_sculpt_brush_do_frame(C, gso, gpl, gpl->actframe, diff_mat);
1799  }
1800  }
1801  }
1802 
1803  return changed;
1804 }
1805 
1806 /* Calculate settings for applying brush */
1808 {
1809  tGP_BrushEditData *gso = op->customdata;
1810  Brush *brush = gso->brush;
1811  const int radius = (brush->flag & GP_BRUSH_USE_PRESSURE) ? gso->brush->size * gso->pressure :
1812  gso->brush->size;
1813  float mousef[2];
1814  int mouse[2];
1815  bool changed = false;
1816 
1817  /* Get latest mouse coordinates */
1818  RNA_float_get_array(itemptr, "mouse", mousef);
1819  gso->mval[0] = mouse[0] = (int)(mousef[0]);
1820  gso->mval[1] = mouse[1] = (int)(mousef[1]);
1821 
1822  gso->pressure = RNA_float_get(itemptr, "pressure");
1823 
1824  if (RNA_boolean_get(itemptr, "pen_flip")) {
1825  gso->flag |= GP_SCULPT_FLAG_INVERT;
1826  }
1827  else {
1828  gso->flag &= ~GP_SCULPT_FLAG_INVERT;
1829  }
1830 
1831  /* Store coordinates as reference, if operator just started running */
1832  if (gso->first) {
1833  gso->mval_prev[0] = gso->mval[0];
1834  gso->mval_prev[1] = gso->mval[1];
1835  gso->pressure_prev = gso->pressure;
1836  }
1837 
1838  /* Update brush_rect, so that it represents the bounding rectangle of brush */
1839  gso->brush_rect.xmin = mouse[0] - radius;
1840  gso->brush_rect.ymin = mouse[1] - radius;
1841  gso->brush_rect.xmax = mouse[0] + radius;
1842  gso->brush_rect.ymax = mouse[1] + radius;
1843 
1844  /* Apply brush */
1845  char tool = gso->brush->gpencil_sculpt_tool;
1846  if (tool == GPSCULPT_TOOL_CLONE) {
1847  changed = gpencil_sculpt_brush_apply_clone(C, gso);
1848  }
1849  else {
1850  changed = gpencil_sculpt_brush_apply_standard(C, gso);
1851  }
1852 
1853  /* Updates */
1854  if (changed) {
1857  }
1858 
1859  /* Store values for next step */
1860  gso->mval_prev[0] = gso->mval[0];
1861  gso->mval_prev[1] = gso->mval[1];
1862  gso->pressure_prev = gso->pressure;
1863  gso->first = false;
1864 }
1865 
1866 /* Running --------------------------------------------- */
1868 {
1869  Main *bmain = gso->bmain;
1870  Brush *brush = BLI_findstring(&bmain->brushes, "Smooth Stroke", offsetof(ID, name) + 2);
1871 
1872  return brush;
1873 }
1874 
1875 /* helper - a record stroke, and apply paint event */
1877 {
1878  tGP_BrushEditData *gso = op->customdata;
1879  PointerRNA itemptr;
1880  float mouse[2];
1881 
1882  mouse[0] = event->mval[0] + 1;
1883  mouse[1] = event->mval[1] + 1;
1884 
1885  /* fill in stroke */
1886  RNA_collection_add(op->ptr, "stroke", &itemptr);
1887 
1888  RNA_float_set_array(&itemptr, "mouse", mouse);
1889  RNA_boolean_set(&itemptr, "pen_flip", event->ctrl != false);
1890  RNA_boolean_set(&itemptr, "is_start", gso->first);
1891 
1892  /* handle pressure sensitivity (which is supplied by tablets and otherwise 1.0) */
1893  float pressure = event->tablet.pressure;
1894  /* special exception here for too high pressure values on first touch in
1895  * windows for some tablets: clamp the values to be sane */
1896  if (pressure >= 0.99f) {
1897  pressure = 1.0f;
1898  }
1899  RNA_float_set(&itemptr, "pressure", pressure);
1900 
1901  if (event->shift) {
1902  gso->brush_prev = gso->brush;
1903 
1905  if (gso->brush == NULL) {
1906  gso->brush = gso->brush_prev;
1907  }
1908  }
1909  else {
1910  if (gso->brush_prev != NULL) {
1911  gso->brush = gso->brush_prev;
1912  }
1913  }
1914 
1915  /* apply */
1916  gpencil_sculpt_brush_apply(C, op, &itemptr);
1917 }
1918 
1919 /* reapply */
1921 {
1922  if (!gpencil_sculpt_brush_init(C, op)) {
1923  return OPERATOR_CANCELLED;
1924  }
1925 
1926  RNA_BEGIN (op->ptr, itemptr, "stroke") {
1927  gpencil_sculpt_brush_apply(C, op, &itemptr);
1928  }
1929  RNA_END;
1930 
1932 
1933  return OPERATOR_FINISHED;
1934 }
1935 
1936 /* start modal painting */
1938 {
1939  tGP_BrushEditData *gso = NULL;
1940  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1941  const bool is_playing = ED_screen_animation_playing(CTX_wm_manager(C)) != NULL;
1942  bool needs_timer = false;
1943  float brush_rate = 0.0f;
1944 
1945  /* the operator cannot work while play animation */
1946  if (is_playing) {
1947  BKE_report(op->reports, RPT_ERROR, "Cannot sculpt while animation is playing");
1948 
1949  return OPERATOR_CANCELLED;
1950  }
1951 
1952  /* init painting data */
1953  if (!gpencil_sculpt_brush_init(C, op)) {
1954  return OPERATOR_CANCELLED;
1955  }
1956 
1957  gso = op->customdata;
1958 
1959  /* Initialize type-specific data (used for the entire session). */
1960  char tool = gso->brush->gpencil_sculpt_tool;
1961  switch (tool) {
1962  /* Brushes requiring timer... */
1964  brush_rate = 0.01f;
1965  needs_timer = true;
1966  break;
1967 
1969  brush_rate = 0.01f;
1970  needs_timer = true;
1971  break;
1972 
1973  case GPSCULPT_TOOL_PINCH:
1974  brush_rate = 0.001f;
1975  needs_timer = true;
1976  break;
1977 
1978  case GPSCULPT_TOOL_TWIST:
1979  brush_rate = 0.01f;
1980  needs_timer = true;
1981  break;
1982 
1983  default:
1984  break;
1985  }
1986 
1987  /* register timer for increasing influence by hovering over an area */
1988  if (needs_timer) {
1989  gso->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, brush_rate);
1990  }
1991 
1992  /* register modal handler */
1994 
1995  /* start drawing immediately? */
1996  if (is_modal == false) {
1997  ARegion *region = CTX_wm_region(C);
1998 
1999  /* ensure that we'll have a new frame to draw on */
2001 
2002  /* apply first dab... */
2003  gso->is_painting = true;
2004  gpencil_sculpt_brush_apply_event(C, op, event);
2005 
2006  /* redraw view with feedback */
2007  ED_region_tag_redraw(region);
2008  }
2009 
2010  return OPERATOR_RUNNING_MODAL;
2011 }
2012 
2013 /* painting - handle events */
2014 static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
2015 {
2016  tGP_BrushEditData *gso = op->customdata;
2017  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
2018  bool redraw_region = false;
2019  bool redraw_toolsettings = false;
2020 
2021  /* The operator can be in 2 states: Painting and Idling */
2022  if (gso->is_painting) {
2023  /* Painting */
2024  switch (event->type) {
2025  /* Mouse Move = Apply somewhere else */
2026  case MOUSEMOVE:
2027  case INBETWEEN_MOUSEMOVE:
2028  /* apply brush effect at new position */
2029  gpencil_sculpt_brush_apply_event(C, op, event);
2030 
2031  /* force redraw, so that the cursor will at least be valid */
2032  redraw_region = true;
2033  break;
2034 
2035  /* Timer Tick - Only if this was our own timer */
2036  case TIMER:
2037  if (event->customdata == gso->timer) {
2038  gso->timerTick = true;
2039  gpencil_sculpt_brush_apply_event(C, op, event);
2040  gso->timerTick = false;
2041  }
2042  break;
2043 
2044  /* Painting mbut release = Stop painting (back to idle) */
2045  case LEFTMOUSE:
2046  // BLI_assert(event->val == KM_RELEASE);
2047  if (is_modal) {
2048  /* go back to idling... */
2049  gso->is_painting = false;
2050  }
2051  else {
2052  /* end sculpt session, since we're not modal */
2053  gso->is_painting = false;
2054 
2056  return OPERATOR_FINISHED;
2057  }
2058  break;
2059 
2060  /* Abort painting if any of the usual things are tried */
2061  case MIDDLEMOUSE:
2062  case RIGHTMOUSE:
2063  case EVT_ESCKEY:
2065  return OPERATOR_FINISHED;
2066  }
2067  }
2068  else {
2069  /* Idling */
2070  BLI_assert(is_modal == true);
2071 
2072  switch (event->type) {
2073  /* Painting mbut press = Start painting (switch to painting state) */
2074  case LEFTMOUSE:
2075  /* do initial "click" apply */
2076  gso->is_painting = true;
2077  gso->first = true;
2078 
2080  gpencil_sculpt_brush_apply_event(C, op, event);
2081  break;
2082 
2083  /* Exit modal operator, based on the "standard" ops */
2084  case RIGHTMOUSE:
2085  case EVT_ESCKEY:
2087  return OPERATOR_FINISHED;
2088 
2089  /* MMB is often used for view manipulations */
2090  case MIDDLEMOUSE:
2091  return OPERATOR_PASS_THROUGH;
2092 
2093  /* Mouse movements should update the brush cursor - Just redraw the active region */
2094  case MOUSEMOVE:
2095  case INBETWEEN_MOUSEMOVE:
2096  redraw_region = true;
2097  break;
2098 
2099  /* Change Frame - Allowed */
2100  case EVT_LEFTARROWKEY:
2101  case EVT_RIGHTARROWKEY:
2102  case EVT_UPARROWKEY:
2103  case EVT_DOWNARROWKEY:
2104  return OPERATOR_PASS_THROUGH;
2105 
2106  /* Camera/View Gizmo's - Allowed */
2107  /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */
2108  case EVT_PAD0:
2109  case EVT_PAD1:
2110  case EVT_PAD2:
2111  case EVT_PAD3:
2112  case EVT_PAD4:
2113  case EVT_PAD5:
2114  case EVT_PAD6:
2115  case EVT_PAD7:
2116  case EVT_PAD8:
2117  case EVT_PAD9:
2118  return OPERATOR_PASS_THROUGH;
2119 
2120  /* Unhandled event */
2121  default:
2122  break;
2123  }
2124  }
2125 
2126  /* Redraw region? */
2127  if (redraw_region) {
2128  ARegion *region = CTX_wm_region(C);
2129  ED_region_tag_redraw(region);
2130  }
2131 
2132  /* Redraw toolsettings (brush settings)? */
2133  if (redraw_toolsettings) {
2136  }
2137 
2138  return OPERATOR_RUNNING_MODAL;
2139 }
2140 
2141 /* Also used for weight paint. */
2143 {
2144  /* identifiers */
2145  ot->name = "Stroke Sculpt";
2146  ot->idname = "GPENCIL_OT_sculpt_paint";
2147  ot->description = "Apply tweaks to strokes by painting over the strokes"; /* XXX */
2148 
2149  /* api callbacks */
2155 
2156  /* flags */
2158 
2159  /* properties */
2160  PropertyRNA *prop;
2161  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2163 
2164  prop = RNA_def_boolean(
2165  ot->srna,
2166  "wait_for_input",
2167  true,
2168  "Wait for Input",
2169  "Enter a mini 'sculpt-mode' if enabled, otherwise, exit after drawing a single stroke");
2171 }
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 ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
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 bGPDlayer * CTX_data_active_gpencil_layer(const bContext *C)
Definition: context.c:1376
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 wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
support for deformation groups and hooks.
struct bGPDframe * BKE_gpencil_frame_addcopy(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:598
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
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
int BKE_gpencil_object_material_index_get(struct Object *ob, struct Material *ma)
Definition: gpencil.c:2437
void BKE_gpencil_frame_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe)
Definition: gpencil.c:2084
struct bGPDlayer * BKE_gpencil_layer_named_get(struct bGPdata *gpd, const char *name)
Definition: gpencil.c:1496
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1307
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, const bool dup_points, const bool dup_curve)
Definition: gpencil.c:957
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:190
@ GP_GETFRAME_USE_PREV
Definition: BKE_gpencil.h:187
bool BKE_gpencil_stroke_smooth_strength(struct bGPDstroke *gps, int point_index, float influence)
Definition: gpencil_geom.c:841
bool BKE_gpencil_stroke_smooth_thickness(struct bGPDstroke *gps, int point_index, float influence)
Definition: gpencil_geom.c:905
bool BKE_gpencil_stroke_smooth_uv(struct bGPDstroke *gps, int point_index, float influence)
Definition: gpencil_geom.c:968
void BKE_gpencil_stroke_geometry_update(struct bGPdata *gpd, struct bGPDstroke *gps)
bool BKE_gpencil_stroke_smooth(struct bGPDstroke *gps, int i, float inf)
Definition: gpencil_geom.c:778
bool BKE_gpencil_has_transform_modifiers(struct Object *ob)
General operations, lookup, etc. for materials.
struct MaterialGPencilStyle * BKE_gpencil_material_settings(struct Object *ob, short act)
Definition: material.c:713
Functions for dealing with objects and deform verts, used by painting and tools.
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
bool BLI_ghash_haskey(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:941
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void * BLI_findstring(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float clamp_f(float value, float min, float max)
#define M_PI_2
Definition: BLI_math_base.h:41
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:243
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
Definition: math_geom.c:405
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:930
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:262
void unit_m4(float m[4][4])
Definition: rct.c:1140
void mul_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:794
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void loc_eul_size_to_mat4(float R[4][4], const float loc[3], const float eul[3], const float size[3])
Definition: math_matrix.c:2653
#define DEG2RADF(_deg)
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle)
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:483
MINLINE void sub_v2_v2(float r[2], const float a[2])
MINLINE float normalize_v3(float r[3])
MINLINE float len_v2v2_int(const int v1[2], const int v2[2])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
Random number functions.
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:76
struct RNG * BLI_rng_new(unsigned int seed)
Definition: rand.cc:54
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:120
bool BLI_rcti_isect_pt(const struct rcti *rect, const int x, const int y)
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:83
#define CLAMP_MAX(a, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_UINT(i)
#define UNUSED(x)
#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_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
eGP_Sculpt_Flag
@ GP_SCULPT_FLAG_TMP_INVERT
@ GP_SCULPT_FLAG_INVERT
@ GP_SCULPT_FLAGMODE_APPLY_UV
@ GP_SCULPT_FLAGMODE_APPLY_POSITION
@ GP_SCULPT_FLAGMODE_APPLY_THICKNESS
@ GP_SCULPT_FLAGMODE_APPLY_STRENGTH
@ GP_BRUSH_USE_PRESSURE
@ BRUSH_DIR_IN
@ GPSCULPT_TOOL_GRAB
@ GPSCULPT_TOOL_TWIST
@ GPSCULPT_TOOL_PUSH
@ GPSCULPT_TOOL_STRENGTH
@ GPSCULPT_TOOL_PINCH
@ GPSCULPT_TOOL_SMOOTH
@ GPSCULPT_TOOL_CLONE
@ GPSCULPT_TOOL_THICKNESS
@ GPSCULPT_TOOL_RANDOMIZE
@ GP_STROKE_TAG
@ GP_STROKE_2DSPACE
@ GP_STROKE_3DSPACE
#define GPENCIL_MULTIEDIT_SESSIONS_ON(gpd)
#define GPENCIL_ANY_SCULPT_MASK(flag)
@ GP_FRAME_SELECT
@ GP_SPOINT_SELECT
@ GP_MATERIAL_FILL_SHOW
Object is a sort of wrapper for general info.
@ GP_SCULPT_SETT_FLAG_FRAME_FALLOFF
#define CFRA
@ GP_LOCKAXIS_X
@ GP_LOCKAXIS_Y
@ GP_LOCKAXIS_Z
@ GP_LOCKAXIS_CURSOR
eGP_Sculpt_SelectMaskFlag
@ SPACE_VIEW3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
#define IS_AUTOKEY_ON(scene)
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
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:193
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
void ED_view3d_win_to_delta(const struct ARegion *region, const float mval[2], float out[3], const float zfac)
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip)
_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 GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group RGB to Bright Vector Camera CLAMP
Platform independent time functions.
#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 UI_MAX_DRAW_STR
Definition: UI_interface.h:90
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#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
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Scene scene
const Depsgraph * depsgraph
#define str(s)
ListBase gpencil_strokes_copypastebuf
GHash * gpencil_copybuf_validate_colormap(bContext *C)
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)
void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc, const short flag, const float pt[3], float xy[2])
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)
static int gpencil_sculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_brush_clone_add(bContext *C, tGP_BrushEditData *gso)
static bool gpencil_sculpt_brush_poll(bContext *C)
static GP_Sculpt_Settings * gpencil_sculpt_get_settings(Scene *scene)
struct tGPSB_Grab_StrokeData tGPSB_Grab_StrokeData
static void gpencil_sculpt_brush_header_set(bContext *C, tGP_BrushEditData *gso)
static bool gpencil_brush_invert_check(tGP_BrushEditData *gso)
static void gpencil_sculpt_compute_lock_axis(tGP_BrushEditData *gso, bGPDspoint *pt, const float save_pt[3])
static Brush * gpencil_sculpt_get_smooth_brush(tGP_BrushEditData *gso)
static bool gpencil_brush_thickness_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static bool gpencil_brush_twist_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static void gpencil_sculpt_brush_exit(bContext *C, wmOperator *op)
static void gpencil_sculpt_brush_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
static void gpencil_brush_clone_init(bContext *C, tGP_BrushEditData *gso)
static bool gpencil_brush_strength_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static void gpencil_brush_clone_adjust(tGP_BrushEditData *gso)
static int gpencil_sculpt_brush_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static bool gpencil_sculpt_brush_apply_clone(bContext *C, tGP_BrushEditData *gso)
static void gpencil_brush_grab_calc_dvec(tGP_BrushEditData *gso)
static bool gpencil_brush_grab_store_points(tGP_BrushEditData *gso, bGPDstroke *gps, float rot_eval, int pt_index, const int radius, const int co[2])
static void gpencil_update_geometry(bGPdata *gpd)
static void gpencil_brush_grab_apply_cached(tGP_BrushEditData *gso, bGPDstroke *gps, const float diff_mat[4][4])
static float gpencil_brush_influence_calc(tGP_BrushEditData *gso, const int radius, const int co[2])
static bool gpencil_sculpt_brush_do_frame(bContext *C, tGP_BrushEditData *gso, bGPDlayer *gpl, bGPDframe *gpf, const float diff_mat[4][4])
static bool gpencil_sculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso)
static void gpencil_brush_clone_free(tGP_BrushEditData *gso)
static void gpencil_brush_grab_stroke_init(tGP_BrushEditData *gso, bGPDstroke *gps)
static void gpencil_brush_calc_midpoint(tGP_BrushEditData *gso)
bool(* GP_BrushApplyCb)(tGP_BrushEditData *gso, bGPDstroke *gps, float rotation, int pt_index, const int radius, const int co[2])
static int gpencil_sculpt_brush_exec(bContext *C, wmOperator *op)
static bool gpencil_brush_randomize_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static bool gpencil_brush_pinch_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static bool gpencil_brush_push_apply(tGP_BrushEditData *gso, bGPDstroke *gps, float UNUSED(rot_eval), int pt_index, const int radius, const int co[2])
static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, bGPDstroke *gps, const float diff_mat[4][4], GP_BrushApplyCb apply)
struct tGPSB_CloneBrushData tGPSB_CloneBrushData
static void gpencil_sculpt_brush_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
static void gpencil_sculpt_brush_init_stroke(bContext *C, tGP_BrushEditData *gso)
struct tGP_BrushEditData tGP_BrushEditData
static void gpencil_brush_grab_stroke_free(void *ptr)
static bool gpencil_sculpt_brush_init(bContext *C, wmOperator *op)
static void gpencil_recalc_geometry_tag(bGPDstroke *gps)
static float gpencil_sculpt_rotation_eval_get(tGP_BrushEditData *gso, bGPDstroke *gps_eval, bGPDspoint *pt_eval, int idx_eval)
void GPENCIL_OT_sculpt_paint(wmOperatorType *ot)
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)
#define UINT_MAX
Definition: hash_md5.c:58
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:311
static void area(int d1, int d2, int e1, int e2, float weights[2])
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
void * regiondata
float alpha
struct CurveMapping * curve
struct BrushGpencilSettings * gpencil_settings
char gpencil_sculpt_tool
struct CurveMapping * cur_falloff
struct ARegion * region
struct View2D * v2d
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase brushes
Definition: BKE_main.h:171
ListBase defbase
float loc[3]
float imat[4][4]
unsigned short actdef
float obmat[4][4]
void * data
struct Brush * brush
Definition: rand.cc:48
float persinv[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
GpSculptPaint * gp_sculptpaint
char gpencil_selectmode_sculpt
struct GP_Sculpt_Settings gp_sculpt
float rotation_euler[3]
ListBase strokes
bGPDframe * actframe
struct bGPDspoint * pt_orig
bGPDspoint_Runtime runtime
struct bGPDstroke * gps_orig
struct bGPDstroke * prev
bGPDspoint * points
bGPDstroke_Runtime runtime
struct bGPDstroke * next
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
GP_Sculpt_Settings * settings
eGP_Sculpt_SelectMaskFlag mask
GP_SpaceConversion gsc
short shift
Definition: WM_types.h:618
short ctrl
Definition: WM_types.h:618
short type
Definition: WM_types.h:577
void * customdata
Definition: WM_types.h:631
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
long int PIL_check_seconds_timer_i(void)
Definition: time.c:90
ccl_device_inline float distance(const float2 &a, const float2 &b)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_PAD8
@ EVT_PAD2
@ RIGHTMOUSE
@ TIMER
@ 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
PointerRNA * ptr
Definition: wm_files.c:3157
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1669
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632