Blender  V3.3
gpencil_convert.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. */
3 
9 #include <math.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include "MEM_guardedalloc.h"
16 
17 #include "BLI_blenlib.h"
18 #include "BLI_math.h"
19 #include "BLI_rand.h"
20 #include "BLI_utildefines.h"
21 
22 #include "BLT_translation.h"
23 
24 #include "DNA_anim_types.h"
25 #include "DNA_collection_types.h"
26 #include "DNA_curve_types.h"
27 #include "DNA_gpencil_types.h"
28 #include "DNA_material_types.h"
29 #include "DNA_node_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_space_types.h"
34 #include "DNA_view3d_types.h"
35 
36 #include "BKE_animsys.h"
37 #include "BKE_collection.h"
38 #include "BKE_context.h"
39 #include "BKE_curve.h"
40 #include "BKE_fcurve.h"
41 #include "BKE_global.h"
42 #include "BKE_gpencil.h"
43 #include "BKE_gpencil_geom.h"
44 #include "BKE_image.h"
45 #include "BKE_layer.h"
46 #include "BKE_main.h"
47 #include "BKE_material.h"
48 #include "BKE_object.h"
49 #include "BKE_report.h"
50 #include "BKE_scene.h"
51 #include "BKE_tracking.h"
52 
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_query.h"
55 
56 #include "UI_interface.h"
57 
58 #include "WM_api.h"
59 #include "WM_types.h"
60 
61 #include "RNA_access.h"
62 #include "RNA_define.h"
63 
64 #include "UI_resources.h"
65 #include "UI_view2d.h"
66 
67 #include "ED_clip.h"
68 #include "ED_gpencil.h"
69 #include "ED_keyframing.h"
70 #include "ED_object.h"
71 #include "ED_view3d.h"
72 
73 #include "gpencil_intern.h"
74 
75 /* ************************************************ */
76 /* Grease Pencil to Data Operator */
77 
78 /* defines for possible modes */
79 enum {
83 };
84 
85 /* Defines for possible timing modes */
86 enum {
91 };
92 
93 /* RNA enum define */
95  {GP_STROKECONVERT_PATH, "PATH", ICON_CURVE_PATH, "Path", "Animation path"},
96  {GP_STROKECONVERT_CURVE, "CURVE", ICON_CURVE_BEZCURVE, "Bezier Curve", "Smooth Bezier curve"},
98  "POLY",
99  ICON_MESH_DATA,
100  "Polygon Curve",
101  "Bezier curve with straight-line segments (vector handles)"},
102  {0, NULL, 0, NULL, NULL},
103 };
104 
106  {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
107  {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
108  {0, NULL, 0, NULL, NULL},
109 };
110 
112  {GP_STROKECONVERT_TIMING_NONE, "NONE", 0, "No Timing", "Ignore timing"},
113  {GP_STROKECONVERT_TIMING_LINEAR, "LINEAR", 0, "Linear", "Simple linear timing"},
115  "FULL",
116  0,
117  "Original",
118  "Use the original timing, gaps included"},
120  "CUSTOMGAP",
121  0,
122  "Custom Gaps",
123  "Use the original timing, but with custom gap lengths (in frames)"},
124  {0, NULL, 0, NULL, NULL},
125 };
126 
128  PointerRNA *ptr,
129  PropertyRNA *UNUSED(prop),
130  bool *UNUSED(r_free))
131 {
132  if (RNA_boolean_get(ptr, "use_timing_data")) {
134  }
136 }
137 
138 /* --- */
139 
140 /* convert the coordinates from the given stroke point into 3d-coordinates
141  * - assumes that the active space is the 3D-View
142  */
144  bGPDlayer *gpl,
145  bGPDstroke *gps,
146  bGPDspoint *source_pt,
147  float p3d[3],
148  const rctf *subrect)
149 {
151  View3D *v3d = CTX_wm_view3d(C);
152  ARegion *region = CTX_wm_region(C);
153  /* TODO(sergey): This function might be called from a loop, but no tagging is happening in it,
154  * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the
155  * parameters are to wrapped into a context style struct and queried from Context once. */
157  Object *obact = CTX_data_active_object(C);
158  bGPDspoint mypt, *pt;
159 
160  float diff_mat[4][4];
161  pt = &mypt;
162 
163  /* apply parent transform */
164  float fpt[3];
165  BKE_gpencil_layer_transform_matrix_get(depsgraph, obact, gpl, diff_mat);
166  mul_v3_m4v3(fpt, diff_mat, &source_pt->x);
167  copy_v3_v3(&pt->x, fpt);
168 
169  if (gps->flag & GP_STROKE_3DSPACE) {
170  /* directly use 3d-coordinates */
171  copy_v3_v3(p3d, &pt->x);
172  }
173  else {
174  const float *fp = scene->cursor.location;
175  float mvalf[2];
176 
177  /* get screen coordinate */
178  if (gps->flag & GP_STROKE_2DSPACE) {
179  View2D *v2d = &region->v2d;
180  UI_view2d_view_to_region_fl(v2d, pt->x, pt->y, &mvalf[0], &mvalf[1]);
181  }
182  else {
183  if (subrect) {
184  mvalf[0] = (((float)pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
185  mvalf[1] = (((float)pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
186  }
187  else {
188  mvalf[0] = (float)pt->x / 100.0f * region->winx;
189  mvalf[1] = (float)pt->y / 100.0f * region->winy;
190  }
191  }
192 
193  ED_view3d_win_to_3d(v3d, region, fp, mvalf, p3d);
194  }
195 }
196 
197 /* --- */
198 
199 /* temp struct for gp_stroke_path_animation() */
200 typedef struct tGpTimingData {
201  /* Data set from operator settings */
202  int mode;
203  int frame_range; /* Number of frames evaluated for path animation */
205  bool realtime; /* Will overwrite end_frame in case of Original or CustomGap timing... */
206  float gap_duration, gap_randomness; /* To be used with CustomGap mode. */
207  int seed;
208 
209  /* Data set from points, used to compute final timing FCurve */
211 
212  /* Distances */
213  float *dists;
214  float tot_dist;
215 
216  /* Times */
217  float *times; /* NOTE: Gap times will be negative! */
219  double inittime;
220 
221  /* Only used during creation of dists & times lists. */
222  float offset_time;
223 
224  /* Curve bevel. */
225  float bevel_depth;
228 
229 /* Init point buffers for timing data.
230  * Note this assumes we only grow those arrays!
231  */
232 static void gpencil_timing_data_set_num(tGpTimingData *gtd, const int num)
233 {
234  float *tmp;
235 
236  BLI_assert(num > gtd->points_num);
237 
238  /* distances */
239  tmp = gtd->dists;
240  gtd->dists = MEM_callocN(sizeof(float) * num, __func__);
241  if (tmp) {
242  memcpy(gtd->dists, tmp, sizeof(float) * gtd->points_num);
243  MEM_freeN(tmp);
244  }
245 
246  /* times */
247  tmp = gtd->times;
248  gtd->times = MEM_callocN(sizeof(float) * num, __func__);
249  if (tmp) {
250  memcpy(gtd->times, tmp, sizeof(float) * gtd->points_num);
251  MEM_freeN(tmp);
252  }
253 
254  gtd->points_num = num;
255 }
256 
257 /* add stroke point to timing buffers */
259  const double stroke_inittime,
260  const float time,
261  const float delta_dist)
262 {
263  float delta_time = 0.0f;
264  const int cur_point = gtd->cur_point;
265 
266  if (!cur_point) {
267  /* Special case, first point, if time is not 0.0f we have to compensate! */
268  gtd->offset_time = -time;
269  gtd->times[cur_point] = 0.0f;
270  }
271  else if (time < 0.0f) {
272  /* This is a gap, negative value! */
273  gtd->times[cur_point] = -(((float)(stroke_inittime - gtd->inittime)) + time +
274  gtd->offset_time);
275  delta_time = -gtd->times[cur_point] - gtd->times[cur_point - 1];
276 
277  gtd->gap_tot_time += delta_time;
278  }
279  else {
280  gtd->times[cur_point] = (((float)(stroke_inittime - gtd->inittime)) + time + gtd->offset_time);
281  delta_time = gtd->times[cur_point] - fabsf(gtd->times[cur_point - 1]);
282  }
283 
284  gtd->tot_time += delta_time;
285  gtd->tot_dist += delta_dist;
286  gtd->dists[cur_point] = gtd->tot_dist;
287 
288  gtd->cur_point++;
289 }
290 
291 /* In frames! Binary search for FCurve keys have a threshold of 0.01, so we can't set
292  * arbitrarily close points - this is esp. important with NoGaps mode!
293  */
294 #define MIN_TIME_DELTA 0.02f
295 
296 /* Loop over next points to find the end of the stroke, and compute */
298  RNG *rng,
299  const int idx,
300  const int gaps_count,
301  int *gaps_done_count,
302  const float tot_gaps_time,
303  const float delta_time,
304  float *next_delta_time)
305 {
306  int j;
307 
308  for (j = idx + 1; j < gtd->points_num; j++) {
309  if (gtd->times[j] < 0) {
310  gtd->times[j] = -gtd->times[j];
312  /* In this mode, gap time between this stroke and the next should be 0 currently...
313  * So we have to compute its final duration!
314  */
315  if (gtd->gap_randomness > 0.0f) {
316  /* We want gaps that are in gtd->gap_duration +/- gtd->gap_randomness range,
317  * and which sum to exactly tot_gaps_time...
318  */
319  int rem_gaps = gaps_count - (*gaps_done_count);
320  if (rem_gaps < 2) {
321  /* Last gap, just give remaining time! */
322  *next_delta_time = tot_gaps_time;
323  }
324  else {
325  float delta, min, max;
326 
327  /* This code ensures that if the first gaps
328  * have been shorter than average gap_duration, next gaps
329  * will tend to be longer (i.e. try to recover the lateness), and vice-versa! */
330  delta = delta_time - (gtd->gap_duration * (*gaps_done_count));
331 
332  /* Clamp min between [-gap_randomness, 0.0], with lower delta giving higher min */
333  min = -gtd->gap_randomness - delta;
334  CLAMP(min, -gtd->gap_randomness, 0.0f);
335 
336  /* Clamp max between [0.0, gap_randomness], with lower delta giving higher max */
337  max = gtd->gap_randomness - delta;
338  CLAMP(max, 0.0f, gtd->gap_randomness);
339  *next_delta_time += gtd->gap_duration + (BLI_rng_get_float(rng) * (max - min)) + min;
340  }
341  }
342  else {
343  *next_delta_time += gtd->gap_duration;
344  }
345  }
346  (*gaps_done_count)++;
347  break;
348  }
349  }
350 
351  return j - 1;
352 }
353 
355  RNG *rng,
356  int *gaps_count,
357  float *r_tot_gaps_time)
358 {
359  float delta_time = 0.0f;
360 
361  for (int i = 0; i < gtd->points_num; i++) {
362  if (gtd->times[i] < 0 && i) {
363  (*gaps_count)++;
364  gtd->times[i] = -gtd->times[i] - delta_time;
365  delta_time += gtd->times[i] - gtd->times[i - 1];
366  gtd->times[i] = -gtd->times[i - 1]; /* Temp marker, values *have* to be different! */
367  }
368  else {
369  gtd->times[i] -= delta_time;
370  }
371  }
372  gtd->tot_time -= delta_time;
373 
374  *r_tot_gaps_time = (float)(*gaps_count) * gtd->gap_duration;
375  gtd->tot_time += *r_tot_gaps_time;
376  if (gtd->gap_randomness > 0.0f) {
377  BLI_rng_srandom(rng, gtd->seed);
378  }
379 }
380 
382  PointerRNA ptr,
383  PropertyRNA *prop,
385  FCurve *fcu,
386  Curve *cu,
387  tGpTimingData *gtd,
388  RNG *rng,
389  const float time_range,
390  const int gaps_count,
391  const float tot_gaps_time)
392 {
393  /* Use actual recorded timing! */
394  const float time_start = (float)gtd->start_frame;
395 
396  float last_valid_time = 0.0f;
397  int end_stroke_idx = -1, start_stroke_idx = 0;
398  float end_stroke_time = 0.0f;
399 
400  /* CustomGaps specific */
401  float delta_time = 0.0f, next_delta_time = 0.0f;
402  int gaps_done_count = 0;
403 
404  /* This is a bit tricky, as:
405  * - We can't add arbitrarily close points on FCurve (in time).
406  * - We *must* have all "caps" points of all strokes in FCurve, as much as possible!
407  */
408  for (int i = 0; i < gtd->points_num; i++) {
409  /* If new stroke... */
410  if (i > end_stroke_idx) {
411  start_stroke_idx = i;
412  delta_time = next_delta_time;
413  /* find end of that new stroke */
414  end_stroke_idx = gpencil_find_end_of_stroke_idx(
415  gtd, rng, i, gaps_count, &gaps_done_count, tot_gaps_time, delta_time, &next_delta_time);
416  /* This one should *never* be negative! */
417  end_stroke_time = time_start +
418  ((gtd->times[end_stroke_idx] + delta_time) / gtd->tot_time * time_range);
419  }
420 
421  /* Simple proportional stuff... */
422  cu->ctime = gtd->dists[i] / gtd->tot_dist * cu->pathlen;
423  float cfra = time_start + ((gtd->times[i] + delta_time) / gtd->tot_time * time_range);
424 
425  /* And now, the checks about timing... */
426  if (i == start_stroke_idx) {
427  /* If first point of a stroke, be sure it's enough ahead of last valid keyframe, and
428  * that the end point of the stroke is far enough!
429  * In case it is not, we keep the end point...
430  * Note that with CustomGaps mode, this is here we set the actual gap timing!
431  */
432  if ((end_stroke_time - last_valid_time) > MIN_TIME_DELTA * 2) {
433  if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
434  cfra = last_valid_time + MIN_TIME_DELTA;
435  }
437  depsgraph, cfra);
438  insert_keyframe_direct(reports,
439  ptr,
440  prop,
441  fcu,
442  &anim_eval_context,
444  NULL,
446  last_valid_time = cfra;
447  }
448  }
449  else if (i == end_stroke_idx) {
450  /* Always try to insert end point of a curve (should be safe enough, anyway...) */
451  if ((cfra - last_valid_time) < MIN_TIME_DELTA) {
452  cfra = last_valid_time + MIN_TIME_DELTA;
453  }
455  cfra);
456  insert_keyframe_direct(reports,
457  ptr,
458  prop,
459  fcu,
460  &anim_eval_context,
462  NULL,
464  last_valid_time = cfra;
465  }
466  else {
467  /* Else ("middle" point), we only insert it if it's far enough from last keyframe,
468  * and also far enough from (not yet added!) end_stroke keyframe!
469  */
470  if ((cfra - last_valid_time) > MIN_TIME_DELTA && (end_stroke_time - cfra) > MIN_TIME_DELTA) {
472  depsgraph, cfra);
473  insert_keyframe_direct(reports,
474  ptr,
475  prop,
476  fcu,
477  &anim_eval_context,
479  NULL,
481  last_valid_time = cfra;
482  }
483  else if (G.debug & G_DEBUG) {
484  printf(
485  "\t Skipping \"middle\" point %d, too close from last added point or end point %d\n",
486  i,
487  end_stroke_idx);
488  }
489  }
490  }
491 }
492 
494  ReportList *reports,
495  Curve *cu,
496  tGpTimingData *gtd)
497 {
498  Main *bmain = CTX_data_main(C);
501  bAction *act;
502  FCurve *fcu;
503  PointerRNA ptr;
504  PropertyRNA *prop = NULL;
505  int gaps_count = 0;
506 
507  if (gtd->mode == GP_STROKECONVERT_TIMING_NONE) {
508  return;
509  }
510 
511  /* gap_duration and gap_randomness are in frames, but we need seconds!!! */
512  gtd->gap_duration = FRA2TIME(gtd->gap_duration);
514 
515  /* Enable path! */
516  cu->flag |= CU_PATH;
517  cu->pathlen = gtd->frame_range;
518 
519  /* Get RNA pointer to read/write path time values */
520  RNA_id_pointer_create((ID *)cu, &ptr);
521  prop = RNA_struct_find_property(&ptr, "eval_time");
522 
523  /* Ensure we have an F-Curve to add keyframes to */
524  act = ED_id_action_ensure(bmain, (ID *)cu);
525  fcu = ED_action_fcurve_ensure(bmain, act, NULL, &ptr, "eval_time", 0);
526 
527  if (gtd->mode == GP_STROKECONVERT_TIMING_LINEAR) {
528  float cfra;
529 
530  /* Linear extrapolation! */
532 
533  cu->ctime = 0.0f;
534  cfra = (float)gtd->start_frame;
536  cfra);
537  insert_keyframe_direct(reports,
538  ptr,
539  prop,
540  fcu,
541  &anim_eval_context_start,
543  NULL,
545 
546  cu->ctime = cu->pathlen;
547  if (gtd->realtime) {
548  cfra += (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
549  }
550  else {
551  cfra = (float)gtd->end_frame;
552  }
554  cfra);
555  insert_keyframe_direct(reports,
556  ptr,
557  prop,
558  fcu,
559  &anim_eval_context_end,
561  NULL,
563  }
564  else {
565  /* Use actual recorded timing! */
566  RNG *rng = BLI_rng_new(0);
567  float time_range;
568 
569  /* CustomGaps specific */
570  float tot_gaps_time = 0.0f;
571 
572  /* Pre-process gaps, in case we don't want to keep their original timing */
574  gpencil_stroke_path_animation_preprocess_gaps(gtd, rng, &gaps_count, &tot_gaps_time);
575  }
576 
577  if (gtd->realtime) {
578  time_range = (float)TIME2FRA(gtd->tot_time); /* Seconds to frames */
579  }
580  else {
581  time_range = (float)(gtd->end_frame - gtd->start_frame);
582  }
583 
585  reports, ptr, prop, depsgraph, fcu, cu, gtd, rng, time_range, gaps_count, tot_gaps_time);
586 
587  BLI_rng_free(rng);
588  }
589 
590  /* As we used INSERTKEY_FAST mode, we need to recompute all curve's handles now */
592 
594 
595  /* send updates */
596  DEG_id_tag_update(&cu->id, 0);
597 }
598 
599 #undef MIN_TIME_DELTA
600 
601 #define GAP_DFAC 0.01f
602 #define WIDTH_CORR_FAC 0.1f
603 #define BEZT_HANDLE_FAC 0.3f
604 
605 /* convert stroke to 3d path */
606 
607 /* helper */
609  BPoint *bp,
610  const float p[3],
611  const float prev_p[3],
612  const bool do_gtd,
613  const double inittime,
614  const float time,
615  const float width,
616  const float rad_fac,
617  float minmax_weights[2])
618 {
619  copy_v3_v3(bp->vec, p);
620  bp->vec[3] = 1.0f;
621 
622  /* set settings */
623  bp->f1 = SELECT;
624  bp->radius = width * rad_fac;
625  bp->weight = width;
626  CLAMP(bp->weight, 0.0f, 1.0f);
627  if (bp->weight < minmax_weights[0]) {
628  minmax_weights[0] = bp->weight;
629  }
630  else if (bp->weight > minmax_weights[1]) {
631  minmax_weights[1] = bp->weight;
632  }
633 
634  /* Update timing data */
635  if (do_gtd) {
636  gpencil_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
637  }
638 }
639 
641  bGPDlayer *gpl,
642  bGPDstroke *gps,
643  Curve *cu,
644  rctf *subrect,
645  Nurb **curnu,
646  float minmax_weights[2],
647  const float rad_fac,
648  bool stitch,
649  const bool add_start_point,
650  const bool add_end_point,
651  tGpTimingData *gtd)
652 {
653  bGPDspoint *pt;
654  Nurb *nu = (curnu) ? *curnu : NULL;
655  BPoint *bp, *prev_bp = NULL;
656  const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
657  const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
658  int i, old_nbp = 0;
659 
660  /* create new 'nurb' or extend current one within the curve */
661  if (nu) {
662  old_nbp = nu->pntsu;
663 
664  /* If stitch, the first point of this stroke is already present in current nu.
665  * Else, we have to add two additional points to make the zero-radius link between strokes.
666  */
667  BKE_nurb_points_add(nu, gps->totpoints + (stitch ? -1 : 2) + add_start_end_points);
668  }
669  else {
670  nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_path(nurb)");
671 
672  nu->pntsu = gps->totpoints + add_start_end_points;
673  nu->pntsv = 1;
674  nu->orderu = 2; /* point-to-point! */
675  nu->type = CU_NURBS;
676  nu->flagu = CU_NURB_ENDPOINT;
677  nu->resolu = cu->resolu;
678  nu->resolv = cu->resolv;
679  nu->knotsu = NULL;
680 
681  nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "bpoints");
682 
683  stitch = false; /* Security! */
684  }
685 
686  if (do_gtd) {
688  }
689 
690  /* If needed, make the link between both strokes with two zero-radius additional points */
691  /* About "zero-radius" point interpolations:
692  * - If we have at least two points in current curve (most common case), we linearly extrapolate
693  * the last segment to get the first point (p1) position and timing.
694  * - If we do not have those (quite odd, but may happen), we linearly interpolate the last point
695  * with the first point of the current stroke.
696  *
697  * The same goes for the second point, first segment of the current stroke is "negatively"
698  * extrapolated if it exists, else (if the stroke is a single point),
699  * linear interpolation with last curve point.
700  */
701  if (curnu && !stitch && old_nbp) {
702  float p1[3], p2[3], p[3], next_p[3];
703  float dt1 = 0.0f, dt2 = 0.0f;
704 
705  BLI_assert(gps->prev != NULL);
706 
707  prev_bp = NULL;
708  if ((old_nbp > 1) && (gps->prev->totpoints > 1)) {
709  /* Only use last curve segment if previous stroke was not a single-point one! */
710  prev_bp = &nu->bp[old_nbp - 2];
711  }
712  bp = &nu->bp[old_nbp - 1];
713 
714  /* First point */
715  gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
716  if (prev_bp) {
717  interp_v3_v3v3(p1, bp->vec, prev_bp->vec, -GAP_DFAC);
718  if (do_gtd) {
719  const int idx = gps->prev->totpoints - 1;
720  dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
721  }
722  }
723  else {
724  interp_v3_v3v3(p1, bp->vec, p, GAP_DFAC);
725  if (do_gtd) {
726  dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
727  }
728  }
729  bp++;
731  bp,
732  p1,
733  (bp - 1)->vec,
734  do_gtd,
735  gps->prev->inittime,
736  dt1,
737  0.0f,
738  rad_fac,
739  minmax_weights);
740 
741  /* Second point */
742  /* Note dt2 is always negative, which marks the gap. */
743  if (gps->totpoints > 1) {
744  gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
745  interp_v3_v3v3(p2, p, next_p, -GAP_DFAC);
746  if (do_gtd) {
747  dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
748  }
749  }
750  else {
751  interp_v3_v3v3(p2, p, bp->vec, GAP_DFAC);
752  if (do_gtd) {
753  dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
754  }
755  }
756  bp++;
758  gtd, bp, p2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
759 
760  old_nbp += 2;
761  }
762  else if (add_start_point) {
763  float p[3], next_p[3];
764  float dt = 0.0f;
765 
766  gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points, p, subrect);
767  if (gps->totpoints > 1) {
768  gpencil_strokepoint_convertcoords(C, gpl, gps, gps->points + 1, next_p, subrect);
769  interp_v3_v3v3(p, p, next_p, -GAP_DFAC);
770  if (do_gtd) {
771  dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
772  }
773  }
774  else {
775  p[0] -= GAP_DFAC; /* Rather arbitrary... */
776  dt = -GAP_DFAC; /* Rather arbitrary too! */
777  }
778  bp = &nu->bp[old_nbp];
779  /* Note we can't give anything else than 0.0 as time here, since a negative one
780  * (which would be expected value) would not work
781  * (it would be *before* gtd->inittime, which is not supported currently).
782  */
784  gtd, bp, p, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
785 
786  old_nbp++;
787  }
788 
789  if (old_nbp) {
790  prev_bp = &nu->bp[old_nbp - 1];
791  }
792 
793  /* add points */
794  for (i = (stitch) ? 1 : 0, pt = &gps->points[(stitch) ? 1 : 0], bp = &nu->bp[old_nbp];
795  i < gps->totpoints;
796  i++, pt++, bp++) {
797  float p[3];
798  float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
799 
800  /* get coordinates to add at */
801  gpencil_strokepoint_convertcoords(C, gpl, gps, pt, p, subrect);
802 
804  bp,
805  p,
806  (prev_bp) ? prev_bp->vec : p,
807  do_gtd,
808  gps->inittime,
809  pt->time,
810  width,
811  rad_fac,
812  minmax_weights);
813 
814  prev_bp = bp;
815  }
816 
817  if (add_end_point) {
818  float p[3];
819  float dt = 0.0f;
820 
821  if (gps->totpoints > 1) {
822  interp_v3_v3v3(p, prev_bp->vec, (prev_bp - 1)->vec, -GAP_DFAC);
823  if (do_gtd) {
824  const int idx = gps->totpoints - 1;
825  dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
826  }
827  }
828  else {
829  copy_v3_v3(p, prev_bp->vec);
830  p[0] += GAP_DFAC; /* Rather arbitrary... */
831  dt = GAP_DFAC; /* Rather arbitrary too! */
832  }
833  /* Note bp has already been incremented in main loop above, so it points to the right place. */
835  gtd, bp, p, prev_bp->vec, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
836  }
837 
838  /* add nurb to curve */
839  if (!curnu || !*curnu) {
840  BLI_addtail(&cu->nurb, nu);
841  }
842  if (curnu) {
843  *curnu = nu;
844  }
845 
847 }
848 
849 /* convert stroke to 3d bezier */
850 
851 /* helper */
853  BezTriple *bezt,
854  const float p[3],
855  const float h1[3],
856  const float h2[3],
857  const float prev_p[3],
858  const bool do_gtd,
859  const double inittime,
860  const float time,
861  const float width,
862  const float rad_fac,
863  float minmax_weights[2])
864 {
865  copy_v3_v3(bezt->vec[0], h1);
866  copy_v3_v3(bezt->vec[1], p);
867  copy_v3_v3(bezt->vec[2], h2);
868 
869  /* set settings */
870  bezt->h1 = bezt->h2 = HD_FREE;
871  bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
872  bezt->radius = width * rad_fac;
873  bezt->weight = width;
874  CLAMP(bezt->weight, 0.0f, 1.0f);
875  if (bezt->weight < minmax_weights[0]) {
876  minmax_weights[0] = bezt->weight;
877  }
878  else if (bezt->weight > minmax_weights[1]) {
879  minmax_weights[1] = bezt->weight;
880  }
881 
882  /* Update timing data */
883  if (do_gtd) {
884  gpencil_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
885  }
886 }
887 
889  bGPDlayer *gpl,
890  bGPDstroke *gps,
891  Curve *cu,
892  rctf *subrect,
893  Nurb **curnu,
894  float minmax_weights[2],
895  const float rad_fac,
896  bool stitch,
897  const bool add_start_point,
898  const bool add_end_point,
899  tGpTimingData *gtd)
900 {
901  bGPDspoint *pt;
902  Nurb *nu = (curnu) ? *curnu : NULL;
903  BezTriple *bezt, *prev_bezt = NULL;
904  int i, tot, old_nbezt = 0;
905  const int add_start_end_points = (add_start_point ? 1 : 0) + (add_end_point ? 1 : 0);
906  float p3d_cur[3], p3d_prev[3], p3d_next[3], h1[3], h2[3];
907  const bool do_gtd = (gtd->mode != GP_STROKECONVERT_TIMING_NONE);
908 
909  /* create new 'nurb' or extend current one within the curve */
910  if (nu) {
911  old_nbezt = nu->pntsu;
912  /* If we do stitch, first point of current stroke is assumed the same as last point of
913  * previous stroke, so no need to add it.
914  * If no stitch, we want to add two additional points to make a "zero-radius"
915  * link between both strokes.
916  */
917  BKE_nurb_bezierPoints_add(nu, gps->totpoints + ((stitch) ? -1 : 2) + add_start_end_points);
918  }
919  else {
920  nu = (Nurb *)MEM_callocN(sizeof(Nurb), "gpstroke_to_bezier(nurb)");
921 
922  nu->pntsu = gps->totpoints + add_start_end_points;
923  nu->resolu = 12;
924  nu->resolv = 12;
925  nu->type = CU_BEZIER;
926  nu->bezt = (BezTriple *)MEM_callocN(sizeof(BezTriple) * nu->pntsu, "bezts");
927 
928  stitch = false; /* Security! */
929  }
930 
931  if (do_gtd) {
933  }
934 
935  tot = gps->totpoints;
936 
937  /* get initial coordinates */
938  pt = gps->points;
939  if (tot) {
940  gpencil_strokepoint_convertcoords(C, gpl, gps, pt, (stitch) ? p3d_prev : p3d_cur, subrect);
941  if (tot > 1) {
943  C, gpl, gps, pt + 1, (stitch) ? p3d_cur : p3d_next, subrect);
944  }
945  if (stitch && tot > 2) {
946  gpencil_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
947  }
948  }
949 
950  /* If needed, make the link between both strokes with two zero-radius additional points */
951  if (curnu && old_nbezt) {
952  BLI_assert(gps->prev != NULL);
953 
954  /* Update last point's second handle */
955  if (stitch) {
956  bezt = &nu->bezt[old_nbezt - 1];
957  interp_v3_v3v3(h2, bezt->vec[1], p3d_cur, BEZT_HANDLE_FAC);
958  copy_v3_v3(bezt->vec[2], h2);
959  pt++;
960  }
961 
962  /* Create "link points" */
963  /* About "zero-radius" point interpolations:
964  * - If we have at least two points in current curve (most common case),
965  * we linearly extrapolate the last segment to get the first point (p1) position and timing.
966  * - If we do not have those (quite odd, but may happen),
967  * we linearly interpolate the last point with the first point of the current stroke.
968  *
969  * The same goes for the second point,
970  * first segment of the current stroke is "negatively" extrapolated
971  * if it exists, else (if the stroke is a single point),
972  * linear interpolation with last curve point.
973  */
974  else {
975  float p1[3], p2[3];
976  float dt1 = 0.0f, dt2 = 0.0f;
977 
978  prev_bezt = NULL;
979  if ((old_nbezt > 1) && (gps->prev->totpoints > 1)) {
980  /* Only use last curve segment if previous stroke was not a single-point one! */
981  prev_bezt = &nu->bezt[old_nbezt - 2];
982  }
983  bezt = &nu->bezt[old_nbezt - 1];
984 
985  /* First point */
986  if (prev_bezt) {
987  interp_v3_v3v3(p1, prev_bezt->vec[1], bezt->vec[1], 1.0f + GAP_DFAC);
988  if (do_gtd) {
989  const int idx = gps->prev->totpoints - 1;
990  dt1 = interpf(gps->prev->points[idx - 1].time, gps->prev->points[idx].time, -GAP_DFAC);
991  }
992  }
993  else {
994  interp_v3_v3v3(p1, bezt->vec[1], p3d_cur, GAP_DFAC);
995  if (do_gtd) {
996  dt1 = interpf(gps->inittime - gps->prev->inittime, 0.0f, GAP_DFAC);
997  }
998  }
999 
1000  /* Second point */
1001  /* Note dt2 is always negative, which marks the gap. */
1002  if (tot > 1) {
1003  interp_v3_v3v3(p2, p3d_cur, p3d_next, -GAP_DFAC);
1004  if (do_gtd) {
1005  dt2 = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
1006  }
1007  }
1008  else {
1009  interp_v3_v3v3(p2, p3d_cur, bezt->vec[1], GAP_DFAC);
1010  if (do_gtd) {
1011  dt2 = interpf(gps->prev->inittime - gps->inittime, 0.0f, GAP_DFAC);
1012  }
1013  }
1014 
1015  /* Second handle of last point of previous stroke. */
1016  interp_v3_v3v3(h2, bezt->vec[1], p1, BEZT_HANDLE_FAC);
1017  copy_v3_v3(bezt->vec[2], h2);
1018 
1019  /* First point */
1020  interp_v3_v3v3(h1, p1, bezt->vec[1], BEZT_HANDLE_FAC);
1021  interp_v3_v3v3(h2, p1, p2, BEZT_HANDLE_FAC);
1022  bezt++;
1024  bezt,
1025  p1,
1026  h1,
1027  h2,
1028  (bezt - 1)->vec[1],
1029  do_gtd,
1030  gps->prev->inittime,
1031  dt1,
1032  0.0f,
1033  rad_fac,
1034  minmax_weights);
1035 
1036  /* Second point */
1037  interp_v3_v3v3(h1, p2, p1, BEZT_HANDLE_FAC);
1038  interp_v3_v3v3(h2, p2, p3d_cur, BEZT_HANDLE_FAC);
1039  bezt++;
1041  gtd, bezt, p2, h1, h2, p1, do_gtd, gps->inittime, dt2, 0.0f, rad_fac, minmax_weights);
1042 
1043  old_nbezt += 2;
1044  copy_v3_v3(p3d_prev, p2);
1045  }
1046  }
1047  else if (add_start_point) {
1048  float p[3];
1049  float dt = 0.0f;
1050 
1051  if (gps->totpoints > 1) {
1052  interp_v3_v3v3(p, p3d_cur, p3d_next, -GAP_DFAC);
1053  if (do_gtd) {
1054  dt = interpf(gps->points[1].time, gps->points[0].time, -GAP_DFAC);
1055  }
1056  }
1057  else {
1058  copy_v3_v3(p, p3d_cur);
1059  p[0] -= GAP_DFAC; /* Rather arbitrary... */
1060  dt = -GAP_DFAC; /* Rather arbitrary too! */
1061  }
1062  interp_v3_v3v3(h1, p, p3d_cur, -BEZT_HANDLE_FAC);
1063  interp_v3_v3v3(h2, p, p3d_cur, BEZT_HANDLE_FAC);
1064  bezt = &nu->bezt[old_nbezt];
1066  gtd, bezt, p, h1, h2, p, do_gtd, gps->inittime, dt, 0.0f, rad_fac, minmax_weights);
1067 
1068  old_nbezt++;
1069  copy_v3_v3(p3d_prev, p);
1070  }
1071 
1072  if (old_nbezt) {
1073  prev_bezt = &nu->bezt[old_nbezt - 1];
1074  }
1075 
1076  /* add points */
1077  for (i = stitch ? 1 : 0, bezt = &nu->bezt[old_nbezt]; i < tot; i++, pt++, bezt++) {
1078  float width = pt->pressure * (gps->thickness + gpl->line_change) * WIDTH_CORR_FAC;
1079 
1080  if (i || old_nbezt) {
1081  interp_v3_v3v3(h1, p3d_cur, p3d_prev, BEZT_HANDLE_FAC);
1082  }
1083  else {
1084  interp_v3_v3v3(h1, p3d_cur, p3d_next, -BEZT_HANDLE_FAC);
1085  }
1086 
1087  if (i < tot - 1) {
1088  interp_v3_v3v3(h2, p3d_cur, p3d_next, BEZT_HANDLE_FAC);
1089  }
1090  else {
1091  interp_v3_v3v3(h2, p3d_cur, p3d_prev, -BEZT_HANDLE_FAC);
1092  }
1093 
1095  bezt,
1096  p3d_cur,
1097  h1,
1098  h2,
1099  prev_bezt ? prev_bezt->vec[1] : p3d_cur,
1100  do_gtd,
1101  gps->inittime,
1102  pt->time,
1103  width,
1104  rad_fac,
1105  minmax_weights);
1106 
1107  /* Shift coord vectors. */
1108  copy_v3_v3(p3d_prev, p3d_cur);
1109  copy_v3_v3(p3d_cur, p3d_next);
1110 
1111  if (i + 2 < tot) {
1112  gpencil_strokepoint_convertcoords(C, gpl, gps, pt + 2, p3d_next, subrect);
1113  }
1114 
1115  prev_bezt = bezt;
1116  }
1117 
1118  if (add_end_point) {
1119  float p[3];
1120  float dt = 0.0f;
1121 
1122  if (gps->totpoints > 1) {
1123  interp_v3_v3v3(p, prev_bezt->vec[1], (prev_bezt - 1)->vec[1], -GAP_DFAC);
1124  if (do_gtd) {
1125  const int idx = gps->totpoints - 1;
1126  dt = interpf(gps->points[idx - 1].time, gps->points[idx].time, -GAP_DFAC);
1127  }
1128  }
1129  else {
1130  copy_v3_v3(p, prev_bezt->vec[1]);
1131  p[0] += GAP_DFAC; /* Rather arbitrary... */
1132  dt = GAP_DFAC; /* Rather arbitrary too! */
1133  }
1134 
1135  /* Second handle of last point of this stroke. */
1136  interp_v3_v3v3(h2, prev_bezt->vec[1], p, BEZT_HANDLE_FAC);
1137  copy_v3_v3(prev_bezt->vec[2], h2);
1138 
1139  /* The end point */
1140  interp_v3_v3v3(h1, p, prev_bezt->vec[1], BEZT_HANDLE_FAC);
1141  interp_v3_v3v3(h2, p, prev_bezt->vec[1], -BEZT_HANDLE_FAC);
1142  /* Note bezt has already been incremented in main loop above,
1143  * so it points to the right place. */
1145  bezt,
1146  p,
1147  h1,
1148  h2,
1149  prev_bezt->vec[1],
1150  do_gtd,
1151  gps->inittime,
1152  dt,
1153  0.0f,
1154  rad_fac,
1155  minmax_weights);
1156  }
1157 
1158  /* must calculate handles or else we crash */
1160 
1161  if (!curnu || !*curnu) {
1162  BLI_addtail(&cu->nurb, nu);
1163  }
1164  if (curnu) {
1165  *curnu = nu;
1166  }
1167 }
1168 
1169 #undef GAP_DFAC
1170 #undef WIDTH_CORR_FAC
1171 #undef BEZT_HANDLE_FAC
1172 
1174 {
1175  /* start */
1176  Nurb *nu = cu->nurb.first;
1177  int i = 0;
1178  if (nu->bezt) {
1179  BezTriple *bezt = nu->bezt;
1180  if (bezt) {
1181  bezt[i].weight = bezt[i].radius = 0.0f;
1182  }
1183  }
1184  else if (nu->bp) {
1185  BPoint *bp = nu->bp;
1186  if (bp) {
1187  bp[i].weight = bp[i].radius = 0.0f;
1188  }
1189  }
1190 
1191  /* end */
1192  nu = cu->nurb.last;
1193  i = nu->pntsu - 1;
1194  if (nu->bezt) {
1195  BezTriple *bezt = nu->bezt;
1196  if (bezt) {
1197  bezt[i].weight = bezt[i].radius = 0.0f;
1198  }
1199  }
1200  else if (nu->bp) {
1201  BPoint *bp = nu->bp;
1202  if (bp) {
1203  bp[i].weight = bp[i].radius = 0.0f;
1204  }
1205  }
1206 }
1207 
1208 static void gpencil_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
1209 {
1210  const float delta = minmax_weights[0];
1211 
1212  /* when delta == minmax_weights[0] == minmax_weights[1], we get div by zero T35686. */
1213  float fac;
1214  if (IS_EQF(delta, minmax_weights[1])) {
1215  fac = 1.0f;
1216  }
1217  else {
1218  fac = 1.0f / (minmax_weights[1] - delta);
1219  }
1220 
1221  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
1222  if (nu->bezt) {
1223  BezTriple *bezt = nu->bezt;
1224  for (int i = 0; i < nu->pntsu; i++, bezt++) {
1225  bezt->weight = (bezt->weight - delta) * fac;
1226  }
1227  }
1228  else if (nu->bp) {
1229  BPoint *bp = nu->bp;
1230  for (int i = 0; i < nu->pntsu; i++, bp++) {
1231  bp->weight = (bp->weight - delta) * fac;
1232  }
1233  }
1234  }
1235 }
1236 
1238 {
1239  View3D *v3d = CTX_wm_view3d(C);
1240  ARegion *region = CTX_wm_region(C);
1241 
1242  if (v3d) {
1243  RegionView3D *rv3d = region->regiondata;
1244 
1245  /* for camera view set the subrect */
1246  if (rv3d->persp == RV3D_CAMOB) {
1249  ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, subrect, true);
1250  return 1;
1251  }
1252  }
1253 
1254  return 0;
1255 }
1256 
1257 /* convert a given grease-pencil layer to a 3d-curve representation
1258  * (using current view if appropriate) */
1260  ReportList *reports,
1261  bGPdata *gpd,
1262  bGPDlayer *gpl,
1263  const int mode,
1264  const bool norm_weights,
1265  const float rad_fac,
1266  const bool link_strokes,
1267  tGpTimingData *gtd)
1268 {
1269  struct Main *bmain = CTX_data_main(C);
1270  ViewLayer *view_layer = CTX_data_view_layer(C);
1271  Collection *collection = CTX_data_collection(C);
1273 
1275  bGPDstroke *prev_gps = NULL;
1276  Object *ob;
1277  Curve *cu;
1278  Nurb *nu = NULL;
1279  Base *base_new = NULL;
1280  float minmax_weights[2] = {1.0f, 0.0f};
1281 
1282  /* camera framing */
1283  rctf subrect, *subrect_ptr = NULL;
1284 
1285  /* error checking */
1286  if (ELEM(NULL, gpd, gpl, gpf)) {
1287  return;
1288  }
1289 
1290  /* only convert if there are any strokes on this layer's frame to convert */
1291  if (BLI_listbase_is_empty(&gpf->strokes)) {
1292  return;
1293  }
1294 
1295  /* initialize camera framing */
1296  if (gpencil_camera_view_subrect(C, &subrect)) {
1297  subrect_ptr = &subrect;
1298  }
1299 
1300  /* init the curve object (remove rotation and get curve data from it)
1301  * - must clear transforms set on object, as those skew our results
1302  */
1304  cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVES_LEGACY);
1305  BKE_collection_object_add(bmain, collection, ob);
1306  base_new = BKE_view_layer_base_find(view_layer, ob);
1307  DEG_relations_tag_update(bmain); /* added object */
1308 
1309  cu->flag |= CU_3D;
1310  cu->bevresol = gtd->bevel_resolution;
1311  cu->bevel_radius = gtd->bevel_depth;
1312 
1313  gtd->inittime = ((bGPDstroke *)gpf->strokes.first)->inittime;
1314 
1315  /* add points to curve */
1316  LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
1317  if (gps->totpoints < 1) {
1318  continue;
1319  }
1320  const bool add_start_point = (link_strokes && !(prev_gps));
1321  const bool add_end_point = (link_strokes && !(gps->next));
1322 
1323  /* Detect new strokes created because of GP_STROKE_BUFFER_MAX reached,
1324  * and stitch them to previous one. */
1325  bool stitch = false;
1326  if (prev_gps) {
1327  bGPDspoint *pt1 = &prev_gps->points[prev_gps->totpoints - 1];
1328  bGPDspoint *pt2 = &gps->points[0];
1329 
1330  if ((pt1->x == pt2->x) && (pt1->y == pt2->y)) {
1331  stitch = true;
1332  }
1333  }
1334 
1335  /* Decide whether we connect this stroke to previous one */
1336  if (!(stitch || link_strokes)) {
1337  nu = NULL;
1338  }
1339 
1340  switch (mode) {
1341  case GP_STROKECONVERT_PATH:
1343  gpl,
1344  gps,
1345  cu,
1346  subrect_ptr,
1347  &nu,
1348  minmax_weights,
1349  rad_fac,
1350  stitch,
1351  add_start_point,
1352  add_end_point,
1353  gtd);
1354  break;
1356  case GP_STROKECONVERT_POLY: /* convert after */
1358  gpl,
1359  gps,
1360  cu,
1361  subrect_ptr,
1362  &nu,
1363  minmax_weights,
1364  rad_fac,
1365  stitch,
1366  add_start_point,
1367  add_end_point,
1368  gtd);
1369  break;
1370  default:
1371  BLI_assert_msg(0, "invalid mode");
1372  break;
1373  }
1374  prev_gps = gps;
1375  }
1376 
1377  /* If link_strokes, be sure first and last points have a zero weight/size! */
1378  if (link_strokes) {
1380  }
1381 
1382  /* Update curve's weights, if needed */
1383  if (norm_weights && ((minmax_weights[0] > 0.0f) || (minmax_weights[1] < 1.0f))) {
1384  gpencil_stroke_norm_curve_weights(cu, minmax_weights);
1385  }
1386 
1387  /* Create the path animation, if needed */
1388  gpencil_stroke_path_animation(C, reports, cu, gtd);
1389 
1390  if (mode == GP_STROKECONVERT_POLY) {
1391  for (nu = cu->nurb.first; nu; nu = nu->next) {
1392  BKE_nurb_type_convert(nu, CU_POLY, false, NULL);
1393  }
1394  }
1395 
1396  ED_object_base_select(base_new, BA_SELECT);
1397 
1399 }
1400 
1401 /* --- */
1402 
1403 /* Check a GP layer has valid timing data! Else, most timing options are hidden in the operator.
1404  * op may be NULL.
1405  */
1407 {
1409 
1410  bGPDframe *gpf = NULL;
1411  bGPDstroke *gps = NULL;
1412  bGPDspoint *pt;
1413  double base_time, cur_time, prev_time = -1.0;
1414  int i;
1415  bool valid = true;
1416 
1417  if (!gpl || !(gpf = BKE_gpencil_layer_frame_get(gpl, scene->r.cfra, GP_GETFRAME_USE_PREV)) ||
1418  !(gps = gpf->strokes.first)) {
1419  return false;
1420  }
1421 
1422  do {
1423  base_time = cur_time = gps->inittime;
1424  if (cur_time <= prev_time) {
1425  valid = false;
1426  break;
1427  }
1428 
1429  prev_time = cur_time;
1430  for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1431  cur_time = base_time + (double)pt->time;
1432  /* First point of a stroke should have the same time as stroke's inittime,
1433  * so it's the only case where equality is allowed!
1434  */
1435  if ((i && cur_time <= prev_time) || (cur_time < prev_time)) {
1436  valid = false;
1437  break;
1438  }
1439  prev_time = cur_time;
1440  }
1441 
1442  if (!valid) {
1443  break;
1444  }
1445  } while ((gps = gps->next));
1446 
1447  if (op) {
1448  RNA_boolean_set(op->ptr, "use_timing_data", valid);
1449  }
1450  return valid;
1451 }
1452 
1453 /* Check end_frame is always > start frame! */
1455  struct Scene *UNUSED(scene),
1456  struct PointerRNA *ptr)
1457 {
1458  int start_frame = RNA_int_get(ptr, "start_frame");
1459  int end_frame = RNA_int_get(ptr, "end_frame");
1460 
1461  if (end_frame <= start_frame) {
1462  RNA_int_set(ptr, "end_frame", start_frame + 1);
1463  }
1464 }
1465 
1467 {
1470 
1471  if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
1472  return false;
1473  }
1474 
1475  bGPdata *gpd = (bGPdata *)ob->data;
1476  bGPDlayer *gpl = NULL;
1477  bGPDframe *gpf = NULL;
1478  ScrArea *area = CTX_wm_area(C);
1479 
1480  /* only if the current view is 3D View, if there's valid data (i.e. at least one stroke!),
1481  * and if we are not in edit mode!
1482  */
1483  return ((area && area->spacetype == SPACE_VIEW3D) && (gpl = BKE_gpencil_layer_active_get(gpd)) &&
1485  (gpf->strokes.first) && (!GPENCIL_ANY_EDIT_MODE(gpd)));
1486 }
1487 
1489 {
1490  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
1492  bGPdata *gpd = (bGPdata *)ob->data;
1493 
1496  const int mode = RNA_enum_get(op->ptr, "type");
1497  const bool norm_weights = RNA_boolean_get(op->ptr, "use_normalize_weights");
1498  const float rad_fac = RNA_float_get(op->ptr, "radius_multiplier");
1499  const bool link_strokes = RNA_boolean_get(op->ptr, "use_link_strokes");
1500  bool valid_timing;
1501  tGpTimingData gtd;
1502 
1503  /* check if there's data to work with */
1504  if (gpd == NULL) {
1505  BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data to work on");
1506  return OPERATOR_CANCELLED;
1507  }
1508 
1509  if (!RNA_property_is_set(op->ptr, prop) && !gpencil_convert_check_has_valid_timing(C, gpl, op)) {
1510  BKE_report(op->reports,
1511  RPT_WARNING,
1512  "Current Grease Pencil strokes have no valid timing data, most timing options will "
1513  "be hidden!");
1514  }
1515  valid_timing = RNA_property_boolean_get(op->ptr, prop);
1516 
1517  gtd.mode = RNA_enum_get(op->ptr, "timing_mode");
1518  /* Check for illegal timing mode! */
1519  if (!valid_timing &&
1522  RNA_enum_set(op->ptr, "timing_mode", gtd.mode);
1523  }
1524  if (!link_strokes) {
1526  }
1527 
1528  /* grab all relevant settings */
1529  gtd.frame_range = RNA_int_get(op->ptr, "frame_range");
1530  gtd.start_frame = RNA_int_get(op->ptr, "start_frame");
1531  gtd.bevel_depth = RNA_float_get(op->ptr, "bevel_depth");
1532  gtd.bevel_resolution = RNA_int_get(op->ptr, "bevel_resolution");
1533  gtd.realtime = valid_timing ? RNA_boolean_get(op->ptr, "use_realtime") : false;
1534  gtd.end_frame = RNA_int_get(op->ptr, "end_frame");
1535  gtd.gap_duration = RNA_float_get(op->ptr, "gap_duration");
1536  gtd.gap_randomness = RNA_float_get(op->ptr, "gap_randomness");
1538  gtd.seed = RNA_int_get(op->ptr, "seed");
1539  gtd.points_num = gtd.cur_point = 0;
1540  gtd.dists = gtd.times = NULL;
1541  gtd.tot_dist = gtd.tot_time = gtd.gap_tot_time = 0.0f;
1542  gtd.inittime = 0.0;
1543  gtd.offset_time = 0.0f;
1544 
1545  /* perform conversion */
1547  C, op->reports, gpd, gpl, mode, norm_weights, rad_fac, link_strokes, &gtd);
1548 
1549  /* free temp memory */
1550  MEM_SAFE_FREE(gtd.dists);
1551  MEM_SAFE_FREE(gtd.times);
1552 
1553  /* notifiers */
1557 
1558  /* done */
1559  return OPERATOR_FINISHED;
1560 }
1561 
1563  wmOperator *op,
1564  const PropertyRNA *prop)
1565 {
1566  PointerRNA *ptr = op->ptr;
1567  const char *prop_id = RNA_property_identifier(prop);
1568  const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes");
1569  int timing_mode = RNA_enum_get(ptr, "timing_mode");
1570  bool realtime = RNA_boolean_get(ptr, "use_realtime");
1571  float gap_duration = RNA_float_get(ptr, "gap_duration");
1572  float gap_randomness = RNA_float_get(ptr, "gap_randomness");
1573  const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
1574 
1575  /* Always show those props */
1576  if (STR_ELEM(prop_id,
1577  "type",
1578  "use_normalize_weights",
1579  "radius_multiplier",
1580  "use_link_strokes",
1581  "bevel_depth",
1582  "bevel_resolution")) {
1583  return true;
1584  }
1585 
1586  /* Never show this prop */
1587  if (STREQ(prop_id, "use_timing_data")) {
1588  return false;
1589  }
1590 
1591  if (link_strokes) {
1592  /* Only show when link_stroke is true */
1593  if (STREQ(prop_id, "timing_mode")) {
1594  return true;
1595  }
1596 
1597  if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
1598  /* Only show when link_stroke is true and stroke timing is enabled */
1599  if (STR_ELEM(prop_id, "frame_range", "start_frame")) {
1600  return true;
1601  }
1602 
1603  /* Only show if we have valid timing data! */
1604  if (valid_timing && STREQ(prop_id, "use_realtime")) {
1605  return true;
1606  }
1607 
1608  /* Only show if realtime or valid_timing is false! */
1609  if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame")) {
1610  return true;
1611  }
1612 
1613  if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
1614  /* Only show for custom gaps! */
1615  if (STREQ(prop_id, "gap_duration")) {
1616  return true;
1617  }
1618 
1619  /* Only show randomness for non-null custom gaps! */
1620  if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f)) {
1621  return true;
1622  }
1623 
1624  /* Only show seed for randomize action! */
1625  if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) {
1626  return true;
1627  }
1628  }
1629  }
1630  }
1631 
1632  /* Else, hidden! */
1633  return false;
1634 }
1635 
1637 {
1638  PropertyRNA *prop;
1639 
1640  /* identifiers */
1641  ot->name = "Convert Grease Pencil";
1642  ot->idname = "GPENCIL_OT_convert";
1643  ot->description = "Convert the active Grease Pencil layer to a new Curve Object";
1644 
1645  /* callbacks */
1650 
1651  /* flags */
1653 
1654  /* properties */
1655  ot->prop = RNA_def_enum(
1656  ot->srna, "type", prop_gpencil_convertmodes, 0, "Type", "Which type of curve to convert to");
1657 
1659  ot->srna, "bevel_depth", 0.0f, 0.0f, 1000.0f, "Bevel Depth", "", 0.0f, 10.0f);
1660  RNA_def_int(ot->srna,
1661  "bevel_resolution",
1662  0,
1663  0,
1664  32,
1665  "Bevel Resolution",
1666  "Bevel resolution when depth is non-zero",
1667  0,
1668  32);
1669 
1671  "use_normalize_weights",
1672  true,
1673  "Normalize Weight",
1674  "Normalize weight (set from stroke width)");
1676  "radius_multiplier",
1677  1.0f,
1678  0.0f,
1679  1000.0f,
1680  "Radius Factor",
1681  "Multiplier for the points' radii (set from stroke width)",
1682  0.0f,
1683  10.0f);
1685  "use_link_strokes",
1686  false,
1687  "Link Strokes",
1688  "Whether to link strokes with zero-radius sections of curves");
1689 
1690  prop = RNA_def_enum(ot->srna,
1691  "timing_mode",
1694  "Timing Mode",
1695  "How to use timing data stored in strokes");
1697 
1698  RNA_def_int(ot->srna,
1699  "frame_range",
1700  100,
1701  1,
1702  10000,
1703  "Frame Range",
1704  "The duration of evaluation of the path control curve",
1705  1,
1706  1000);
1707  RNA_def_int(ot->srna,
1708  "start_frame",
1709  1,
1710  1,
1711  100000,
1712  "Start Frame",
1713  "The start frame of the path control curve",
1714  1,
1715  100000);
1717  "use_realtime",
1718  false,
1719  "Realtime",
1720  "Whether the path control curve reproduces the drawing in realtime, starting "
1721  "from Start Frame");
1722  prop = RNA_def_int(ot->srna,
1723  "end_frame",
1724  250,
1725  1,
1726  100000,
1727  "End Frame",
1728  "The end frame of the path control curve (if Realtime is not set)",
1729  1,
1730  100000);
1732 
1734  "gap_duration",
1735  0.0f,
1736  0.0f,
1737  10000.0f,
1738  "Gap Duration",
1739  "Custom Gap mode: (Average) length of gaps, in frames "
1740  "(Note: Realtime value, will be scaled if Realtime is not set)",
1741  0.0f,
1742  1000.0f);
1744  "gap_randomness",
1745  0.0f,
1746  0.0f,
1747  10000.0f,
1748  "Gap Randomness",
1749  "Custom Gap mode: Number of frames that gap lengths can vary",
1750  0.0f,
1751  1000.0f);
1752  RNA_def_int(ot->srna,
1753  "seed",
1754  0,
1755  0,
1756  1000,
1757  "Random Seed",
1758  "Custom Gap mode: Random generator seed",
1759  0,
1760  100);
1761 
1762  /* NOTE: Internal use, this one will always be hidden by UI code... */
1763  prop = RNA_def_boolean(
1764  ot->srna,
1765  "use_timing_data",
1766  false,
1767  "Has Valid Timing",
1768  "Whether the converted Grease Pencil layer has valid timing data (internal use)");
1770 }
1771 
1772 /* Generate Grease Pencil from Image. */
1774 {
1775  SpaceLink *sl = CTX_wm_space_data(C);
1776  if ((sl != NULL) && (sl->spacetype == SPACE_IMAGE)) {
1777  SpaceImage *sima = CTX_wm_space_image(C);
1778  Image *image = sima->image;
1779  ImageUser iuser = sima->iuser;
1780  return BKE_image_has_ibuf(image, &iuser);
1781  }
1782 
1783  return false;
1784 }
1785 
1787 {
1788  const float size = RNA_float_get(op->ptr, "size");
1789  const bool is_mask = RNA_boolean_get(op->ptr, "mask");
1790 
1791  Main *bmain = CTX_data_main(C);
1793  SpaceImage *sima = CTX_wm_space_image(C);
1794  bool done = false;
1795 
1796  if (sima->image == NULL) {
1797  return OPERATOR_CANCELLED;
1798  }
1799 
1800  /* Create Object. */
1801  const float *cur = scene->cursor.location;
1802  ushort local_view_bits = 0;
1803  Object *ob = ED_gpencil_add_object(C, cur, local_view_bits);
1804  DEG_relations_tag_update(bmain); /* added object */
1805 
1806  /* Create material slot. */
1807  Material *ma = BKE_gpencil_object_material_new(bmain, ob, "Image Material", NULL);
1808  MaterialGPencilStyle *gp_style = ma->gp_style;
1809  gp_style->mode = GP_MATERIAL_MODE_SQUARE;
1810 
1811  /* Add layer and frame. */
1812  bGPdata *gpd = (bGPdata *)ob->data;
1813  bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, "Image Layer", true, false);
1815  done = BKE_gpencil_from_image(sima, gpd, gpf, size, is_mask);
1816 
1817  if (done) {
1818  /* Delete any selected point. */
1819  LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
1821  gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0);
1822  }
1823 
1824  BKE_reportf(op->reports, RPT_INFO, "Object created");
1825  }
1826 
1827  return OPERATOR_FINISHED;
1828 }
1829 
1831 {
1832  PropertyRNA *prop;
1833 
1834  /* identifiers */
1835  ot->name = "Generate Grease Pencil Object using image as source";
1836  ot->idname = "GPENCIL_OT_image_to_grease_pencil";
1837  ot->description = "Generate a Grease Pencil Object using Image as source";
1838 
1839  /* api callbacks */
1842 
1843  /* flags */
1845 
1846  /* properties */
1847  ot->prop = RNA_def_float(ot->srna,
1848  "size",
1849  0.005f,
1850  0.0001f,
1851  10.0f,
1852  "Point Size",
1853  "Size used for grease pencil points",
1854  0.001f,
1855  1.0f);
1857 
1858  prop = RNA_def_boolean(ot->srna,
1859  "mask",
1860  false,
1861  "Generate Mask",
1862  "Create an inverted image for masking using alpha channel");
1864 }
typedef float(TangentPoint)[2]
AnimationEvalContext BKE_animsys_eval_context_construct(struct Depsgraph *depsgraph, float eval_time)
Definition: anim_sys.c:761
bool BKE_collection_object_add(struct Main *bmain, struct Collection *collection, struct Object *ob)
Definition: collection.c:1125
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Collection * CTX_data_collection(const bContext *C)
Definition: context.c:1141
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct SpaceLink * CTX_wm_space_data(const bContext *C)
Definition: context.c:743
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
void BKE_nurb_handles_calc(struct Nurb *nu)
Definition: curve.cc:3995
bool BKE_nurb_type_convert(struct Nurb *nu, short type, bool use_handles, const char **r_err_msg)
Definition: curve.cc:4833
struct Curve * BKE_curve_add(struct Main *bmain, const char *name, int type)
Definition: curve.cc:414
void BKE_nurb_points_add(struct Nurb *nu, int number)
Definition: curve.cc:915
void BKE_nurb_knot_calc_u(struct Nurb *nu)
Definition: curve.cc:1234
void BKE_nurb_bezierPoints_add(struct Nurb *nu, int number)
Definition: curve.cc:928
void BKE_fcurve_handles_recalc(struct FCurve *fcu)
Definition: fcurve.c:1303
@ G_DEBUG
Definition: BKE_global.h:174
struct bGPDframe * BKE_gpencil_frame_addnew(struct bGPDlayer *gpl, int cframe)
Definition: gpencil.c:514
struct Material * BKE_gpencil_object_material_new(struct Main *bmain, struct Object *ob, const char *name, int *r_index)
Definition: gpencil.c:1734
struct bGPDlayer * BKE_gpencil_layer_active_get(struct bGPdata *gpd)
Definition: gpencil.c:1558
struct bGPDlayer * BKE_gpencil_layer_addnew(struct bGPdata *gpd, const char *name, bool setactive, bool add_to_header)
Definition: gpencil.c:621
bool BKE_gpencil_from_image(struct SpaceImage *sima, struct bGPdata *gpd, struct bGPDframe *gpf, float size, bool mask)
Definition: gpencil.c:2290
struct bGPDframe * BKE_gpencil_layer_frame_get(struct bGPDlayer *gpl, int cframe, eGP_GetFrame_Mode addnew)
Definition: gpencil.c:1232
void BKE_gpencil_layer_transform_matrix_get(const struct Depsgraph *depsgraph, struct Object *obact, struct bGPDlayer *gpl, float diff_mat[4][4])
@ GP_GETFRAME_USE_PREV
Definition: BKE_gpencil.h:338
struct bGPDstroke * BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, bool select, bool flat_cap, int limit)
bool BKE_image_has_ibuf(struct Image *ima, struct ImageUser *iuser)
struct Base * BKE_view_layer_base_find(struct ViewLayer *view_layer, struct Object *ob)
Definition: layer.c:379
General operations, lookup, etc. for materials.
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Definition: object.cc:2241
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
Definition: BLI_listbase.h:354
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float min_ff(float a, float b)
MINLINE float interpf(float a, float b, float t)
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
Random number functions.
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1)
Definition: rand.cc:68
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition: rand.cc:58
struct RNG * BLI_rng_new(unsigned int seed)
Definition: rand.cc:39
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: rand.cc:93
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:194
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition: BLI_rect.h:198
#define STR_ELEM(...)
Definition: BLI_string.h:539
unsigned short ushort
Definition: BLI_sys_types.h:68
#define UNUSED(x)
#define ELEM(...)
#define IS_EQF(a, b)
#define STREQ(a, b)
typedef double(DMatrix)[4][4]
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ INSERTKEY_FAST
@ FCURVE_EXTRAPOLATE_LINEAR
Object groups, one object can be in many groups at once.
@ CU_BEZIER
@ CU_POLY
@ CU_NURBS
@ CU_NURB_ENDPOINT
@ HD_FREE
@ CU_3D
@ CU_PATH
@ BEZT_KEYTYPE_BREAKDOWN
@ BEZT_KEYTYPE_KEYFRAME
@ GP_STROKE_2DSPACE
@ GP_STROKE_3DSPACE
#define GPENCIL_ANY_EDIT_MODE(gpd)
@ GP_SPOINT_SELECT
@ GP_MATERIAL_MODE_SQUARE
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
@ OB_GPENCIL
#define TIME2FRA(a)
#define FRA2TIME(a)
@ SPACE_IMAGE
@ SPACE_VIEW3D
#define RV3D_CAMOB
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void ED_object_base_select(struct Base *base, eObjectSelect_Mode mode)
Definition: object_select.c:76
@ BA_SELECT
Definition: ED_object.h:155
void ED_view3d_win_to_3d(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
void ED_view3d_calc_camera_border(const struct Scene *scene, struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, bool no_shift)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
#define C
Definition: RandGen.cpp:25
void UI_view2d_view_to_region_fl(const struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL()
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_OB_ACTIVE
Definition: WM_types.h:388
#define NC_ANIMATION
Definition: WM_types.h:338
#define NC_SCENE
Definition: WM_types.h:328
#define NA_ADDED
Definition: WM_types.h:525
#define NA_EDITED
Definition: WM_types.h:523
#define ND_KEYFRAME
Definition: WM_types.h:442
#define NC_OBJECT
Definition: WM_types.h:329
int main(int argc, char *argv[])
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
#define SELECT
double time
Scene scene
const Depsgraph * depsgraph
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
static int image_to_gpencil_exec(bContext *C, wmOperator *op)
#define GAP_DFAC
static void gpencil_stroke_to_path(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, const bool add_end_point, tGpTimingData *gtd)
static bool gpencil_convert_poll(bContext *C)
#define BEZT_HANDLE_FAC
struct tGpTimingData tGpTimingData
static void gpencil_stroke_finalize_curve_endpoints(Curve *cu)
static bool gpencil_convert_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
void GPENCIL_OT_image_to_grease_pencil(wmOperatorType *ot)
static void gpencil_timing_data_add_point(tGpTimingData *gtd, const double stroke_inittime, const float time, const float delta_dist)
static void gpencil_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt, const float p[3], const float h1[3], const float h2[3], const float prev_p[3], const bool do_gtd, const double inittime, const float time, const float width, const float rad_fac, float minmax_weights[2])
static void gpencil_strokepoint_convertcoords(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, bGPDspoint *source_pt, float p3d[3], const rctf *subrect)
static int gpencil_find_end_of_stroke_idx(tGpTimingData *gtd, RNG *rng, const int idx, const int gaps_count, int *gaps_done_count, const float tot_gaps_time, const float delta_time, float *next_delta_time)
static const EnumPropertyItem * rna_GPConvert_mode_items(bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
static void gpencil_stroke_path_animation(bContext *C, ReportList *reports, Curve *cu, tGpTimingData *gtd)
#define WIDTH_CORR_FAC
#define MIN_TIME_DELTA
static const EnumPropertyItem prop_gpencil_convert_timingmodes[]
static int gpencil_convert_layer_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_gpencil_convertmodes[]
static void gpencil_stroke_path_animation_preprocess_gaps(tGpTimingData *gtd, RNG *rng, int *gaps_count, float *r_tot_gaps_time)
static bool gpencil_convert_check_has_valid_timing(bContext *C, bGPDlayer *gpl, wmOperator *op)
static void gpencil_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bGPDlayer *gpl, const int mode, const bool norm_weights, const float rad_fac, const bool link_strokes, tGpTimingData *gtd)
static bool image_to_gpencil_poll(bContext *C)
static const EnumPropertyItem prop_gpencil_convert_timingmodes_restricted[]
void GPENCIL_OT_convert(wmOperatorType *ot)
static void gpencil_stroke_norm_curve_weights(Curve *cu, const float minmax_weights[2])
@ GP_STROKECONVERT_TIMING_LINEAR
@ GP_STROKECONVERT_TIMING_NONE
@ GP_STROKECONVERT_TIMING_CUSTOMGAP
@ GP_STROKECONVERT_TIMING_FULL
static void gpencil_timing_data_set_num(tGpTimingData *gtd, const int num)
@ GP_STROKECONVERT_POLY
@ GP_STROKECONVERT_PATH
@ GP_STROKECONVERT_CURVE
static void gpencil_stroke_to_bezier(bContext *C, bGPDlayer *gpl, bGPDstroke *gps, Curve *cu, rctf *subrect, Nurb **curnu, float minmax_weights[2], const float rad_fac, bool stitch, const bool add_start_point, const bool add_end_point, tGpTimingData *gtd)
static void gpencil_stroke_path_animation_add_keyframes(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, Depsgraph *depsgraph, FCurve *fcu, Curve *cu, tGpTimingData *gtd, RNG *rng, const float time_range, const int gaps_count, const float tot_gaps_time)
static void gpencil_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UNUSED(scene), struct PointerRNA *ptr)
static void gpencil_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3], const bool do_gtd, const double inittime, const float time, const float width, const float rad_fac, float minmax_weights[2])
static int gpencil_camera_view_subrect(bContext *C, rctf *subrect)
Object * ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view_bits)
bAction * ED_id_action_ensure(Main *bmain, ID *id)
Definition: keyframing.c:123
bool insert_keyframe_direct(ReportList *reports, PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, const AnimationEvalContext *anim_eval_context, eBezTriple_KeyframeType keytype, struct NlaKeyframingContext *nla_context, eInsertKeyFlags flag)
Definition: keyframing.c:1303
FCurve * ED_action_fcurve_ensure(struct Main *bmain, struct bAction *act, const char group[], struct PointerRNA *ptr, const char rna_path[], const int array_index)
Definition: keyframing.c:173
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define G(x, y, z)
#define fabsf(x)
Definition: metal/compat.h:219
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
bool RNA_property_boolean_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2153
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:5015
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_float_distance(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:4052
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_property_update_runtime(PropertyRNA *prop, const void *func)
Definition: rna_define.c:2911
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
#define min(a, b)
Definition: sort.c:35
void * regiondata
float weight
uint8_t f1
float vec[4]
float radius
uint8_t h1
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
uint8_t h2
short resolv
short bevresol
short resolu
float bevel_radius
ListBase nurb
float ctime
short extend
Definition: DNA_ID.h:368
void * last
Definition: DNA_listBase.h:31
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct MaterialGPencilStyle * gp_style
short flagu
short orderu
struct Nurb * next
float * knotsu
short type
BezTriple * bezt
BPoint * bp
short resolu
short resolv
void * data
Definition: rand.cc:33
struct RenderData r
View3DCursor cursor
struct ImageUser iuser
struct Image * image
struct bGPDframe * next
ListBase strokes
char info[128]
struct bGPDstroke * prev
bGPDspoint * points
struct bGPDstroke * next
float xmin
Definition: DNA_vec_types.h:69
float ymin
Definition: DNA_vec_types.h:70
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:949
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
float max
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))