Blender  V3.3
annotate_paint.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008-2018 Blender Foundation. */
3 
8 #include <math.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLI_blenlib.h"
17 #include "BLI_math.h"
18 #include "BLI_math_geom.h"
19 #include "BLI_utildefines.h"
20 
21 #include "BLT_translation.h"
22 
23 #include "PIL_time.h"
24 
25 #include "BKE_callbacks.h"
26 #include "BKE_colortools.h"
27 #include "BKE_context.h"
28 #include "BKE_global.h"
29 #include "BKE_gpencil.h"
30 #include "BKE_gpencil_geom.h"
31 #include "BKE_layer.h"
32 #include "BKE_main.h"
33 #include "BKE_report.h"
34 #include "BKE_screen.h"
35 #include "BKE_tracking.h"
36 
37 #include "DNA_gpencil_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
41 
42 #include "UI_view2d.h"
43 
44 #include "ED_clip.h"
45 #include "ED_gpencil.h"
46 #include "ED_screen.h"
47 #include "ED_view3d.h"
48 
49 #include "GPU_immediate.h"
50 #include "GPU_immediate_util.h"
51 #include "GPU_state.h"
52 
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55 #include "RNA_prototypes.h"
56 
57 #include "WM_api.h"
58 #include "WM_types.h"
59 
60 #include "DEG_depsgraph.h"
61 
62 #include "gpencil_intern.h"
63 
64 /* ******************************************* */
65 /* 'Globals' and Defines */
66 
67 #define DEPTH_INVALID 1.0f
68 
69 /* values for tGPsdata->status */
70 typedef enum eGPencil_PaintStatus {
71  GP_STATUS_IDLING = 0, /* stroke isn't in progress yet */
72  GP_STATUS_PAINTING, /* a stroke is in progress */
73  GP_STATUS_ERROR, /* something wasn't correctly set up */
74  GP_STATUS_DONE, /* painting done */
75  GP_STATUS_CAPTURE /* capture event, but cancel */
77 
78 /* Return flags for adding points to stroke buffer */
79 typedef enum eGP_StrokeAdd_Result {
80  GP_STROKEADD_INVALID = -2, /* error occurred - insufficient info to do so */
81  GP_STROKEADD_OVERFLOW = -1, /* error occurred - cannot fit any more points */
82  GP_STROKEADD_NORMAL, /* point was successfully added */
83  GP_STROKEADD_FULL, /* cannot add any more points to buffer */
85 
86 /* Runtime flags */
87 typedef enum eGPencil_PaintFlags {
88  GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */
92  /* Flags used to indicate if stabilization is being used. */
96 
97 /* Temporary 'Stroke' Operation data
98  * "p" = op->customdata
99  */
100 typedef struct tGPsdata {
105 
119 
122 
131 
133  char *align_flag;
134 
141 
143  short radius;
144 
145  /* Stabilizer. */
149 
151  float mval[2];
153  float mvalo[2];
154 
156  float pressure;
158  float opressure;
159 
160  /* These need to be doubles, as (at least under unix) they are in seconds since epoch,
161  * float (and its 7 digits precision) is definitively not enough here!
162  * double, with its 15 digits precision,
163  * ensures us millisecond precision for a few centuries at least.
164  */
166  double inittime;
168  double curtime;
170  double ocurtime;
171 
174  float imat[4][4];
175  float mat[4][4];
176 
178  float custom_color[4];
179 
182 
184  short straight[2];
185 
187  short keymodifier;
189 
190 /* ------ */
191 
192 /* Macros for accessing sensitivity thresholds... */
193 /* minimum number of pixels mouse should move before new point created */
194 #define MIN_MANHATTAN_PX (U.gp_manhattandist)
195 /* minimum length of new segment before new point can be added */
196 #define MIN_EUCLIDEAN_PX (U.gp_euclideandist)
197 
199 {
200  return (p->gpf && p->gpf->strokes.last && p->flags & GP_PAINTFLAG_STROKEADDED);
201 }
202 
204 {
205  BLI_assert(p->gpf->strokes.last != NULL);
207 }
208 
209 /* ------ */
210 /* Forward defines for some functions... */
211 
213 
214 /* ******************************************* */
215 /* Context Wrangling... */
216 
217 /* check if context is suitable for drawing */
219 {
221  /* check if current context can support GPencil data */
223  /* check if Grease Pencil isn't already running */
224  if (ED_gpencil_session_active() == 0) {
225  return true;
226  }
227  CTX_wm_operator_poll_msg_set(C, "Annotation operator is already active");
228  }
229  else {
230  CTX_wm_operator_poll_msg_set(C, "Failed to find Annotation data to draw into");
231  }
232  }
233  else {
234  CTX_wm_operator_poll_msg_set(C, "Active region not set");
235  }
236 
237  return false;
238 }
239 
240 /* check if projecting strokes into 3d-geometry in the 3D-View */
242 {
243  bGPdata *gpd = p->gpd;
244  return ((gpd->runtime.sbuffer_sflag & GP_STROKE_3DSPACE) &&
246 }
247 
248 /* ******************************************* */
249 /* Calculations/Conversions */
250 
251 /* Utilities --------------------------------- */
252 
253 /* get the reference point for stroke-point conversions */
254 static void annotation_get_3d_reference(tGPsdata *p, float vec[3])
255 {
256  const float *fp = p->scene->cursor.location;
257 
258  /* use 3D-cursor */
259  copy_v3_v3(vec, fp);
260 }
261 
262 /* Stroke Editing ---------------------------- */
263 
264 /* check if the current mouse position is suitable for adding a new point */
265 static bool annotation_stroke_filtermval(tGPsdata *p, const float mval[2], const float pmval[2])
266 {
267  int dx = (int)fabsf(mval[0] - pmval[0]);
268  int dy = (int)fabsf(mval[1] - pmval[1]);
269 
270  /* if buffer is empty, just let this go through (i.e. so that dots will work) */
271  if (p->gpd->runtime.sbuffer_used == 0) {
272  return true;
273  }
274 
275  /* check if mouse moved at least certain distance on both axes (best case)
276  * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand
277  */
278 
279  /* If lazy mouse, check minimum distance. */
281  if ((dx * dx + dy * dy) > (p->stabilizer_radius * p->stabilizer_radius)) {
282  return true;
283  }
284 
285  /* If the mouse is moving within the radius of the last move,
286  * don't update the mouse position. This allows sharp turns. */
287  copy_v2_v2(p->mval, p->mvalo);
288  return false;
289  }
290 
291  if ((dx > MIN_MANHATTAN_PX) && (dy > MIN_MANHATTAN_PX)) {
292  return true;
293  }
294 
295  /* Check if the distance since the last point is significant enough:
296  * - Prevents points being added too densely
297  * - Distance here doesn't use sqrt to prevent slowness.
298  * We should still be safe from overflows though.
299  */
300  if ((dx * dx + dy * dy) > MIN_EUCLIDEAN_PX * MIN_EUCLIDEAN_PX) {
301  return true;
302  }
303 
304  /* mouse 'didn't move' */
305  return false;
306 }
307 
308 /* convert screen-coordinates to buffer-coordinates */
310  const float mval[2],
311  float out[3],
312  float *depth)
313 {
314  bGPdata *gpd = p->gpd;
315  if (depth && (*depth == DEPTH_INVALID)) {
316  depth = NULL;
317  }
318 
319  /* in 3d-space - pt->x/y/z are 3 side-by-side floats */
321  int mval_i[2];
322  round_v2i_v2fl(mval_i, mval);
323  if (annotation_project_check(p) &&
324  (ED_view3d_autodist_simple(p->region, mval_i, out, 0, depth))) {
325  /* projecting onto 3D-Geometry
326  * - nothing more needs to be done here, since view_autodist_simple() has already done it
327  */
328  }
329  else {
330  float mval_prj[2];
331  float rvec[3];
332 
333  /* Current method just converts each point in screen-coordinates to
334  * 3D-coordinates using the 3D-cursor as reference. In general, this
335  * works OK, but it could of course be improved.
336  *
337  * TODO:
338  * - investigate using nearest point(s) on a previous stroke as
339  * reference point instead or as offset, for easier stroke matching
340  */
341 
343  const float zfac = ED_view3d_calc_zfac(p->region->regiondata, rvec);
344 
345  if (ED_view3d_project_float_global(p->region, rvec, mval_prj, V3D_PROJ_TEST_NOP) ==
346  V3D_PROJ_RET_OK) {
347  float dvec[3];
348  float xy_delta[2];
349  sub_v2_v2v2(xy_delta, mval_prj, mval);
350  ED_view3d_win_to_delta(p->region, xy_delta, zfac, dvec);
351  sub_v3_v3v3(out, rvec, dvec);
352  }
353  else {
354  zero_v3(out);
355  }
356  }
357  }
358 
359  /* 2d - on 'canvas' (assume that p->v2d is set) */
360  else if ((gpd->runtime.sbuffer_sflag & GP_STROKE_2DSPACE) && (p->v2d)) {
361  UI_view2d_region_to_view(p->v2d, mval[0], mval[1], &out[0], &out[1]);
362  mul_v3_m4v3(out, p->imat, out);
363  }
364 
365  /* 2d - relative to screen (viewport area) */
366  else {
367  if (p->subrect == NULL) { /* normal 3D view */
368  out[0] = (float)(mval[0]) / (float)(p->region->winx) * 100;
369  out[1] = (float)(mval[1]) / (float)(p->region->winy) * 100;
370  }
371  else { /* camera view, use subrect */
372  out[0] = ((mval[0] - p->subrect->xmin) / BLI_rctf_size_x(p->subrect)) * 100;
373  out[1] = ((mval[1] - p->subrect->ymin) / BLI_rctf_size_y(p->subrect)) * 100;
374  }
375  }
376 }
377 
388 static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
389 {
390  bGPdata *gpd = p->gpd;
391  short num_points = gpd->runtime.sbuffer_used;
392 
393  /* Do nothing if not enough points to smooth out */
394  if ((num_points < 3) || (idx < 3) || (inf == 0.0f)) {
395  return;
396  }
397 
398  tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer;
399  float steps = 4.0f;
400  if (idx < 4) {
401  steps--;
402  }
403 
404  tGPspoint *pta = idx >= 4 ? &points[idx - 4] : NULL;
405  tGPspoint *ptb = idx >= 3 ? &points[idx - 3] : NULL;
406  tGPspoint *ptc = idx >= 2 ? &points[idx - 2] : NULL;
407  tGPspoint *ptd = &points[idx - 1];
408 
409  float sco[2] = {0.0f};
410  float a[2], b[2], c[2], d[2];
411  const float average_fac = 1.0f / steps;
412 
413  /* Compute smoothed coordinate by taking the ones nearby */
414  if (pta) {
415  copy_v2_v2(a, pta->m_xy);
416  madd_v2_v2fl(sco, a, average_fac);
417  }
418  if (ptb) {
419  copy_v2_v2(b, ptb->m_xy);
420  madd_v2_v2fl(sco, b, average_fac);
421  }
422  if (ptc) {
423  copy_v2_v2(c, ptc->m_xy);
424  madd_v2_v2fl(sco, c, average_fac);
425  }
426  if (ptd) {
427  copy_v2_v2(d, ptd->m_xy);
428  madd_v2_v2fl(sco, d, average_fac);
429  }
430 
431  /* Based on influence factor, blend between original and optimal smoothed coordinate */
432  interp_v2_v2v2(c, c, sco, inf);
433  copy_v2_v2(ptc->m_xy, c);
434 }
435 
436 static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8],
437  const float ref_point[2],
438  const float dir_cw[2],
439  const float dir_ccw[2],
440  const float length,
441  const float sign)
442 {
443  stroke_points[0] = ref_point[0] + dir_cw[0] * length * sign;
444  stroke_points[1] = ref_point[1] + dir_cw[1] * length * sign;
445  stroke_points[2] = ref_point[0] + dir_ccw[0] * length * sign;
446  stroke_points[3] = ref_point[1] + dir_ccw[1] * length * sign;
447 }
448 
450  const float stroke_dir[2],
451  float corner[2],
452  float stroke_points[8],
453  const int arrow_style)
454 {
455  const int arrow_length = 8;
456  float norm_dir[2];
457  copy_v2_v2(norm_dir, stroke_dir);
458  normalize_v2(norm_dir);
459  const float inv_norm_dir_clockwise[2] = {norm_dir[1], -norm_dir[0]};
460  const float inv_norm_dir_counterclockwise[2] = {-norm_dir[1], norm_dir[0]};
461 
462  switch (arrow_style) {
464  mul_v2_fl(norm_dir, arrow_length);
465  stroke_points[0] = corner[0] + inv_norm_dir_clockwise[0] * arrow_length + norm_dir[0];
466  stroke_points[1] = corner[1] + inv_norm_dir_clockwise[1] * arrow_length + norm_dir[1];
467  stroke_points[2] = corner[0] + inv_norm_dir_counterclockwise[0] * arrow_length + norm_dir[0];
468  stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_length + norm_dir[1];
469  break;
472  corner,
473  inv_norm_dir_clockwise,
474  inv_norm_dir_counterclockwise,
475  arrow_length,
476  1.0f);
477  break;
479  mul_v2_fl(norm_dir, arrow_length);
480  if (point != NULL) {
481  add_v2_v2(point->m_xy, norm_dir);
482  copy_v2_v2(corner, point->m_xy);
483  }
485  corner,
486  inv_norm_dir_clockwise,
487  inv_norm_dir_counterclockwise,
488  arrow_length,
489  -1.0f);
490  stroke_points[4] = corner[0] - norm_dir[0];
491  stroke_points[5] = corner[1] - norm_dir[1];
492  break;
494  mul_v2_fl(norm_dir, arrow_length * 1.5f);
495  if (point != NULL) {
496  add_v2_v2(point->m_xy, norm_dir);
497  copy_v2_v2(corner, point->m_xy);
498  }
500  corner,
501  inv_norm_dir_clockwise,
502  inv_norm_dir_counterclockwise,
503  arrow_length * 0.75f,
504  -1.0f);
505  stroke_points[4] = stroke_points[0] - norm_dir[0];
506  stroke_points[5] = stroke_points[1] - norm_dir[1];
507  stroke_points[6] = stroke_points[2] - norm_dir[0];
508  stroke_points[7] = stroke_points[3] - norm_dir[1];
509  break;
510  default:
511  break;
512  }
513 }
514 
515 /* add current stroke-point to buffer (returns whether point was successfully added) */
517  const float mval[2],
518  float pressure,
519  double curtime)
520 {
521  bGPdata *gpd = p->gpd;
522  tGPspoint *pt;
523  ToolSettings *ts = p->scene->toolsettings;
524 
525  /* check painting mode */
527  /* straight lines only - i.e. only store start and end point in buffer */
528  if (gpd->runtime.sbuffer_used == 0) {
529  /* first point in buffer (start point) */
530  pt = (tGPspoint *)(gpd->runtime.sbuffer);
531 
532  /* store settings */
533  copy_v2_v2(pt->m_xy, mval);
534  /* T44932 - Pressure vals are unreliable, so ignore for now */
535  pt->pressure = 1.0f;
536  pt->strength = 1.0f;
537  pt->time = (float)(curtime - p->inittime);
538 
539  /* increment buffer size */
540  gpd->runtime.sbuffer_used++;
541  }
542  else {
543  /* just reset the endpoint to the latest value
544  * - assume that pointers for this are always valid...
545  */
546  pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1);
547 
548  /* store settings */
549  copy_v2_v2(pt->m_xy, mval);
550  /* T44932 - Pressure vals are unreliable, so ignore for now */
551  pt->pressure = 1.0f;
552  pt->strength = 1.0f;
553  pt->time = (float)(curtime - p->inittime);
554 
555  /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */
556  gpd->runtime.sbuffer_used = 2;
557 
558  /* Arrows. */
560  /* Store start and end point coords for arrows. */
561  float end[2];
562  copy_v2_v2(end, pt->m_xy);
563  pt = ((tGPspoint *)(gpd->runtime.sbuffer));
564  float start[2];
565  copy_v2_v2(start, pt->m_xy);
566 
567  /* Arrow end corner. */
569  pt++;
570  const float e_heading[2] = {start[0] - end[0], start[1] - end[1]};
571  /* Calculate points for ending arrow. */
573  pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style);
574  }
575  /* Arrow start corner. */
577  const float s_heading[2] = {end[0] - start[0], end[1] - start[1]};
578  /* Calculate points for starting arrow. */
580  NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style);
581  }
582  }
583  }
584 
585  /* can keep carrying on this way :) */
586  return GP_STROKEADD_NORMAL;
587  }
588 
589  if (p->paintmode == GP_PAINTMODE_DRAW) { /* normal drawing */
590  /* check if still room in buffer or add more */
592  gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
593 
594  /* get pointer to destination point */
595  pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
596 
597  /* store settings */
598  copy_v2_v2(pt->m_xy, mval);
599  pt->pressure = pressure;
600  /* Unused for annotations, but initialize for easier conversions to GP Object. */
601  pt->strength = 1.0f;
602 
603  /* point time */
604  pt->time = (float)(curtime - p->inittime);
605 
606  /* increment counters */
607  gpd->runtime.sbuffer_used++;
608 
609  /* Don't smooth if stabilizer is on. */
610  if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
611  /* smooth while drawing previous points with a reduction factor for previous */
612  for (int s = 0; s < 3; s++) {
613  annotation_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s);
614  }
615  }
616 
617  return GP_STROKEADD_NORMAL;
618  }
619 
620  if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
621  /* get pointer to destination point */
622  pt = (tGPspoint *)gpd->runtime.sbuffer;
623 
624  /* store settings */
625  copy_v2_v2(pt->m_xy, mval);
626  /* T44932 - Pressure vals are unreliable, so ignore for now */
627  pt->pressure = 1.0f;
628  pt->strength = 1.0f;
629  pt->time = (float)(curtime - p->inittime);
630 
631  /* if there's stroke for this poly line session add (or replace last) point
632  * to stroke. This allows to draw lines more interactively (see new segment
633  * during mouse slide, e.g.)
634  */
636  bGPDstroke *gps = p->gpf->strokes.last;
637  bGPDspoint *pts;
638 
639  /* first time point is adding to temporary buffer -- need to allocate new point in stroke */
640  if (gpd->runtime.sbuffer_used == 0) {
641  gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
642  gps->totpoints++;
643  }
644 
645  pts = &gps->points[gps->totpoints - 1];
646 
647  /* special case for poly lines: normally,
648  * depth is needed only when creating new stroke from buffer,
649  * but poly lines are converting to stroke instantly,
650  * so initialize depth buffer before converting coordinates
651  */
652  if (annotation_project_check(p)) {
653  View3D *v3d = p->area->spacedata.first;
654 
657  p->region,
658  v3d,
659  NULL,
663  NULL);
664  }
665 
666  /* convert screen-coordinates to appropriate coordinates (and store them) */
667  annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL);
668 
669  /* copy pressure and time */
670  pts->pressure = pt->pressure;
671  pts->strength = pt->strength;
672  pts->time = pt->time;
673  gps->tot_triangles = 0;
674  }
675 
676  /* increment counters */
677  if (gpd->runtime.sbuffer_used == 0) {
678  gpd->runtime.sbuffer_used++;
679  }
680 
681  return GP_STROKEADD_NORMAL;
682  }
683 
684  /* return invalid state for now... */
685  return GP_STROKEADD_INVALID;
686 }
687 
689 {
690  pt->pressure = 1.0f;
691  pt->strength = 1.0f;
692  pt->time = 1.0f;
693 }
694 
696 {
697  copy_v3_v3(&pt->x, point);
699 }
700 
702  tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx)
703 {
704  /* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */
705  const float real_co[2] = {co[co_idx], co[co_idx + 1]};
706  copy_v2_v2(ptc->m_xy, real_co);
707  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
709 }
710 
711 static void annotation_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints)
712 {
713  /* Copy appropriate settings for stroke. */
714  gps->totpoints = totpoints;
715  /* Allocate enough memory for a continuous array for storage points. */
716  gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "annotation_stroke_points");
717 }
718 
720  tGPspoint *ptc,
721  bGPDspoint *pt,
722  const float corner_point[3],
723  const float arrow_points[8])
724 {
725  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
726  pt++;
727  annotation_stroke_arrow_init_conv_point(pt, corner_point);
728  pt++;
729  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
730 }
731 
733  tGPspoint *ptc,
734  bGPDspoint *pt,
735  const float arrow_points[8])
736 {
737  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
738  pt++;
739  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
740 }
741 
743  tGPspoint *ptc,
744  bGPDspoint *pt,
745  const float arrow_points[8])
746 {
747  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
748  pt++;
749  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
750  pt++;
751  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
752  pt++;
753  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
754 }
755 
757  tGPspoint *ptc,
758  bGPDspoint *pt,
759  const float corner_point[3],
760  const float arrow_points[8])
761 {
762  annotation_stroke_arrow_init_conv_point(pt, corner_point);
763  pt++;
764  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0);
765  pt++;
766  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4);
767  pt++;
768  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6);
769  pt++;
770  annotation_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2);
771  pt++;
772  annotation_stroke_arrow_init_conv_point(pt, corner_point);
773 }
774 
776  tGPspoint *ptc,
777  bGPDspoint *pt,
778  bGPDstroke *arrow_stroke,
779  const float arrow_points[8],
780  const int style)
781 {
782  float corner_conv[3];
783  copy_v3_v3(corner_conv, &pt->x);
784 
785  switch (style) {
787  annotation_arrow_create_segm(p, ptc, pt, arrow_points);
788  break;
790  annotation_arrow_create_closed(p, ptc, pt, arrow_points);
791  break;
793  annotation_arrow_create_open(p, ptc, pt, corner_conv, arrow_points);
794  break;
796  annotation_arrow_create_square(p, ptc, pt, corner_conv, arrow_points);
797  break;
798  default:
799  break;
800  }
801  /* Link stroke to frame. */
802  BLI_addtail(&p->gpf->strokes, arrow_stroke);
803 }
804 
805 /* make a new stroke from the buffer data */
807 {
808  bGPdata *gpd = p->gpd;
809  bGPDlayer *gpl = p->gpl;
810  bGPDstroke *gps;
811  bGPDspoint *pt;
812  tGPspoint *ptc;
813  ToolSettings *ts = p->scene->toolsettings;
814 
815  int i, totelem;
816  /* Since strokes are so fine, when using their depth we need a margin
817  * otherwise they might get missed. */
818  int depth_margin = (ts->annotate_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0;
819 
820  /* get total number of points to allocate space for
821  * - drawing straight-lines only requires the endpoints
822  */
824  totelem = (gpd->runtime.sbuffer_used >= 2) ? 2 : gpd->runtime.sbuffer_used;
825  }
826  else {
827  totelem = gpd->runtime.sbuffer_used;
828  }
829 
830  /* exit with error if no valid points from this stroke */
831  if (totelem == 0) {
832  return;
833  }
834 
835  /* special case for poly line -- for already added stroke during session
836  * coordinates are getting added to stroke immediately to allow more
837  * interactive behavior
838  */
839  if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
841  return;
842  }
843  }
844 
845  /* allocate memory for a new stroke */
846  gps = MEM_callocN(sizeof(bGPDstroke), "annotation_stroke");
847 
848  /* copy appropriate settings for stroke */
849  gps->totpoints = totelem;
850  gps->thickness = gpl->thickness;
851  gps->fill_opacity_fac = 1.0f;
852  gps->hardeness = 1.0f;
853  copy_v2_fl(gps->aspect_ratio, 1.0f);
854  gps->uv_scale = 1.0f;
855  gps->flag = gpd->runtime.sbuffer_sflag;
856  gps->inittime = p->inittime;
857  gps->tot_triangles = 0;
858 
859  /* allocate enough memory for a continuous array for storage points */
860  gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "annotation_stroke_points");
861  gps->tot_triangles = 0;
862 
863  /* set pointer to first non-initialized point */
864  pt = gps->points + (gps->totpoints - totelem);
865 
866  /* copy points from the buffer to the stroke */
868  /* straight lines only -> only endpoints */
869  {
870  /* first point */
871  ptc = gpd->runtime.sbuffer;
872 
873  /* convert screen-coordinates to appropriate coordinates (and store them) */
874  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
875 
876  /* copy pressure and time */
877  pt->pressure = ptc->pressure;
878  pt->strength = ptc->strength;
879  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
880  pt->time = ptc->time;
881 
882  pt++;
883  }
884 
885  if (totelem == 2) {
886  bGPdata_Runtime runtime = gpd->runtime;
887 
888  /* Last point if applicable. */
889  ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
890 
891  /* Convert screen-coordinates to appropriate coordinates (and store them). */
892  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
893 
894  /* Copy pressure and time. */
895  pt->pressure = ptc->pressure;
896  pt->strength = ptc->strength;
897  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
898  pt->time = ptc->time;
899 
901  /* End arrow stroke. */
902  if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) &&
904  int totarrowpoints = runtime.arrow_end_style;
905 
906  /* Setting up arrow stroke. */
907  bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false, false);
908  annotation_stroke_arrow_allocate(e_arrow_gps, totarrowpoints);
909 
910  /* Set pointer to first non-initialized point. */
911  pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints);
912 
913  /* End point. */
914  ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1);
915  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
917 
918  /* Fill and convert arrow points to create arrow shape. */
920  p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style);
921  }
922  /* Start arrow stroke. */
923  if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) &&
925  int totarrowpoints = runtime.arrow_start_style;
926 
927  /* Setting up arrow stroke. */
928  bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false, false);
929  annotation_stroke_arrow_allocate(s_arrow_gps, totarrowpoints);
930 
931  /* Set pointer to first non-initialized point. */
932  pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints);
933 
934  /* Start point. */
935  ptc = runtime.sbuffer;
936  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
938 
939  /* Fill and convert arrow points to create arrow shape. */
941  p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style);
942  }
943  }
944  }
945  else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) {
946  /* first point */
947  ptc = gpd->runtime.sbuffer;
948 
949  /* convert screen-coordinates to appropriate coordinates (and store them) */
950  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL);
951 
952  /* copy pressure and time */
953  pt->pressure = ptc->pressure;
954  pt->strength = ptc->strength;
955  pt->time = ptc->time;
956  }
957  else {
958  float *depth_arr = NULL;
959 
960  /* get an array of depths, far depths are blended */
961  if (annotation_project_check(p)) {
962  int mval_i[2], mval_prev[2] = {0};
963  int interp_depth = 0;
964  int found_depth = 0;
965 
966  depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points");
967 
968  const ViewDepths *depths = p->depths;
969  for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) {
970  round_v2i_v2fl(mval_i, ptc->m_xy);
971 
972  if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) &&
974  depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) {
975  interp_depth = true;
976  }
977  else {
978  found_depth = true;
979  }
980 
981  copy_v2_v2_int(mval_prev, mval_i);
982  }
983 
984  if (found_depth == false) {
985  /* Unfortunately there is not much we can do when the depth isn't found,
986  * ignore depth in this case, use the 3D cursor. */
987  for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
988  depth_arr[i] = 0.9999f;
989  }
990  }
991  else {
993  /* remove all info between the valid endpoints */
994  int first_valid = 0;
995  int last_valid = 0;
996 
997  for (i = 0; i < gpd->runtime.sbuffer_used; i++) {
998  if (depth_arr[i] != DEPTH_INVALID) {
999  break;
1000  }
1001  }
1002  first_valid = i;
1003 
1004  for (i = gpd->runtime.sbuffer_used - 1; i >= 0; i--) {
1005  if (depth_arr[i] != DEPTH_INVALID) {
1006  break;
1007  }
1008  }
1009  last_valid = i;
1010 
1011  /* invalidate non-endpoints, so only blend between first and last */
1012  for (i = first_valid + 1; i < last_valid; i++) {
1013  depth_arr[i] = DEPTH_INVALID;
1014  }
1015 
1016  interp_depth = true;
1017  }
1018 
1019  if (interp_depth) {
1021  }
1022  }
1023  }
1024 
1025  pt = gps->points;
1026 
1027  /* convert all points (normal behavior) */
1028  for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc;
1029  i++, ptc++, pt++) {
1030  /* convert screen-coordinates to appropriate coordinates (and store them) */
1031  annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL);
1032 
1033  /* copy pressure and time */
1034  pt->pressure = ptc->pressure;
1035  pt->strength = ptc->strength;
1036  CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
1037  pt->time = ptc->time;
1038  }
1039 
1040  if (depth_arr) {
1041  MEM_freeN(depth_arr);
1042  }
1043  }
1044 
1045  /* add stroke to frame */
1046  BLI_addtail(&p->gpf->strokes, gps);
1048 }
1049 
1050 /* --- 'Eraser' for 'Paint' Tool ------ */
1051 
1052 /* helper to free a stroke
1053  * NOTE: gps->dvert and gps->triangles should be NULL, but check anyway for good measure
1054  */
1056 {
1057  if (gps->points) {
1058  MEM_freeN(gps->points);
1059  }
1060 
1061  if (gps->dvert) {
1063  MEM_freeN(gps->dvert);
1064  }
1065 
1066  if (gps->triangles) {
1067  MEM_freeN(gps->triangles);
1068  }
1069 
1070  BLI_freelinkN(&gpf->strokes, gps);
1071 }
1072 
1073 /* only erase stroke points that are visible (3d view) */
1075  const bGPDspoint *pt,
1076  const int x,
1077  const int y)
1078 {
1080  RegionView3D *rv3d = p->region->regiondata;
1081  const int mval_i[2] = {x, y};
1082  float mval_3d[3];
1083 
1084  float p_depth;
1085  if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) {
1086  ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d);
1087 
1088  const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d);
1089  const float depth_pt = ED_view3d_calc_depth_for_comparison(rv3d, &pt->x);
1090 
1091  if (depth_pt > depth_mval) {
1092  return true;
1093  }
1094  }
1095  }
1096  return false;
1097 }
1098 
1099 /* Eraser tool - evaluation per stroke. */
1101  bGPDframe *gpf,
1102  bGPDstroke *gps,
1103  const float mval[2],
1104  const int radius,
1105  const rcti *rect)
1106 {
1107  bGPDspoint *pt1, *pt2;
1108  int pc1[2] = {0};
1109  int pc2[2] = {0};
1110  int mval_i[2];
1111  round_v2i_v2fl(mval_i, mval);
1112 
1113  if (gps->totpoints == 0) {
1114  /* just free stroke */
1115  annotation_free_stroke(gpf, gps);
1116  }
1117  else if (gps->totpoints == 1) {
1118  /* only process if it hasn't been masked out... */
1119  if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) {
1120  gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]);
1121 
1122  /* Do bound-box check first. */
1123  if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) {
1124  /* only check if point is inside */
1125  if (len_v2v2_int(mval_i, pc1) <= radius) {
1126  /* free stroke */
1127  annotation_free_stroke(gpf, gps);
1128  }
1129  }
1130  }
1131  }
1132  else {
1133  /* Perform culling? */
1134  bool do_cull = false;
1135 
1136  /* Clear Tags
1137  *
1138  * NOTE: It's better this way, as we are sure that
1139  * we don't miss anything, though things will be
1140  * slightly slower as a result
1141  */
1142  for (int i = 0; i < gps->totpoints; i++) {
1143  bGPDspoint *pt = &gps->points[i];
1144  pt->flag &= ~GP_SPOINT_TAG;
1145  }
1146 
1147  /* First Pass: Loop over the points in the stroke
1148  * 1) Thin out parts of the stroke under the brush
1149  * 2) Tag "too thin" parts for removal (in second pass)
1150  */
1151  for (int i = 0; (i + 1) < gps->totpoints; i++) {
1152  /* get points to work with */
1153  pt1 = gps->points + i;
1154  pt2 = gps->points + i + 1;
1155 
1156  /* only process if it hasn't been masked out... */
1157  if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) {
1158  continue;
1159  }
1160 
1161  gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]);
1162  gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]);
1163 
1164  /* Check that point segment of the bound-box of the eraser stroke. */
1165  if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) ||
1166  ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) {
1167  /* Check if point segment of stroke had anything to do with
1168  * eraser region (either within stroke painted, or on its lines)
1169  * - this assumes that line-width is irrelevant.
1170  */
1171  if (gpencil_stroke_inside_circle(mval, radius, pc1[0], pc1[1], pc2[0], pc2[1])) {
1172  if ((annotation_stroke_eraser_is_occluded(p, pt1, pc1[0], pc1[1]) == false) ||
1173  (annotation_stroke_eraser_is_occluded(p, pt2, pc2[0], pc2[1]) == false)) {
1174  /* Edge is affected - Check individual points now */
1175  if (len_v2v2_int(mval_i, pc1) <= radius) {
1176  pt1->flag |= GP_SPOINT_TAG;
1177  }
1178  if (len_v2v2_int(mval_i, pc2) <= radius) {
1179  pt2->flag |= GP_SPOINT_TAG;
1180  }
1181  do_cull = true;
1182  }
1183  }
1184  }
1185  }
1186 
1187  /* Second Pass: Remove any points that are tagged */
1188  if (do_cull) {
1190  p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0);
1191  }
1192  }
1193 }
1194 
1195 /* erase strokes which fall under the eraser strokes */
1197 {
1198  bGPDframe *gpf = p->gpf;
1199  bGPDstroke *gps, *gpn;
1200  rcti rect;
1201 
1202  /* rect is rectangle of eraser */
1203  rect.xmin = p->mval[0] - p->radius;
1204  rect.ymin = p->mval[1] - p->radius;
1205  rect.xmax = p->mval[0] + p->radius;
1206  rect.ymax = p->mval[1] + p->radius;
1207 
1208  if (p->area->spacetype == SPACE_VIEW3D) {
1210  View3D *v3d = p->area->spacedata.first;
1213  p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths);
1214  }
1215  }
1216 
1217  /* loop over strokes of active layer only (session init already took care of ensuring validity),
1218  * checking segments for intersections to remove
1219  */
1220  for (gps = gpf->strokes.first; gps; gps = gpn) {
1221  gpn = gps->next;
1222  /* Not all strokes in the datablock may be valid in the current editor/context
1223  * (e.g. 2D space strokes in the 3D view, if the same datablock is shared)
1224  */
1225  if (ED_gpencil_stroke_can_use_direct(p->area, gps)) {
1226  annotation_stroke_eraser_dostroke(p, gpf, gps, p->mval, p->radius, &rect);
1227  }
1228  }
1229 }
1230 
1231 /* ******************************************* */
1232 /* Sketching Operator */
1233 
1234 /* clear the session buffers (call this before AND after a paint operation) */
1236 {
1237  bGPdata *gpd = p->gpd;
1238 
1240  gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, true);
1241 
1242  /* reset flags */
1243  gpd->runtime.sbuffer_sflag = 0;
1244 
1245  /* reset inittime */
1246  p->inittime = 0.0;
1247 }
1248 
1249 /* (re)init new painting data */
1251 {
1252  Main *bmain = CTX_data_main(C);
1253  bGPdata **gpd_ptr = NULL;
1254  ScrArea *curarea = CTX_wm_area(C);
1255  ARegion *region = CTX_wm_region(C);
1257 
1258  /* make sure the active view (at the starting time) is a 3d-view */
1259  if (curarea == NULL) {
1260  p->status = GP_STATUS_ERROR;
1261  return 0;
1262  }
1263 
1264  /* pass on current scene and window */
1265  p->bmain = CTX_data_main(C);
1266  p->scene = CTX_data_scene(C);
1268  p->win = CTX_wm_window(C);
1269 
1270  unit_m4(p->imat);
1271  unit_m4(p->mat);
1272 
1273  switch (curarea->spacetype) {
1274  /* supported views first */
1275  case SPACE_VIEW3D: {
1276  /* View3D *v3d = curarea->spacedata.first; */
1277  /* RegionView3D *rv3d = region->regiondata; */
1278 
1279  /* set current area
1280  * - must verify that region data is 3D-view (and not something else)
1281  */
1282  /* CAUTION: If this is the "toolbar", then this will change on the first stroke */
1283  p->area = curarea;
1284  p->region = region;
1285  p->align_flag = &ts->annotate_v3d_align;
1286 
1287  if (region->regiondata == NULL) {
1288  p->status = GP_STATUS_ERROR;
1289  return 0;
1290  }
1291  break;
1292  }
1293  case SPACE_NODE: {
1294  /* SpaceNode *snode = curarea->spacedata.first; */
1295 
1296  /* set current area */
1297  p->area = curarea;
1298  p->region = region;
1299  p->v2d = &region->v2d;
1300  p->align_flag = &ts->gpencil_v2d_align;
1301  break;
1302  }
1303  case SPACE_SEQ: {
1304  SpaceSeq *sseq = curarea->spacedata.first;
1305 
1306  /* set current area */
1307  p->area = curarea;
1308  p->region = region;
1309  p->v2d = &region->v2d;
1310  p->align_flag = &ts->gpencil_v2d_align;
1311 
1312  /* check that gpencil data is allowed to be drawn */
1313  if (!((sseq->mainb == SEQ_DRAW_IMG_IMBUF) && (region->regiontype == RGN_TYPE_PREVIEW))) {
1314  p->status = GP_STATUS_ERROR;
1315  return 0;
1316  }
1317  break;
1318  }
1319  case SPACE_IMAGE: {
1320  /* SpaceImage *sima = curarea->spacedata.first; */
1321 
1322  /* set the current area */
1323  p->area = curarea;
1324  p->region = region;
1325  p->v2d = &region->v2d;
1326  p->align_flag = &ts->gpencil_v2d_align;
1327  break;
1328  }
1329  case SPACE_CLIP: {
1330  SpaceClip *sc = curarea->spacedata.first;
1331  MovieClip *clip = ED_space_clip_get_clip(sc);
1332 
1333  if (clip == NULL) {
1334  p->status = GP_STATUS_ERROR;
1335  return false;
1336  }
1337 
1338  /* set the current area */
1339  p->area = curarea;
1340  p->region = region;
1341  p->v2d = &region->v2d;
1342  p->align_flag = &ts->gpencil_v2d_align;
1343 
1344  invert_m4_m4(p->imat, sc->unistabmat);
1345 
1346  /* custom color for new layer */
1347  p->custom_color[0] = 1.0f;
1348  p->custom_color[1] = 0.0f;
1349  p->custom_color[2] = 0.5f;
1350  p->custom_color[3] = 0.9f;
1351 
1352  if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
1353  int framenr = ED_space_clip_get_clip_frame_number(sc);
1355  MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
1356 
1357  if (marker) {
1358  p->imat[3][0] -= marker->pos[0];
1359  p->imat[3][1] -= marker->pos[1];
1360  }
1361  else {
1362  p->status = GP_STATUS_ERROR;
1363  return false;
1364  }
1365  }
1366 
1367  invert_m4_m4(p->mat, p->imat);
1368  copy_m4_m4(p->gsc.mat, p->mat);
1369  break;
1370  }
1371  /* unsupported views */
1372  default: {
1373  p->status = GP_STATUS_ERROR;
1374  return 0;
1375  }
1376  }
1377 
1378  /* get gp-data */
1379  gpd_ptr = ED_annotation_data_get_pointers(C, &p->ownerPtr);
1380  if ((gpd_ptr == NULL) || !ED_gpencil_data_owner_is_annotation(&p->ownerPtr)) {
1381  p->status = GP_STATUS_ERROR;
1382  return 0;
1383  }
1384 
1385  /* if no existing GPencil block exists, add one */
1386  if (*gpd_ptr == NULL) {
1387  bGPdata *gpd = BKE_gpencil_data_addnew(bmain, "Annotations");
1388  *gpd_ptr = gpd;
1389 
1390  /* mark datablock as being used for annotations */
1391  gpd->flag |= GP_DATA_ANNOTATIONS;
1392  }
1393  p->gpd = *gpd_ptr;
1394 
1395  if (ED_gpencil_session_active() == 0) {
1396  /* initialize undo stack,
1397  * also, existing undo stack would make buffer drawn
1398  */
1399  gpencil_undo_init(p->gpd);
1400  }
1401 
1402  /* clear out buffer (stored in gp-data), in case something contaminated it */
1404 
1405  return 1;
1406 }
1407 
1408 /* Enable the annotations in the current space. */
1410 {
1411  ScrArea *area = p->area;
1412  switch (area->spacetype) {
1413  case SPACE_VIEW3D: {
1414  View3D *v3d = (View3D *)area->spacedata.first;
1415  v3d->flag2 |= V3D_SHOW_ANNOTATION;
1416  break;
1417  }
1418  case SPACE_SEQ: {
1419  SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
1420  sseq->flag |= SEQ_PREVIEW_SHOW_GPENCIL;
1421  break;
1422  }
1423  case SPACE_IMAGE: {
1424  SpaceImage *sima = (SpaceImage *)area->spacedata.first;
1425  sima->flag |= SI_SHOW_GPENCIL;
1426  break;
1427  }
1428  case SPACE_NODE: {
1429  SpaceNode *snode = (SpaceNode *)area->spacedata.first;
1430  snode->flag |= SNODE_SHOW_GPENCIL;
1431  break;
1432  }
1433  case SPACE_CLIP: {
1434  SpaceClip *sclip = (SpaceClip *)area->spacedata.first;
1435  sclip->flag |= SC_SHOW_ANNOTATION;
1436  break;
1437  }
1438  default:
1439  break;
1440  }
1441 }
1442 
1443 /* init new painting session */
1445 {
1446  tGPsdata *p = NULL;
1447 
1448  /* create new context data */
1449  p = MEM_callocN(sizeof(tGPsdata), "Annotation Drawing Data");
1450 
1451  /* Try to initialize context data
1452  * WARNING: This may not always succeed (e.g. using GP in an annotation-only context)
1453  */
1454  if (annotation_session_initdata(C, p) == 0) {
1455  /* Invalid state - Exit
1456  * NOTE: It should be safe to just free the data, since failing context checks should
1457  * only happen when no data has been allocated.
1458  */
1459  MEM_freeN(p);
1460  return NULL;
1461  }
1462 
1463  /* Radius for eraser circle is defined in user-preferences. */
1464  /* NOTE: we do this here, so that if we exit immediately,
1465  * erase size won't get lost
1466  */
1467  p->radius = U.gp_eraser;
1468 
1469  /* Annotations must be always visible when use it. */
1471 
1472  /* return context data for running paint operator */
1473  return p;
1474 }
1475 
1476 /* cleanup after a painting session */
1478 {
1479  bGPdata *gpd = (p) ? p->gpd : NULL;
1480 
1481  /* error checking */
1482  if (gpd == NULL) {
1483  return;
1484  }
1485 
1486  /* free stroke buffer */
1487  if (gpd->runtime.sbuffer) {
1488  MEM_freeN(gpd->runtime.sbuffer);
1489  gpd->runtime.sbuffer = NULL;
1490  }
1491 
1492  /* clear flags */
1493  gpd->runtime.sbuffer_used = 0;
1494  gpd->runtime.sbuffer_size = 0;
1495  gpd->runtime.sbuffer_sflag = 0;
1496  p->inittime = 0.0;
1497 }
1498 
1500 {
1501  if (p->depths) {
1503  }
1504  MEM_freeN(p);
1505 }
1506 
1507 /* init new stroke */
1509  eGPencil_PaintModes paintmode,
1511 {
1512  Scene *scene = p->scene;
1514 
1515  /* Call to the annotation pre handler to notify python the annotation starts. */
1517 
1518  /* get active layer (or add a new one if non-existent) */
1520  if (p->gpl == NULL) {
1521  /* tag for annotations */
1522  p->gpd->flag |= GP_DATA_ANNOTATIONS;
1523  p->gpl = BKE_gpencil_layer_addnew(p->gpd, DATA_("Note"), true, false);
1524 
1525  if (p->custom_color[3]) {
1526  copy_v3_v3(p->gpl->color, p->custom_color);
1527  }
1528  }
1529  if (p->gpl->flag & GP_LAYER_LOCKED) {
1530  p->status = GP_STATUS_ERROR;
1531  return;
1532  }
1533 
1534  /* get active frame (add a new one if not matching frame) */
1535  if (paintmode == GP_PAINTMODE_ERASER) {
1536  /* Eraser mode:
1537  * 1) Only allow erasing on the active layer (unlike for 3d-art Grease Pencil),
1538  * since we won't be exposing layer locking in the UI
1539  * 2) Ensure that p->gpf refers to the frame used for the active layer
1540  * (to avoid problems with other tools which expect it to exist)
1541  */
1542  bool has_layer_to_erase = false;
1543 
1545  /* Ensure that there's stuff to erase here (not including selection mask below)... */
1546  if (p->gpl->actframe && p->gpl->actframe->strokes.first) {
1547  has_layer_to_erase = true;
1548  }
1549  }
1550 
1551  /* Ensure active frame is set correctly... */
1552  p->gpf = p->gpl->actframe;
1553 
1554  if (has_layer_to_erase == false) {
1556  printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n");
1557  return;
1558  }
1559  }
1560  else {
1561  /* Drawing Modes - Add a new frame if needed on the active layer */
1562  short add_frame_mode = GP_GETFRAME_ADD_NEW;
1563 
1565  add_frame_mode = GP_GETFRAME_ADD_COPY;
1566  }
1567  else {
1568  add_frame_mode = GP_GETFRAME_ADD_NEW;
1569  }
1570 
1571  p->gpf = BKE_gpencil_layer_frame_get(p->gpl, scene->r.cfra, add_frame_mode);
1572 
1573  if (p->gpf == NULL) {
1574  p->status = GP_STATUS_ERROR;
1575  return;
1576  }
1577 
1578  p->gpf->flag |= GP_FRAME_PAINT;
1579  }
1580 
1581  /* set 'eraser' for this stroke if using eraser */
1582  p->paintmode = paintmode;
1583  if (p->paintmode == GP_PAINTMODE_ERASER) {
1585 
1586  /* check if we should respect depth while erasing */
1587  if (p->area->spacetype == SPACE_VIEW3D) {
1588  if (p->gpl->flag & GP_LAYER_NO_XRAY) {
1590  }
1591  }
1592  }
1593  else {
1594  /* disable eraser flags - so that we can switch modes during a session */
1596 
1597  if (p->area->spacetype == SPACE_VIEW3D) {
1598  if (p->gpl->flag & GP_LAYER_NO_XRAY) {
1600  }
1601  }
1602  }
1603 
1604  /* set 'initial run' flag, which is only used to denote when a new stroke is starting */
1606 
1607  /* when drawing in the camera view, in 2D space, set the subrect */
1608  p->subrect = NULL;
1609  if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) {
1610  if (p->area->spacetype == SPACE_VIEW3D) {
1611  View3D *v3d = p->area->spacedata.first;
1612  RegionView3D *rv3d = p->region->regiondata;
1613 
1614  /* for camera view set the subrect */
1615  if (rv3d->persp == RV3D_CAMOB) {
1616  /* no shift */
1618  p->scene, depsgraph, p->region, v3d, rv3d, &p->subrect_data, true);
1619  p->subrect = &p->subrect_data;
1620  }
1621  }
1622  }
1623 
1624  /* init stroke point space-conversion settings... */
1625  p->gsc.gpd = p->gpd;
1626  p->gsc.gpl = p->gpl;
1627 
1628  p->gsc.area = p->area;
1629  p->gsc.region = p->region;
1630  p->gsc.v2d = p->v2d;
1631 
1632  p->gsc.subrect_data = p->subrect_data;
1633  p->gsc.subrect = p->subrect;
1634 
1635  copy_m4_m4(p->gsc.mat, p->mat);
1636 
1637  /* check if points will need to be made in view-aligned space */
1638  if (*p->align_flag & GP_PROJECT_VIEWSPACE) {
1639  switch (p->area->spacetype) {
1640  case SPACE_VIEW3D: {
1642  break;
1643  }
1644  case SPACE_NODE:
1645  case SPACE_SEQ:
1646  case SPACE_IMAGE:
1647  case SPACE_CLIP: {
1649  break;
1650  }
1651  }
1652  }
1653 }
1654 
1655 /* finish off a stroke (clears buffer, but doesn't finish the paint operation) */
1657 {
1658  ToolSettings *ts = p->scene->toolsettings;
1659  const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0;
1660  /* for surface sketching, need to set the right OpenGL context stuff so that
1661  * the conversions will project the values correctly...
1662  */
1663  if (annotation_project_check(p)) {
1664  View3D *v3d = p->area->spacedata.first;
1665 
1666  /* need to restore the original projection settings before packing up */
1669  p->region,
1670  v3d,
1671  NULL,
1675  is_eraser ? NULL : &p->depths);
1676  }
1677 
1678  /* check if doing eraser or not */
1679  if (!is_eraser) {
1680  /* transfer stroke to frame */
1682  }
1683 
1684  /* Call to the annotation post handler to notify python the annotation is done. */
1686 
1687  /* clean up buffer now */
1689 }
1690 
1691 /* finish off stroke painting operation */
1693 {
1694  /* p->gpd==NULL happens when stroke failed to initialize,
1695  * for example when GP is hidden in current space (sergey)
1696  */
1697  if (p->gpd) {
1698  /* finish off a stroke */
1700  }
1701 
1702  /* "unlock" frame */
1703  if (p->gpf) {
1704  p->gpf->flag &= ~GP_FRAME_PAINT;
1705  }
1706 }
1707 
1708 /* ------------------------------- */
1709 
1710 /* Helper callback for drawing the cursor itself */
1711 static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
1712 {
1713  tGPsdata *p = (tGPsdata *)p_ptr;
1714 
1715  if (p->paintmode == GP_PAINTMODE_ERASER) {
1717  const uint shdr_pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
1719 
1720  GPU_line_smooth(true);
1722 
1723  immUniformColor4ub(255, 100, 100, 20);
1724  imm_draw_circle_fill_2d(shdr_pos, x, y, p->radius, 40);
1725 
1726  immUnbindProgram();
1727 
1729 
1730  float viewport_size[4];
1731  GPU_viewport_size_get_f(viewport_size);
1732  immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
1733 
1734  immUniformColor4f(1.0f, 0.39f, 0.39f, 0.78f);
1735  immUniform1i("colors_len", 0); /* "simple" mode */
1736  immUniform1f("dash_width", 12.0f);
1737  immUniform1f("dash_factor", 0.5f);
1738 
1739  imm_draw_circle_wire_2d(shdr_pos,
1740  x,
1741  y,
1742  p->radius,
1743  /* XXX Dashed shader gives bad results with sets of small segments
1744  * currently, temp hack around the issue. :( */
1745  max_ii(8, p->radius / 2)); /* was fixed 40 */
1746 
1747  immUnbindProgram();
1748 
1750  GPU_line_smooth(false);
1751  }
1752 }
1753 
1754 /* Turn brush cursor in 3D view on/off */
1755 static void annotation_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
1756 {
1757  if (p->erasercursor && !enable) {
1758  /* clear cursor */
1760  p->erasercursor = NULL;
1761  }
1762  else if (enable && !p->erasercursor) {
1763  /* enable cursor */
1765  RGN_TYPE_ANY,
1766  NULL, /* XXX */
1768  p);
1769  }
1770 }
1771 static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
1772 {
1773  ARegion *region = CTX_wm_region(C);
1774  tGPsdata *p = (tGPsdata *)p_ptr;
1775  bGPdata_Runtime runtime = p->gpd->runtime;
1776  const tGPspoint *points = runtime.sbuffer;
1777  int totpoints = runtime.sbuffer_used;
1778  if (totpoints < 2) {
1779  return;
1780  }
1781  const tGPspoint *pt = &points[totpoints - 1];
1782 
1786  GPU_line_smooth(true);
1788  GPU_line_width(1.25f);
1789  const float color[3] = {1.0f, 0.39f, 0.39f};
1790 
1791  /* default radius and color */
1792  float darkcolor[3];
1793  const float radius = 4.0f;
1794 
1795  /* Inner Ring: Color from UI panel */
1796  immUniformColor4f(color[0], color[1], color[2], 0.8f);
1797  imm_draw_circle_wire_2d(pos, x, y, radius, 40);
1798 
1799  /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */
1800  mul_v3_v3fl(darkcolor, color, 0.40f);
1801  immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f);
1802  imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40);
1803 
1804  /* Rope Simple. */
1805  immUniformColor4f(color[0], color[1], color[2], 0.8f);
1807  immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin);
1808  immVertex2f(pos, x, y);
1809  immEnd();
1810 
1811  /* Returns back all GPU settings */
1813  GPU_line_smooth(false);
1814 
1815  immUnbindProgram();
1816 }
1817 
1818 /* Turn *stabilizer* brush cursor in 3D view on/off */
1820 {
1821  if (p->stabilizer_cursor && !enable) {
1822  /* clear cursor */
1824  p->stabilizer_cursor = NULL;
1825  }
1826  else if (enable && !p->stabilizer_cursor) {
1827  /* enable cursor */
1830  }
1831 }
1832 
1833 /* Check if tablet eraser is being used (when processing events) */
1835 {
1836  return (event->tablet.active == EVT_TABLET_ERASER);
1837 }
1838 
1839 /* ------------------------------- */
1840 
1842 {
1843  tGPsdata *p = op->customdata;
1844 
1845  /* restore cursor to indicate end of drawing */
1847 
1848  /* don't assume that operator data exists at all */
1849  if (p) {
1850  /* check size of buffer before cleanup, to determine if anything happened here */
1851  if (p->paintmode == GP_PAINTMODE_ERASER) {
1852  /* turn off radial brush cursor */
1854  }
1855  else if (p->paintmode == GP_PAINTMODE_DRAW) {
1857  }
1858 
1859  /* always store the new eraser size to be used again next time
1860  * NOTE: Do this even when not in eraser mode, as eraser may
1861  * have been toggled at some point.
1862  */
1863  U.gp_eraser = p->radius;
1864 
1865  /* clear undo stack */
1867 
1868  /* cleanup */
1872  p = NULL;
1873  }
1874 
1875  op->customdata = NULL;
1876 }
1877 
1879 {
1880  /* this is just a wrapper around exit() */
1881  annotation_draw_exit(C, op);
1882 }
1883 
1884 /* ------------------------------- */
1885 
1886 static int annotation_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
1887 {
1888  tGPsdata *p;
1889  eGPencil_PaintModes paintmode = RNA_enum_get(op->ptr, "mode");
1890 
1891  /* check context */
1893  if ((p == NULL) || (p->status == GP_STATUS_ERROR)) {
1894  /* something wasn't set correctly in context */
1895  annotation_draw_exit(C, op);
1896  return 0;
1897  }
1898 
1899  /* init painting data */
1901  if (p->status == GP_STATUS_ERROR) {
1902  annotation_draw_exit(C, op);
1903  return 0;
1904  }
1905 
1906  if (event != NULL) {
1907  p->keymodifier = event->keymodifier;
1908  }
1909  else {
1910  p->keymodifier = -1;
1911  }
1912 
1913  /* everything is now setup ok */
1914  return 1;
1915 }
1916 
1917 /* ------------------------------- */
1918 
1919 /* ensure that the correct cursor icon is set */
1921 {
1922  if (p->paintmode == GP_PAINTMODE_ERASER) {
1924  }
1925  else {
1927  }
1928 }
1929 
1930 /* update UI indicators of status, including cursor and header prints */
1932 {
1933  /* header prints */
1934  switch (p->status) {
1935  case GP_STATUS_PAINTING:
1936  switch (p->paintmode) {
1938  /* Provide usage tips, since this is modal, and unintuitive without hints */
1940  C,
1941  TIP_("Annotation Create Poly: LMB click to place next stroke vertex | "
1942  "ESC/Enter to end (or click outside this area)"));
1943  break;
1944  default:
1945  /* Do nothing - the others are self explanatory, exit quickly once the mouse is
1946  * released Showing any text would just be annoying as it would flicker.
1947  */
1948  break;
1949  }
1950  break;
1951 
1952  case GP_STATUS_IDLING:
1953  /* print status info */
1954  switch (p->paintmode) {
1955  case GP_PAINTMODE_ERASER:
1957  TIP_("Annotation Eraser: Hold and drag LMB or RMB to erase | "
1958  "ESC/Enter to end (or click outside this area)"));
1959  break;
1962  TIP_("Annotation Line Draw: Hold and drag LMB to draw | "
1963  "ESC/Enter to end (or click outside this area)"));
1964  break;
1965  case GP_PAINTMODE_DRAW:
1967  TIP_("Annotation Freehand Draw: Hold and drag LMB to draw | "
1968  "E/ESC/Enter to end (or click outside this area)"));
1969  break;
1972  C,
1973  TIP_("Annotation Create Poly: LMB click to place next stroke vertex | "
1974  "ESC/Enter to end (or click outside this area)"));
1975  break;
1976 
1977  default: /* unhandled future cases */
1979  C, TIP_("Annotation Session: ESC/Enter to end (or click outside this area)"));
1980  break;
1981  }
1982  break;
1983 
1984  case GP_STATUS_ERROR:
1985  case GP_STATUS_DONE:
1986  case GP_STATUS_CAPTURE:
1987  /* clear status string */
1989  break;
1990  }
1991 }
1992 
1993 /* ------------------------------- */
1994 
1995 /* create a new stroke point at the point indicated by the painting context */
1997 {
1998  /* handle drawing/erasing -> test for erasing first */
1999  if (p->paintmode == GP_PAINTMODE_ERASER) {
2000  /* do 'live' erasing now */
2002 
2003  /* store used values */
2004  p->mvalo[0] = p->mval[0];
2005  p->mvalo[1] = p->mval[1];
2006  p->opressure = p->pressure;
2007  }
2008  /* Only add current point to buffer if mouse moved
2009  * (even though we got an event, it might be just noise). */
2010  else if (annotation_stroke_filtermval(p, p->mval, p->mvalo)) {
2011  /* If lazy mouse, interpolate the last and current mouse positions. */
2013  float now_mouse[2];
2014  float last_mouse[2];
2015  copy_v2_v2(now_mouse, p->mval);
2016  copy_v2_v2(last_mouse, p->mvalo);
2017  interp_v2_v2v2(now_mouse, now_mouse, last_mouse, min_ff(p->stabilizer_factor, .995f));
2018  copy_v2_v2(p->mval, now_mouse);
2019  }
2020 
2021  /* try to add point */
2022  short ok = annotation_stroke_addpoint(p, p->mval, p->pressure, p->curtime);
2023 
2024  /* handle errors while adding point */
2026  /* finish off old stroke */
2028  /* And start a new one!!! Else, projection errors! */
2030 
2031  /* start a new stroke, starting from previous point */
2032  if (ok == GP_STROKEADD_OVERFLOW) {
2033  p->inittime = p->ocurtime;
2035  }
2036  else {
2037  p->inittime = p->curtime;
2038  }
2040  }
2041  else if (ok == GP_STROKEADD_INVALID) {
2042  /* the painting operation cannot continue... */
2043  BKE_report(op->reports, RPT_ERROR, "Cannot paint stroke");
2044  p->status = GP_STATUS_ERROR;
2045 
2046  return;
2047  }
2048 
2049  /* store used values */
2050  p->mvalo[0] = p->mval[0];
2051  p->mvalo[1] = p->mval[1];
2052  p->opressure = p->pressure;
2053  p->ocurtime = p->curtime;
2054  }
2055 }
2056 
2057 /* handle draw event */
2059  wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
2060 {
2061  tGPsdata *p = op->customdata;
2062  PointerRNA itemptr;
2063  float mousef[2];
2064 
2065  /* Convert from window-space to area-space mouse coordinates
2066  * add any x,y override position for fake events. */
2067  if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
2068  /* The first run may be a drag event, see: T99368. */
2069  WM_event_drag_start_mval_fl(event, p->region, p->mval);
2070  p->mval[0] -= x;
2071  p->mval[1] -= y;
2072  }
2073  else {
2074  p->mval[0] = (float)event->mval[0] - x;
2075  p->mval[1] = (float)event->mval[1] - y;
2076  }
2077 
2078  /* Key to toggle stabilization. */
2079  if ((event->modifier & KM_SHIFT) && (p->paintmode == GP_PAINTMODE_DRAW)) {
2080  /* Using permanent stabilization, shift will deactivate the flag. */
2085  }
2086  }
2087  /* Not using any stabilization flag. Activate temporal one. */
2088  else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
2091  }
2092  }
2093  /* verify key status for straight lines */
2094  else if (event->modifier & (KM_CTRL | KM_ALT)) {
2095  if (p->straight[0] == 0) {
2096  int dx = abs((int)(p->mval[0] - p->mvalo[0]));
2097  int dy = abs((int)(p->mval[1] - p->mvalo[1]));
2098  if ((dx > 0) || (dy > 0)) {
2099  /* check mouse direction to replace the other coordinate with previous values */
2100  if (dx >= dy) {
2101  /* horizontal */
2102  p->straight[0] = 1;
2103  p->straight[1] = p->mval[1]; /* save y */
2104  }
2105  else {
2106  /* vertical */
2107  p->straight[0] = 2;
2108  p->straight[1] = p->mval[0]; /* save x */
2109  }
2110  }
2111  }
2112  }
2113  else {
2114  p->straight[0] = 0;
2115  /* We were using shift while having permanent stabilization active,
2116  * so activate the temp flag back again. */
2118  if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) {
2121  }
2122  }
2123  /* We are using the temporal stabilizer flag at the moment,
2124  * but shift is not pressed as well as the permanent flag is not used,
2125  * so we don't need the cursor anymore. */
2126  else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) {
2127  /* Reset temporal stabilizer flag and remove cursor. */
2130  }
2131  }
2132 
2134 
2135  /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
2136  p->pressure = event->tablet.pressure;
2137 
2138  /* Hack for pressure sensitive eraser on D+RMB when using a tablet:
2139  * The pen has to float over the tablet surface, resulting in
2140  * zero pressure (T47101). Ignore pressure values if floating
2141  * (i.e. "effectively zero" pressure), and only when the "active"
2142  * end is the stylus (i.e. the default when not eraser)
2143  */
2144  if (p->paintmode == GP_PAINTMODE_ERASER) {
2145  if ((event->tablet.active != EVT_TABLET_ERASER) && (p->pressure < 0.001f)) {
2146  p->pressure = 1.0f;
2147  }
2148  }
2149 
2150  /* special exception for start of strokes (i.e. maybe for just a dot) */
2151  if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
2153 
2154  p->mvalo[0] = p->mval[0];
2155  p->mvalo[1] = p->mval[1];
2156  p->opressure = p->pressure;
2157  p->inittime = p->ocurtime = p->curtime;
2158  p->straight[0] = 0;
2159  p->straight[1] = 0;
2160 
2161  /* special exception here for too high pressure values on first touch in
2162  * windows for some tablets, then we just skip first touch...
2163  */
2164  if ((event->tablet.active != EVT_TABLET_NONE) && (p->pressure >= 0.99f)) {
2165  return;
2166  }
2167  }
2168 
2169  /* check if alt key is pressed and limit to straight lines */
2170  if ((p->paintmode != GP_PAINTMODE_ERASER) && (p->straight[0] != 0)) {
2171  if (p->straight[0] == 1) {
2172  /* horizontal */
2173  p->mval[1] = p->straight[1]; /* replace y */
2174  }
2175  else {
2176  /* vertical */
2177  p->mval[0] = p->straight[1]; /* replace x */
2178  }
2179  }
2180 
2181  /* fill in stroke data (not actually used directly by gpencil_draw_apply) */
2182  RNA_collection_add(op->ptr, "stroke", &itemptr);
2183 
2184  mousef[0] = p->mval[0];
2185  mousef[1] = p->mval[1];
2186  RNA_float_set_array(&itemptr, "mouse", mousef);
2187  RNA_float_set(&itemptr, "pressure", p->pressure);
2188  RNA_boolean_set(&itemptr, "is_start", (p->flags & GP_PAINTFLAG_FIRSTRUN) != 0);
2189 
2190  RNA_float_set(&itemptr, "time", p->curtime - p->inittime);
2191 
2192  /* apply the current latest drawing point */
2194 
2195  /* force refresh */
2196  /* just active area for now, since doing whole screen is too slow */
2198 }
2199 
2200 /* ------------------------------- */
2201 
2202 /* operator 'redo' (i.e. after changing some properties, but also for repeat last) */
2204 {
2205  tGPsdata *p = NULL;
2207 
2208  /* try to initialize context data needed while drawing */
2209  if (!annotation_draw_init(C, op, NULL)) {
2210  if (op->customdata) {
2211  MEM_freeN(op->customdata);
2212  }
2213  return OPERATOR_CANCELLED;
2214  }
2215 
2216  p = op->customdata;
2217 
2218  /* loop over the stroke RNA elements recorded (i.e. progress of mouse movement),
2219  * setting the relevant values in context at each step, then applying
2220  */
2221  RNA_BEGIN (op->ptr, itemptr, "stroke") {
2222  float mousef[2];
2223 
2224  /* get relevant data for this point from stroke */
2225  RNA_float_get_array(&itemptr, "mouse", mousef);
2226  p->mval[0] = (int)mousef[0];
2227  p->mval[1] = (int)mousef[1];
2228  p->pressure = RNA_float_get(&itemptr, "pressure");
2229  p->curtime = (double)RNA_float_get(&itemptr, "time") + p->inittime;
2230 
2231  if (RNA_boolean_get(&itemptr, "is_start")) {
2232  /* if first-run flag isn't set already (i.e. not true first stroke),
2233  * then we must terminate the previous one first before continuing
2234  */
2235  if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
2236  /* TODO: both of these ops can set error-status, but we probably don't need to worry */
2239  }
2240  }
2241 
2242  /* if first run, set previous data too */
2243  if (p->flags & GP_PAINTFLAG_FIRSTRUN) {
2245 
2246  p->mvalo[0] = p->mval[0];
2247  p->mvalo[1] = p->mval[1];
2248  p->opressure = p->pressure;
2249  p->ocurtime = p->curtime;
2250  }
2251 
2252  /* apply this data as necessary now (as per usual) */
2254  }
2255  RNA_END;
2256 
2257  /* cleanup */
2258  annotation_draw_exit(C, op);
2259 
2260  /* refreshes */
2262 
2263  /* done */
2264  return OPERATOR_FINISHED;
2265 }
2266 
2267 /* ------------------------------- */
2268 
2269 /* start of interactive drawing part of operator */
2270 static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2271 {
2272  tGPsdata *p = NULL;
2273 
2274  /* support for tablets eraser pen */
2276  RNA_enum_set(op->ptr, "mode", GP_PAINTMODE_ERASER);
2277  }
2278 
2279  /* try to initialize context data needed while drawing */
2280  if (!annotation_draw_init(C, op, event)) {
2281  if (op->customdata) {
2282  MEM_freeN(op->customdata);
2283  }
2284  return OPERATOR_CANCELLED;
2285  }
2286 
2287  p = op->customdata;
2288 
2289  /* if empty erase capture and finish */
2290  if (p->status == GP_STATUS_CAPTURE) {
2291  annotation_draw_exit(C, op);
2292 
2293  BKE_report(op->reports, RPT_ERROR, "Nothing to erase");
2294  return OPERATOR_FINISHED;
2295  }
2296 
2297  /* if eraser is on, draw radial aid */
2298  if (p->paintmode == GP_PAINTMODE_ERASER) {
2300  }
2301  else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) {
2302  if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) {
2304  p->gpd->runtime.arrow_start_style = RNA_enum_get(op->ptr, "arrowstyle_start");
2305  }
2306  if (RNA_enum_get(op->ptr, "arrowstyle_end") != GP_STROKE_ARROWSTYLE_NONE) {
2308  p->gpd->runtime.arrow_end_style = RNA_enum_get(op->ptr, "arrowstyle_end");
2309  }
2310  }
2311  else if (p->paintmode == GP_PAINTMODE_DRAW) {
2312  p->stabilizer_factor = RNA_float_get(op->ptr, "stabilizer_factor");
2313  p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius");
2314  if (RNA_boolean_get(op->ptr, "use_stabilizer")) {
2317  }
2318  else if (event->modifier & KM_SHIFT) {
2321  }
2322  }
2323  /* set cursor
2324  * NOTE: This may change later (i.e. intentionally via brush toggle,
2325  * or unintentionally if the user scrolls outside the area)...
2326  */
2328 
2329  /* only start drawing immediately if we're allowed to do so... */
2330  if (RNA_boolean_get(op->ptr, "wait_for_input") == false) {
2331  /* hotkey invoked - start drawing */
2333 
2334  /* handle the initial drawing - i.e. for just doing a simple dot */
2337  }
2338  else {
2339  /* toolbar invoked - don't start drawing yet... */
2341  }
2342 
2344  /* add a modal handler for this operator, so that we can then draw continuous strokes */
2346  return OPERATOR_RUNNING_MODAL;
2347 }
2348 
2349 /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
2350 static bool annotation_area_exists(bContext *C, ScrArea *area_test)
2351 {
2352  bScreen *screen = CTX_wm_screen(C);
2353  return (BLI_findindex(&screen->areabase, area_test) != -1);
2354 }
2355 
2357 {
2358  tGPsdata *p = op->customdata;
2359 
2360  /* we must check that we're still within the area that we're set up to work from
2361  * otherwise we could crash (see bug T20586)
2362  */
2363  if (CTX_wm_area(C) != p->area) {
2364  printf("\t\t\tGP - wrong area execution abort!\n");
2365  p->status = GP_STATUS_ERROR;
2366  }
2367 
2368  /* we may need to set up paint env again if we're resuming */
2369  /* XXX: watch it with the paintmode! in future,
2370  * it'd be nice to allow changing paint-mode when in sketching-sessions */
2371 
2372  if (annotation_session_initdata(C, p)) {
2374  }
2375 
2376  if (p->status != GP_STATUS_ERROR) {
2379  }
2380 
2381  return op->customdata;
2382 }
2383 
2385 {
2386  tGPsdata *p = op->customdata;
2387 
2389 
2390  gpencil_undo_push(p->gpd);
2391 
2393 
2394  p->status = GP_STATUS_IDLING;
2396 
2397  p->gpd = NULL;
2398  p->gpl = NULL;
2399  p->gpf = NULL;
2400 }
2401 
2402 /* add events for missing mouse movements when the artist draw very fast */
2404  wmOperator *op,
2405  const wmEvent *event,
2406  tGPsdata *p)
2407 {
2409  float pt[2], a[2], b[2];
2410  float factor = 10.0f;
2411 
2412  copy_v2_v2(a, p->mvalo);
2413  b[0] = (float)event->mval[0] + 1.0f;
2414  b[1] = (float)event->mval[1] + 1.0f;
2415 
2416  /* get distance in pixels */
2417  float dist = len_v2v2(a, b);
2418 
2419  /* for very small distances, add a half way point */
2420  if (dist <= 2.0f) {
2421  interp_v2_v2v2(pt, a, b, 0.5f);
2422  sub_v2_v2v2(pt, b, pt);
2423  /* create fake event */
2424  annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]);
2425  }
2426  else if (dist >= factor) {
2427  int slices = 2 + (int)((dist - 1.0) / factor);
2428  float n = 1.0f / slices;
2429  for (int i = 1; i < slices; i++) {
2430  interp_v2_v2v2(pt, a, b, n * i);
2431  sub_v2_v2v2(pt, b, pt);
2432  /* create fake event */
2433  annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]);
2434  }
2435  }
2436 }
2437 
2438 /* events handling during interactive drawing part of operator */
2439 static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
2440 {
2441  tGPsdata *p = op->customdata;
2442  /* Default exit state - pass through to support MMB view navigation, etc. */
2443  int estate = OPERATOR_PASS_THROUGH;
2444 
2445  /* NOTE(mike erwin): Not quite what I was looking for, but a good start!
2446  * grease-pencil continues to draw on the screen while the 3D mouse moves the viewpoint.
2447  * Problem is that the stroke is converted to 3D only after it is finished.
2448  * This approach should work better in tools that immediately apply in 3D space. */
2449 #if 0
2450  if (event->type == NDOF_MOTION) {
2451  return OPERATOR_PASS_THROUGH;
2452  }
2453 #endif
2454 
2455  if (p->status == GP_STATUS_IDLING) {
2456  ARegion *region = CTX_wm_region(C);
2457  p->region = region;
2458  }
2459 
2460  /* We don't pass on key events, GP is used with key-modifiers -
2461  * prevents Dkey to insert drivers. */
2462  if (ISKEYBOARD(event->type)) {
2463  if (ELEM(event->type,
2468  EVT_ZKEY)) {
2469  /* allow some keys:
2470  * - For frame changing T33412.
2471  * - For undo (during sketching sessions).
2472  */
2473  }
2474  else if (ELEM(event->type,
2475  EVT_PAD0,
2476  EVT_PAD1,
2477  EVT_PAD2,
2478  EVT_PAD3,
2479  EVT_PAD4,
2480  EVT_PAD5,
2481  EVT_PAD6,
2482  EVT_PAD7,
2483  EVT_PAD8,
2484  EVT_PAD9)) {
2485  /* Allow numpad keys so that camera/view manipulations can still take place
2486  * - #EVT_PAD0 in particular is really important for Grease Pencil drawing,
2487  * as animators may be working "to camera", so having this working
2488  * is essential for ensuring that they can quickly return to that view.
2489  */
2490  }
2491  else if ((event->type == EVT_BKEY) && (event->val == KM_RELEASE)) {
2492  /* Add Blank Frame
2493  * - Since this operator is non-modal, we can just call it here, and keep going...
2494  * - This operator is especially useful when animating
2495  */
2496  WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL, event);
2497  estate = OPERATOR_RUNNING_MODAL;
2498  }
2499  else {
2500  estate = OPERATOR_RUNNING_MODAL;
2501  }
2502  }
2503 
2504  /* Exit painting mode (and/or end current stroke)
2505  *
2506  * NOTE: cannot do RIGHTMOUSE (as is standard for canceling)
2507  * as that would break polyline T32647.
2508  */
2509  if (event->val == KM_PRESS &&
2511  /* exit() ends the current stroke before cleaning up */
2512  p->status = GP_STATUS_DONE;
2513  estate = OPERATOR_FINISHED;
2514  }
2515 
2516  /* toggle painting mode upon mouse-button movement
2517  * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox
2518  * only)
2519  * - RIGHTMOUSE = polyline (hotkey) / eraser (all)
2520  * (Disabling RIGHTMOUSE case here results in bugs like T32647)
2521  * also making sure we have a valid event value, to not exit too early
2522  */
2523  if (ELEM(event->type, LEFTMOUSE, RIGHTMOUSE) && (ELEM(event->val, KM_PRESS, KM_RELEASE))) {
2524  /* if painting, end stroke */
2525  if (p->status == GP_STATUS_PAINTING) {
2526  int sketch = 0;
2527 
2528  /* basically, this should be mouse-button up = end stroke
2529  * BUT, polyline drawing is an exception -- all knots should be added during one session
2530  */
2531  sketch |= (p->paintmode == GP_PAINTMODE_DRAW_POLY);
2532 
2533  if (sketch) {
2534  /* end stroke only, and then wait to resume painting soon */
2536 
2537  /* If eraser mode is on, turn it off after the stroke finishes
2538  * NOTE: This just makes it nicer to work with drawing sessions
2539  */
2540  if (p->paintmode == GP_PAINTMODE_ERASER) {
2541  p->paintmode = RNA_enum_get(op->ptr, "mode");
2542 
2543  /* if the original mode was *still* eraser,
2544  * we'll let it say for now, since this gives
2545  * users an opportunity to have visual feedback
2546  * when adjusting eraser size
2547  */
2548  if (p->paintmode != GP_PAINTMODE_ERASER) {
2549  /* turn off cursor...
2550  * NOTE: this should be enough for now
2551  * Just hiding this makes it seem like
2552  * you can paint again...
2553  */
2555  }
2556  }
2557 
2558  /* we've just entered idling state, so this event was processed (but no others yet) */
2559  estate = OPERATOR_RUNNING_MODAL;
2560 
2561  /* stroke could be smoothed, send notifier to refresh screen */
2563  }
2564  else {
2565  p->status = GP_STATUS_DONE;
2566  estate = OPERATOR_FINISHED;
2567  }
2568  }
2569  else if (event->val == KM_PRESS) {
2570  bool in_bounds = false;
2571 
2572  /* Check if we're outside the bounds of the active region
2573  * NOTE: An exception here is that if launched from the toolbar,
2574  * whatever region we're now in should become the new region
2575  */
2576  if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) {
2577  /* Change to whatever region is now under the mouse */
2578  ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy);
2579 
2580  if (current_region) {
2581  /* Assume that since we found the cursor in here, it is in bounds
2582  * and that this should be the region that we begin drawing in
2583  */
2584  p->region = current_region;
2585  in_bounds = true;
2586  }
2587  else {
2588  /* Out of bounds, or invalid in some other way */
2589  p->status = GP_STATUS_ERROR;
2590  estate = OPERATOR_CANCELLED;
2591  }
2592  }
2593  else if (p->region) {
2594  /* Perform bounds check. */
2595  const rcti *region_rect = ED_region_visible_rect(p->region);
2596  in_bounds = BLI_rcti_isect_pt_v(region_rect, event->mval);
2597  }
2598  else {
2599  /* No region */
2600  p->status = GP_STATUS_ERROR;
2601  estate = OPERATOR_CANCELLED;
2602  }
2603 
2604  if (in_bounds) {
2605  /* Switch paintmode (temporarily if need be) based on which button was used
2606  * NOTE: This is to make it more convenient to erase strokes when using drawing sessions
2607  */
2608  if ((event->type == RIGHTMOUSE) || annotation_is_tablet_eraser_active(event)) {
2609  /* turn on eraser */
2611  }
2612  else if (event->type == LEFTMOUSE) {
2613  /* restore drawmode to default */
2614  p->paintmode = RNA_enum_get(op->ptr, "mode");
2615  }
2616 
2618 
2619  /* not painting, so start stroke (this should be mouse-button down) */
2620  p = annotation_stroke_begin(C, op);
2621 
2622  if (p->status == GP_STATUS_ERROR) {
2623  estate = OPERATOR_CANCELLED;
2624  }
2625  }
2626  else if (p->status != GP_STATUS_ERROR) {
2627  /* User clicked outside bounds of window while idling, so exit paintmode
2628  * NOTE: Don't enter this case if an error occurred while finding the
2629  * region (as above)
2630  */
2631  p->status = GP_STATUS_DONE;
2632  estate = OPERATOR_FINISHED;
2633  }
2634  }
2635  else if (event->val == KM_RELEASE) {
2636  p->status = GP_STATUS_IDLING;
2638  }
2639  }
2640 
2641  /* handle mode-specific events */
2642  if (p->status == GP_STATUS_PAINTING) {
2643  /* handle painting mouse-movements? */
2644  if (ISMOUSE_MOTION(event->type) || (p->flags & GP_PAINTFLAG_FIRSTRUN)) {
2645  /* handle drawing event */
2646  if ((p->flags & GP_PAINTFLAG_FIRSTRUN) == 0) {
2647  annotation_add_missing_events(C, op, event, p);
2648  }
2649 
2650  /* TODO(sergey): Possibly evaluating dependency graph from modal operator? */
2652 
2653  /* finish painting operation if anything went wrong just now */
2654  if (p->status == GP_STATUS_ERROR) {
2655  printf("\t\t\t\tGP - add error done!\n");
2656  estate = OPERATOR_CANCELLED;
2657  }
2658  else {
2659  /* event handled, so just tag as running modal */
2660  estate = OPERATOR_RUNNING_MODAL;
2661  }
2662  }
2663  /* eraser size */
2664  else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
2666  /* just resize the brush (local version)
2667  * TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
2668  */
2669  switch (event->type) {
2670  case WHEELDOWNMOUSE: /* larger */
2671  case EVT_PADPLUSKEY:
2672  p->radius += 5;
2673  break;
2674 
2675  case WHEELUPMOUSE: /* smaller */
2676  case EVT_PADMINUS:
2677  p->radius -= 5;
2678 
2679  if (p->radius <= 0) {
2680  p->radius = 1;
2681  }
2682  break;
2683  }
2684 
2685  /* force refresh */
2686  /* just active area for now, since doing whole screen is too slow */
2688 
2689  /* event handled, so just tag as running modal */
2690  estate = OPERATOR_RUNNING_MODAL;
2691  }
2692  /* there shouldn't be any other events, but just in case there are, let's swallow them
2693  * (i.e. to prevent problems with undo)
2694  */
2695  else {
2696  /* swallow event to save ourselves trouble */
2697  estate = OPERATOR_RUNNING_MODAL;
2698  }
2699  }
2700 
2701  /* gpencil modal operator stores area, which can be removed while using it (like fullscreen) */
2702  if (0 == annotation_area_exists(C, p->area)) {
2703  estate = OPERATOR_CANCELLED;
2704  }
2705  else {
2706  /* update status indicators - cursor, header, etc. */
2708  /* cursor may have changed outside our control - T44084 */
2710  }
2711 
2712  /* process last operations before exiting */
2713  switch (estate) {
2714  case OPERATOR_FINISHED:
2715  /* one last flush before we're done */
2716  annotation_draw_exit(C, op);
2718  break;
2719 
2720  case OPERATOR_CANCELLED:
2721  annotation_draw_exit(C, op);
2722  break;
2723 
2725  /* event doesn't need to be handled */
2726  break;
2727  }
2728 
2729  /* return status code */
2730  return estate;
2731 }
2732 
2733 /* ------------------------------- */
2734 
2736  {GP_PAINTMODE_DRAW, "DRAW", 0, "Draw Freehand", "Draw freehand stroke(s)"},
2738  "DRAW_STRAIGHT",
2739  0,
2740  "Draw Straight Lines",
2741  "Draw straight line segment(s)"},
2743  "DRAW_POLY",
2744  0,
2745  "Draw Poly Line",
2746  "Click to place endpoints of straight line segments (connected)"},
2747  {GP_PAINTMODE_ERASER, "ERASER", 0, "Eraser", "Erase Annotation strokes"},
2748  {0, NULL, 0, NULL, NULL},
2749 };
2750 
2751 static const EnumPropertyItem arrow_types[] = {
2752  {GP_STROKE_ARROWSTYLE_NONE, "NONE", 0, "None", "Don't use any arrow/style in corner"},
2753  {GP_STROKE_ARROWSTYLE_CLOSED, "ARROW", 0, "Arrow", "Use closed arrow style"},
2754  {GP_STROKE_ARROWSTYLE_OPEN, "ARROW_OPEN", 0, "Open Arrow", "Use open arrow style"},
2756  "ARROW_OPEN_INVERTED",
2757  0,
2758  "Segment",
2759  "Use perpendicular segment style"},
2760  {GP_STROKE_ARROWSTYLE_SQUARE, "DIAMOND", 0, "Square", "Use square style"},
2761  {0, NULL, 0, NULL, NULL},
2762 };
2763 
2765 {
2766  PropertyRNA *prop;
2767 
2768  /* identifiers */
2769  ot->name = "Annotation Draw";
2770  ot->idname = "GPENCIL_OT_annotate";
2771  ot->description = "Make annotations on the active data";
2772 
2773  /* api callbacks */
2779 
2780  /* flags */
2782 
2783  /* settings for drawing */
2784  ot->prop = RNA_def_enum(
2785  ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements");
2786 
2787  /* properties */
2788  prop = RNA_def_enum(
2789  ot->srna, "arrowstyle_start", arrow_types, 0, "Start Arrow Style", "Stroke start style");
2790  prop = RNA_def_enum(
2791  ot->srna, "arrowstyle_end", arrow_types, 0, "End Arrow Style", "Stroke end style");
2792  prop = RNA_def_boolean(ot->srna,
2793  "use_stabilizer",
2794  false,
2795  "Stabilize Stroke",
2796  "Helper to draw smooth and clean lines. Press Shift for an invert effect "
2797  "(even if this option is not active)");
2798  prop = RNA_def_float(ot->srna,
2799  "stabilizer_factor",
2800  0.75f,
2801  0.0f,
2802  1.0f,
2803  "Stabilizer Stroke Factor",
2804  "Higher values gives a smoother stroke",
2805  0.0f,
2806  1.0f);
2807  prop = RNA_def_int(ot->srna,
2808  "stabilizer_radius",
2809  35,
2810  0,
2811  200,
2812  "Stabilizer Stroke Radius",
2813  "Minimum distance from last point before stroke continues",
2814  1,
2815  100);
2817 
2818  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
2820 
2821  /* NOTE: wait for input is enabled by default,
2822  * so that all UI code can work properly without needing users to know about this */
2823  prop = RNA_def_boolean(ot->srna,
2824  "wait_for_input",
2825  true,
2826  "Wait for Input",
2827  "Wait for first click instead of painting immediately");
2829 }
typedef float(TangentPoint)[2]
void BKE_callback_exec_id_depsgraph(struct Main *bmain, struct ID *id, struct Depsgraph *depsgraph, eCbEvent evt)
Definition: callbacks.c:56
@ BKE_CB_EVT_ANNOTATION_POST
Definition: BKE_callbacks.h:99
@ BKE_CB_EVT_ANNOTATION_PRE
Definition: BKE_callbacks.h:98
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
struct bGPDstroke * BKE_gpencil_stroke_duplicate(struct bGPDstroke *gps_src, bool dup_points, bool dup_curve)
Definition: gpencil.c:855
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1558
void BKE_gpencil_free_stroke_weights(struct bGPDstroke *gps)
Definition: gpencil.c:361
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive, bool add_to_header)
Definition: gpencil.c:621
bool BKE_gpencil_layer_is_editable(const struct bGPDlayer *gpl)
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1232
#define GPENCIL_STRENGTH_MIN
Definition: BKE_gpencil.h:324
struct bGPdata * BKE_gpencil_data_addnew(struct Main *bmain, const char name[])
Definition: gpencil.c:705
@ GP_GETFRAME_ADD_NEW
Definition: BKE_gpencil.h:341
@ GP_GETFRAME_ADD_COPY
Definition: BKE_gpencil.h:343
struct bGPDstroke * BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, bool select, bool flat_cap, int limit)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
struct ARegion * BKE_area_find_region_xy(struct ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition: screen.c:898
struct MovieTrackingTrack * BKE_tracking_track_get_active(struct MovieTracking *tracking)
Definition: tracking.c:1089
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition: tracking.c:1424
#define BLI_assert(a)
Definition: BLI_assert.h:46
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:239
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
int interp_sparse_array(float *array, int list_size, float skipval)
Definition: math_geom.c:3917
void unit_m4(float m[4][4])
Definition: rct.c:1090
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
MINLINE void round_v2i_v2fl(int r[2], const float a[2])
MINLINE void madd_v2_v2fl(float r[2], const float a[2], float f)
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)
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v2(float r[2])
MINLINE void copy_v2_fl(float r[2], float f)
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
#define DATA_(msgid)
typedef double(DMatrix)[4][4]
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
@ GP_STROKE_ARROWSTYLE_NONE
@ GP_STROKE_ARROWSTYLE_SEGMENT
@ GP_STROKE_ARROWSTYLE_CLOSED
@ GP_STROKE_ARROWSTYLE_OPEN
@ GP_STROKE_ARROWSTYLE_SQUARE
@ GP_STROKE_USE_ARROW_END
@ GP_STROKE_ERASER
@ GP_STROKE_2DSPACE
@ GP_STROKE_3DSPACE
@ GP_STROKE_USE_ARROW_START
@ GP_LAYER_NO_XRAY
@ GP_LAYER_LOCKED
@ GP_FRAME_PAINT
@ GP_DATA_ANNOTATIONS
@ GP_SPOINT_TAG
@ GP_SPOINT_SELECT
Object is a sort of wrapper for general info.
@ GP_PROJECT_VIEWSPACE
@ GP_PROJECT_DEPTH_VIEW
@ GP_PROJECT_DEPTH_STROKE_ENDPOINTS
@ GP_PROJECT_DEPTH_STROKE
@ GP_TOOL_FLAG_RETAIN_LAST
@ RGN_TYPE_PREVIEW
@ RGN_TYPE_TOOLS
#define RGN_TYPE_ANY
@ SI_SHOW_GPENCIL
@ SNODE_SHOW_GPENCIL
@ SPACE_CLIP
@ SPACE_NODE
@ SPACE_SEQ
@ SPACE_IMAGE
@ SPACE_VIEW3D
@ SEQ_PREVIEW_SHOW_GPENCIL
@ SC_SHOW_ANNOTATION
@ SEQ_DRAW_IMG_IMBUF
@ SC_GPENCIL_SRC_TRACK
#define SPACE_TYPE_ANY
#define V3D_SHOW_ANNOTATION
#define RV3D_CAMOB
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ OP_IS_MODAL_CURSOR_REGION
int ED_space_clip_get_clip_frame_number(struct SpaceClip *sc)
Definition: clip_editor.c:231
struct MovieClip * ED_space_clip_get_clip(struct SpaceClip *sc)
Definition: clip_editor.c:570
bool ED_operator_regionactive(struct bContext *C)
Definition: screen_ops.c:91
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
const rcti * ED_region_visible_rect(ARegion *region)
Definition: area.c:3763
bool ED_view3d_depth_read_cached(const ViewDepths *vd, const int mval[2], int margin, float *r_depth)
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:234
void ED_view3d_win_to_delta(const struct ARegion *region, const float xy_delta[2], float zfac, float r_out[3])
eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
bool ED_view3d_depth_read_cached_seg(const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
void ED_view3d_depths_free(ViewDepths *depths)
Definition: view3d_draw.c:2366
@ V3D_DEPTH_NO_GPENCIL
Definition: ED_view3d.h:182
@ V3D_DEPTH_GPENCIL_ONLY
Definition: ED_view3d.h:184
float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3])
bool ED_view3d_depth_unproject_v3(const struct ARegion *region, const int mval[2], double depth, float r_location_world[3])
void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *region)
bool ED_view3d_autodist_simple(struct ARegion *region, const int mval[2], float mouse_worldloc[3], int margin, const float *force_depth)
void ED_view3d_calc_camera_border(const struct Scene *scene, struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, bool no_shift)
void ED_view3d_depth_override(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obact, eV3DDepthOverrideMode mode, struct ViewDepths **r_depths)
Definition: view3d_draw.c:2294
float ED_view3d_calc_depth_for_comparison(const struct RegionView3D *rv3d, const float co[3])
void immUniform2f(const char *name, float x, float y)
void immUniformColor4f(float r, float g, float b, float a)
void immUnbindProgram(void)
void immVertex2f(uint attr_id, float x, float y)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immUniform1i(const char *name, int x)
void immUniform1f(const char *name, float x)
void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
GPUVertFormat * immVertexFormat(void)
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
void imm_draw_circle_fill_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR
Definition: GPU_shader.h:349
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
void GPU_line_width(float width)
Definition: gpu_state.cc:158
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:75
void GPU_viewport_size_get_f(float coords[4])
Definition: gpu_state.cc:259
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
Platform independent time functions.
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:543
#define RNA_END
Definition: RNA_access.h:550
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
@ PROP_PIXEL
Definition: RNA_types.h:141
#define C
Definition: RandGen.cpp:25
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:25
@ KM_PRESS
Definition: WM_types.h:267
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
#define NA_EDITED
Definition: WM_types.h:523
#define NC_GPENCIL
Definition: WM_types.h:349
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
@ KM_CTRL
Definition: WM_types.h:239
@ KM_ALT
Definition: WM_types.h:240
@ KM_SHIFT
Definition: WM_types.h:238
void GPENCIL_OT_annotate(wmOperatorType *ot)
eGPencil_PaintStatus
@ GP_STATUS_PAINTING
@ GP_STATUS_IDLING
@ GP_STATUS_CAPTURE
@ GP_STATUS_ERROR
@ GP_STATUS_DONE
static void annotation_stroke_arrow_calc_points(tGPspoint *point, const float stroke_dir[2], float corner[2], float stroke_points[8], const int arrow_style)
static short annotation_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime)
static void annotation_arrow_create(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, bGPDstroke *arrow_stroke, const float arrow_points[8], const int style)
static void annotation_arrow_create_square(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float corner_point[3], const float arrow_points[8])
static bool annotation_stroke_eraser_is_occluded(tGPsdata *p, const bGPDspoint *pt, const int x, const int y)
static void annotation_stroke_eraser_dostroke(tGPsdata *p, bGPDframe *gpf, bGPDstroke *gps, const float mval[2], const int radius, const rcti *rect)
static void annotation_draw_eraser(bContext *UNUSED(C), int x, int y, void *p_ptr)
static tGPsdata * annotation_stroke_begin(bContext *C, wmOperator *op)
static void annotation_get_3d_reference(tGPsdata *p, float vec[3])
static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx)
static bool annotation_session_initdata(bContext *C, tGPsdata *p)
eGPencil_PaintFlags
@ GP_PAINTFLAG_SELECTMASK
@ GP_PAINTFLAG_USE_STABILIZER
@ GP_PAINTFLAG_FIRSTRUN
@ GP_PAINTFLAG_STROKEADDED
@ GP_PAINTFLAG_V3D_ERASER_DEPTH
@ GP_PAINTFLAG_USE_STABILIZER_TEMP
static void annotation_stroke_end(wmOperator *op)
static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void annotation_stroke_newfrombuffer(tGPsdata *p)
static bool annotation_draw_poll(bContext *C)
static bool annotation_stroke_filtermval(tGPsdata *p, const float mval[2], const float pmval[2])
struct tGPsdata tGPsdata
static int annotation_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void annotation_arrow_create_segm(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float arrow_points[8])
static void annotation_stroke_added_enable(tGPsdata *p)
static bool annotation_area_exists(bContext *C, ScrArea *area_test)
static void annotation_add_missing_events(bContext *C, wmOperator *op, const wmEvent *event, tGPsdata *p)
static void annotation_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Depsgraph *depsgraph)
static void annotation_stroke_arrow_init_point(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx)
static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr)
static void annotation_draw_exit(bContext *C, wmOperator *op)
static bool annotation_stroke_added_check(tGPsdata *p)
static void annotation_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints)
static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8], const float ref_point[2], const float dir_cw[2], const float dir_ccw[2], const float length, const float sign)
static void annotation_paint_strokeend(tGPsdata *p)
static void annotation_draw_toggle_stabilizer_cursor(tGPsdata *p, short enable)
static bool annotation_project_check(tGPsdata *p)
static tGPsdata * annotation_session_initpaint(bContext *C)
static bool annotation_is_tablet_eraser_active(const wmEvent *event)
static void annotation_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph)
static int annotation_draw_init(bContext *C, wmOperator *op, const wmEvent *event)
static void annotation_session_cleanup(tGPsdata *p)
static int annotation_draw_exec(bContext *C, wmOperator *op)
static void annotation_draw_apply_event(wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y)
static void annotation_arrow_create_closed(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float arrow_points[8])
#define MIN_EUCLIDEAN_PX
static void annotation_draw_cancel(bContext *C, wmOperator *op)
static const EnumPropertyItem arrow_types[]
static void annotation_draw_cursor_set(tGPsdata *p)
static void annotation_draw_status_indicators(bContext *C, tGPsdata *p)
static void annotation_visible_on_space(tGPsdata *p)
#define MIN_MANHATTAN_PX
static void annotation_arrow_create_open(tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float corner_point[3], const float arrow_points[8])
eGP_StrokeAdd_Result
@ GP_STROKEADD_INVALID
@ GP_STROKEADD_FULL
@ GP_STROKEADD_NORMAL
@ GP_STROKEADD_OVERFLOW
static void annotation_session_validatebuffer(tGPsdata *p)
static void annotation_stroke_doeraser(tGPsdata *p)
static void annotation_draw_toggle_eraser_cursor(tGPsdata *p, short enable)
static void annotation_session_free(tGPsdata *p)
#define DEPTH_INVALID
static void annotation_stroke_arrow_init_point_default(bGPDspoint *pt)
static void annotation_stroke_convertcoords(tGPsdata *p, const float mval[2], float out[3], float *depth)
static const EnumPropertyItem prop_gpencil_drawmodes[]
static void annotation_free_stroke(bGPDframe *gpf, bGPDstroke *gps)
static void annotation_paint_cleanup(tGPsdata *p)
static void annotation_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3])
unsigned int U
Definition: btGjkEpa3.h:78
Scene scene
const Depsgraph * depsgraph
void gpencil_undo_init(struct bGPdata *gpd)
Definition: gpencil_undo.c:97
eGPencil_PaintModes
@ GP_PAINTMODE_DRAW_POLY
@ GP_PAINTMODE_ERASER
@ GP_PAINTMODE_DRAW
@ GP_PAINTMODE_DRAW_STRAIGHT
void gpencil_undo_push(struct bGPdata *gpd)
Definition: gpencil_undo.c:113
void gpencil_undo_finish(void)
Definition: gpencil_undo.c:164
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)
int ED_gpencil_session_active(void)
Definition: gpencil_undo.c:44
bool ED_gpencil_stroke_can_use_direct(const ScrArea *area, const bGPDstroke *gps)
bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr)
tGPspoint * ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array, int *buffer_size, int *buffer_used, const bool clear)
bGPdata ** ED_annotation_data_get_pointers(const bContext *C, PointerRNA *r_ptr)
uint pos
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
double sign(double arg)
Definition: utility.h:250
static void area(int d1, int d2, int e1, int e2, float weights[2])
T length(const vec_base< T, Size > &a)
T abs(const T &a)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
Definition: rna_access.c:5215
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:5015
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4221
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1534
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
static const int steps
Definition: sky_nishita.cpp:19
void * regiondata
short regiontype
struct bGPDlayer * gpl
struct ARegion * region
struct bGPdata * gpd
struct View2D * v2d
struct ScrArea * area
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct MovieTracking tracking
struct ToolSettings * toolsettings
struct RenderData r
View3DCursor cursor
ListBase spacedata
float unistabmat[4][4]
ListBase strokes
float color[4]
bGPDframe * actframe
bGPDspoint * points
float fill_opacity_fac
float aspect_ratio[2]
bGPDtriangle * triangles
struct MDeformVert * dvert
struct bGPDstroke * next
bGPdata_Runtime runtime
ListBase areabase
float xmin
Definition: DNA_vec_types.h:69
float ymin
Definition: DNA_vec_types.h:70
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
char * align_flag
Scene * scene
ScrArea * area
float stabilizer_factor
short straight[2]
View2D * v2d
PointerRNA ownerPtr
rctf subrect_data
float pressure
eGPencil_PaintStatus status
ViewDepths * depths
float imat[4][4]
float mvalo[2]
float opressure
rctf * subrect
eGPencil_PaintModes paintmode
short keymodifier
double curtime
double inittime
float custom_color[4]
ARegion * region
void * erasercursor
bGPDlayer * gpl
eGPencil_PaintFlags flags
double ocurtime
wmWindow * win
float mat[4][4]
Main * bmain
bGPdata * gpd
GP_SpaceConversion gsc
bGPDframe * gpf
float mval[2]
char stabilizer_radius
void * stabilizer_cursor
struct Depsgraph * depsgraph
short radius
float pressure
Definition: ED_gpencil.h:83
float m_xy[2]
Definition: ED_gpencil.h:81
float time
Definition: ED_gpencil.h:87
float strength
Definition: ED_gpencil.h:85
short val
Definition: WM_types.h:680
int xy[2]
Definition: WM_types.h:682
int mval[2]
Definition: WM_types.h:684
uint8_t modifier
Definition: WM_types.h:693
wmTabletData tablet
Definition: WM_types.h:705
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:64
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:191
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:200
@ WM_CURSOR_PAINT_BRUSH
Definition: wm_cursors.h:33
@ WM_CURSOR_ERASER
Definition: wm_cursors.h:34
void WM_event_drag_start_mval_fl(const wmEvent *event, const ARegion *region, float r_mval[2])
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ EVT_TABLET_NONE
@ EVT_TABLET_ERASER
#define ISMOUSE_MOTION(event_type)
@ EVT_PAD8
@ EVT_PAD2
@ RIGHTMOUSE
@ EVT_EKEY
@ EVT_PAD4
@ EVT_PAD0
@ EVT_PAD9
@ EVT_DOWNARROWKEY
@ EVT_PAD3
@ WHEELUPMOUSE
@ EVT_RIGHTARROWKEY
@ EVT_PADENTER
@ EVT_SPACEKEY
@ WHEELDOWNMOUSE
@ EVT_PAD6
@ EVT_PAD5
@ EVT_PADMINUS
@ EVT_UPARROWKEY
@ LEFTMOUSE
@ EVT_LEFTARROWKEY
@ NDOF_MOTION
@ EVT_ZKEY
@ EVT_ESCKEY
@ EVT_PAD1
@ EVT_PAD7
@ EVT_PADPLUSKEY
@ EVT_BKEY
@ EVT_RETKEY
#define ISKEYBOARD(event_type)
wmOperatorType * ot
Definition: wm_files.c:3479
bool WM_paint_cursor_end(wmPaintCursor *handle)
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)