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