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