413e28c431bedf3ab164ffafef88384e802dff4a
[blender.git] / source / blender / blenkernel / intern / gpencil_geom.c
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  */
19
20 /** \file
21  * \ingroup bke
22  */
23
24 #include <math.h>
25 #include <stddef.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "CLG_log.h"
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_math_vector.h"
36 #include "BLI_polyfill_2d.h"
37
38 #include "BLT_translation.h"
39
40 #include "DNA_gpencil_types.h"
41 #include "DNA_meshdata_types.h"
42
43 #include "BKE_collection.h"
44 #include "BKE_curve.h"
45 #include "BKE_deform.h"
46 #include "BKE_gpencil.h"
47 #include "BKE_gpencil_geom.h"
48 #include "BKE_main.h"
49 #include "BKE_material.h"
50 #include "BKE_object.h"
51
52 #include "DEG_depsgraph_query.h"
53
54 /* GP Object - Boundbox Support */
55 /**
56  * Get min/max coordinate bounds for single stroke
57  * \return Returns whether we found any selected points
58  */
59 bool BKE_gpencil_stroke_minmax(const bGPDstroke *gps,
60                                const bool use_select,
61                                float r_min[3],
62                                float r_max[3])
63 {
64   const bGPDspoint *pt;
65   int i;
66   bool changed = false;
67
68   if (ELEM(NULL, gps, r_min, r_max)) {
69     return false;
70   }
71
72   for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
73     if ((use_select == false) || (pt->flag & GP_SPOINT_SELECT)) {
74       minmax_v3v3_v3(r_min, r_max, &pt->x);
75       changed = true;
76     }
77   }
78   return changed;
79 }
80
81 /* get min/max bounds of all strokes in GP datablock */
82 bool BKE_gpencil_data_minmax(const bGPdata *gpd, float r_min[3], float r_max[3])
83 {
84   bool changed = false;
85
86   INIT_MINMAX(r_min, r_max);
87
88   if (gpd == NULL) {
89     return changed;
90   }
91
92   LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
93     bGPDframe *gpf = gpl->actframe;
94
95     if (gpf != NULL) {
96       LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
97         changed = BKE_gpencil_stroke_minmax(gps, false, r_min, r_max);
98       }
99     }
100   }
101
102   return changed;
103 }
104
105 /* compute center of bounding box */
106 void BKE_gpencil_centroid_3d(bGPdata *gpd, float r_centroid[3])
107 {
108   float min[3], max[3], tot[3];
109
110   BKE_gpencil_data_minmax(gpd, min, max);
111
112   add_v3_v3v3(tot, min, max);
113   mul_v3_v3fl(r_centroid, tot, 0.5f);
114 }
115
116 /* Compute stroke bounding box. */
117 void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps)
118 {
119   INIT_MINMAX(gps->boundbox_min, gps->boundbox_max);
120   BKE_gpencil_stroke_minmax(gps, false, gps->boundbox_min, gps->boundbox_max);
121 }
122
123 /* create bounding box values */
124 static void boundbox_gpencil(Object *ob)
125 {
126   BoundBox *bb;
127   bGPdata *gpd;
128   float min[3], max[3];
129
130   if (ob->runtime.bb == NULL) {
131     ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "GPencil boundbox");
132   }
133
134   bb = ob->runtime.bb;
135   gpd = ob->data;
136
137   if (!BKE_gpencil_data_minmax(gpd, min, max)) {
138     min[0] = min[1] = min[2] = -1.0f;
139     max[0] = max[1] = max[2] = 1.0f;
140   }
141
142   BKE_boundbox_init_from_minmax(bb, min, max);
143
144   bb->flag &= ~BOUNDBOX_DIRTY;
145 }
146
147 /* get bounding box */
148 BoundBox *BKE_gpencil_boundbox_get(Object *ob)
149 {
150   if (ELEM(NULL, ob, ob->data)) {
151     return NULL;
152   }
153
154   bGPdata *gpd = (bGPdata *)ob->data;
155   if ((ob->runtime.bb) && ((gpd->flag & GP_DATA_CACHE_IS_DIRTY) == 0)) {
156     return ob->runtime.bb;
157   }
158
159   boundbox_gpencil(ob);
160
161   return ob->runtime.bb;
162 }
163
164 /* ************************************************** */
165
166 static int stroke_march_next_point(const bGPDstroke *gps,
167                                    const int index_next_pt,
168                                    const float *current,
169                                    const float dist,
170                                    float *result,
171                                    float *pressure,
172                                    float *strength,
173                                    float *vert_color,
174                                    float *ratio_result,
175                                    int *index_from,
176                                    int *index_to)
177 {
178   float remaining_till_next = 0.0f;
179   float remaining_march = dist;
180   float step_start[3];
181   float point[3];
182   int next_point_index = index_next_pt;
183   bGPDspoint *pt = NULL;
184
185   if (!(next_point_index < gps->totpoints)) {
186     return -1;
187   }
188
189   copy_v3_v3(step_start, current);
190   pt = &gps->points[next_point_index];
191   copy_v3_v3(point, &pt->x);
192   remaining_till_next = len_v3v3(point, step_start);
193
194   while (remaining_till_next < remaining_march) {
195     remaining_march -= remaining_till_next;
196     pt = &gps->points[next_point_index];
197     copy_v3_v3(point, &pt->x);
198     copy_v3_v3(step_start, point);
199     next_point_index++;
200     if (!(next_point_index < gps->totpoints)) {
201       next_point_index = gps->totpoints - 1;
202       break;
203     }
204     pt = &gps->points[next_point_index];
205     copy_v3_v3(point, &pt->x);
206     remaining_till_next = len_v3v3(point, step_start);
207   }
208   if (remaining_till_next < remaining_march) {
209     pt = &gps->points[next_point_index];
210     copy_v3_v3(result, &pt->x);
211     *pressure = gps->points[next_point_index].pressure;
212     *strength = gps->points[next_point_index].strength;
213     memcpy(vert_color, gps->points[next_point_index].vert_color, sizeof(float) * 4);
214
215     *index_from = next_point_index - 1;
216     *index_to = next_point_index;
217     *ratio_result = 1.0f;
218
219     return 0;
220   }
221   else {
222     float ratio = remaining_march / remaining_till_next;
223     interp_v3_v3v3(result, step_start, point, ratio);
224     *pressure = interpf(
225         gps->points[next_point_index].pressure, gps->points[next_point_index - 1].pressure, ratio);
226     *strength = interpf(
227         gps->points[next_point_index].strength, gps->points[next_point_index - 1].strength, ratio);
228     interp_v4_v4v4(vert_color,
229                    gps->points[next_point_index - 1].vert_color,
230                    gps->points[next_point_index].vert_color,
231                    ratio);
232
233     *index_from = next_point_index - 1;
234     *index_to = next_point_index;
235     *ratio_result = ratio;
236
237     return next_point_index;
238   }
239 }
240
241 static int stroke_march_next_point_no_interp(const bGPDstroke *gps,
242                                              const int index_next_pt,
243                                              const float *current,
244                                              const float dist,
245                                              float *result)
246 {
247   float remaining_till_next = 0.0f;
248   float remaining_march = dist;
249   float step_start[3];
250   float point[3];
251   int next_point_index = index_next_pt;
252   bGPDspoint *pt = NULL;
253
254   if (!(next_point_index < gps->totpoints)) {
255     return -1;
256   }
257
258   copy_v3_v3(step_start, current);
259   pt = &gps->points[next_point_index];
260   copy_v3_v3(point, &pt->x);
261   remaining_till_next = len_v3v3(point, step_start);
262
263   while (remaining_till_next < remaining_march) {
264     remaining_march -= remaining_till_next;
265     pt = &gps->points[next_point_index];
266     copy_v3_v3(point, &pt->x);
267     copy_v3_v3(step_start, point);
268     next_point_index++;
269     if (!(next_point_index < gps->totpoints)) {
270       next_point_index = gps->totpoints - 1;
271       break;
272     }
273     pt = &gps->points[next_point_index];
274     copy_v3_v3(point, &pt->x);
275     remaining_till_next = len_v3v3(point, step_start);
276   }
277   if (remaining_till_next < remaining_march) {
278     pt = &gps->points[next_point_index];
279     copy_v3_v3(result, &pt->x);
280     return 0;
281   }
282   else {
283     float ratio = remaining_march / remaining_till_next;
284     interp_v3_v3v3(result, step_start, point, ratio);
285     return next_point_index;
286   }
287 }
288
289 static int stroke_march_count(const bGPDstroke *gps, const float dist)
290 {
291   int point_count = 0;
292   float point[3];
293   int next_point_index = 1;
294   bGPDspoint *pt = NULL;
295
296   pt = &gps->points[0];
297   copy_v3_v3(point, &pt->x);
298   point_count++;
299
300   while ((next_point_index = stroke_march_next_point_no_interp(
301               gps, next_point_index, point, dist, point)) > -1) {
302     point_count++;
303     if (next_point_index == 0) {
304       break; /* last point finished */
305     }
306   }
307   return point_count;
308 }
309
310 static void stroke_defvert_create_nr_list(MDeformVert *dv_list,
311                                           int count,
312                                           ListBase *result,
313                                           int *totweight)
314 {
315   LinkData *ld;
316   MDeformVert *dv;
317   MDeformWeight *dw;
318   int i, j;
319   int tw = 0;
320   for (i = 0; i < count; i++) {
321     dv = &dv_list[i];
322
323     /* find def_nr in list, if not exist, then create one */
324     for (j = 0; j < dv->totweight; j++) {
325       bool found = false;
326       dw = &dv->dw[j];
327       for (ld = result->first; ld; ld = ld->next) {
328         if (ld->data == POINTER_FROM_INT(dw->def_nr)) {
329           found = true;
330           break;
331         }
332       }
333       if (!found) {
334         ld = MEM_callocN(sizeof(LinkData), "def_nr_item");
335         ld->data = POINTER_FROM_INT(dw->def_nr);
336         BLI_addtail(result, ld);
337         tw++;
338       }
339     }
340   }
341
342   *totweight = tw;
343 }
344
345 static MDeformVert *stroke_defvert_new_count(int count, int totweight, ListBase *def_nr_list)
346 {
347   int i, j;
348   LinkData *ld;
349   MDeformVert *dst = MEM_mallocN(count * sizeof(MDeformVert), "new_deformVert");
350
351   for (i = 0; i < count; i++) {
352     dst[i].dw = MEM_mallocN(sizeof(MDeformWeight) * totweight, "new_deformWeight");
353     dst[i].totweight = totweight;
354     j = 0;
355     /* re-assign deform groups */
356     for (ld = def_nr_list->first; ld; ld = ld->next) {
357       dst[i].dw[j].def_nr = POINTER_AS_INT(ld->data);
358       j++;
359     }
360   }
361
362   return dst;
363 }
364
365 static void stroke_interpolate_deform_weights(
366     bGPDstroke *gps, int index_from, int index_to, float ratio, MDeformVert *vert)
367 {
368   const MDeformVert *vl = &gps->dvert[index_from];
369   const MDeformVert *vr = &gps->dvert[index_to];
370   int i;
371
372   for (i = 0; i < vert->totweight; i++) {
373     float wl = BKE_defvert_find_weight(vl, vert->dw[i].def_nr);
374     float wr = BKE_defvert_find_weight(vr, vert->dw[i].def_nr);
375     vert->dw[i].weight = interpf(wr, wl, ratio);
376   }
377 }
378
379 /**
380  * Resample a stroke
381  * \param gps: Stroke to sample
382  * \param dist: Distance of one segment
383  */
384 bool BKE_gpencil_stroke_sample(bGPDstroke *gps, const float dist, const bool select)
385 {
386   bGPDspoint *pt = gps->points;
387   bGPDspoint *pt1 = NULL;
388   bGPDspoint *pt2 = NULL;
389   int i;
390   LinkData *ld;
391   ListBase def_nr_list = {0};
392
393   if (gps->totpoints < 2 || dist < FLT_EPSILON) {
394     return false;
395   }
396   /* TODO: Implement feature point preservation. */
397   int count = stroke_march_count(gps, dist);
398
399   bGPDspoint *new_pt = MEM_callocN(sizeof(bGPDspoint) * count, "gp_stroke_points_sampled");
400   MDeformVert *new_dv = NULL;
401
402   int result_totweight;
403
404   if (gps->dvert != NULL) {
405     stroke_defvert_create_nr_list(gps->dvert, gps->totpoints, &def_nr_list, &result_totweight);
406     new_dv = stroke_defvert_new_count(count, result_totweight, &def_nr_list);
407   }
408
409   int next_point_index = 1;
410   i = 0;
411   float pressure, strength, ratio_result;
412   float vert_color[4];
413   int index_from, index_to;
414   float last_coord[3];
415
416   /*  1st point is always at the start */
417   pt1 = &gps->points[0];
418   copy_v3_v3(last_coord, &pt1->x);
419   pt2 = &new_pt[i];
420   copy_v3_v3(&pt2->x, last_coord);
421   new_pt[i].pressure = pt[0].pressure;
422   new_pt[i].strength = pt[0].strength;
423   memcpy(new_pt[i].vert_color, pt[0].vert_color, sizeof(float) * 4);
424   if (select) {
425     new_pt[i].flag |= GP_SPOINT_SELECT;
426   }
427   i++;
428
429   if (new_dv) {
430     stroke_interpolate_deform_weights(gps, 0, 0, 0, &new_dv[0]);
431   }
432
433   /* The rest. */
434   while ((next_point_index = stroke_march_next_point(gps,
435                                                      next_point_index,
436                                                      last_coord,
437                                                      dist,
438                                                      last_coord,
439                                                      &pressure,
440                                                      &strength,
441                                                      vert_color,
442                                                      &ratio_result,
443                                                      &index_from,
444                                                      &index_to)) > -1) {
445     pt2 = &new_pt[i];
446     copy_v3_v3(&pt2->x, last_coord);
447     new_pt[i].pressure = pressure;
448     new_pt[i].strength = strength;
449     memcpy(new_pt[i].vert_color, vert_color, sizeof(float) * 4);
450     if (select) {
451       new_pt[i].flag |= GP_SPOINT_SELECT;
452     }
453
454     if (new_dv) {
455       stroke_interpolate_deform_weights(gps, index_from, index_to, ratio_result, &new_dv[i]);
456     }
457
458     i++;
459     if (next_point_index == 0) {
460       break; /* last point finished */
461     }
462   }
463
464   gps->points = new_pt;
465   /* Free original vertex list. */
466   MEM_freeN(pt);
467
468   if (new_dv) {
469     /* Free original weight data. */
470     BKE_gpencil_free_stroke_weights(gps);
471     MEM_freeN(gps->dvert);
472     while ((ld = BLI_pophead(&def_nr_list))) {
473       MEM_freeN(ld);
474     }
475
476     gps->dvert = new_dv;
477   }
478
479   gps->totpoints = i;
480
481   /* Calc geometry data. */
482   BKE_gpencil_stroke_geometry_update(gps);
483
484   return true;
485 }
486
487 /**
488  * Backbone stretch similar to Freestyle.
489  * \param gps: Stroke to sample
490  * \param dist: Distance of one segment
491  * \param tip_length: Ignore tip jittering, set zero to use default value.
492  */
493 bool BKE_gpencil_stroke_stretch(bGPDstroke *gps, const float dist, const float tip_length)
494 {
495   bGPDspoint *pt = gps->points, *last_pt, *second_last, *next_pt;
496   int i;
497   float threshold = (tip_length == 0 ? 0.001f : tip_length);
498
499   if (gps->totpoints < 2 || dist < FLT_EPSILON) {
500     return false;
501   }
502
503   last_pt = &pt[gps->totpoints - 1];
504   second_last = &pt[gps->totpoints - 2];
505   next_pt = &pt[1];
506
507   float len1 = 0.0f;
508   float len2 = 0.0f;
509
510   i = 1;
511   while (len1 < threshold && gps->totpoints > i) {
512     next_pt = &pt[i];
513     len1 = len_v3v3(&next_pt->x, &pt->x);
514     i++;
515   }
516
517   i = 2;
518   while (len2 < threshold && gps->totpoints >= i) {
519     second_last = &pt[gps->totpoints - i];
520     len2 = len_v3v3(&last_pt->x, &second_last->x);
521     i++;
522   }
523
524   float extend1 = (len1 + dist) / len1;
525   float extend2 = (len2 + dist) / len2;
526
527   float result1[3], result2[3];
528
529   interp_v3_v3v3(result1, &next_pt->x, &pt->x, extend1);
530   interp_v3_v3v3(result2, &second_last->x, &last_pt->x, extend2);
531
532   copy_v3_v3(&pt->x, result1);
533   copy_v3_v3(&last_pt->x, result2);
534
535   return true;
536 }
537
538 /**
539  * Trim stroke to needed segments
540  * \param gps: Target stroke
541  * \param index_from: the index of the first point to be used in the trimmed result
542  * \param index_to: the index of the last point to be used in the trimmed result
543  */
544 bool BKE_gpencil_stroke_trim_points(bGPDstroke *gps, const int index_from, const int index_to)
545 {
546   bGPDspoint *pt = gps->points, *new_pt;
547   MDeformVert *dv, *new_dv;
548
549   const int new_count = index_to - index_from + 1;
550
551   if (new_count >= gps->totpoints) {
552     return false;
553   }
554
555   if (new_count == 1) {
556     BKE_gpencil_free_stroke_weights(gps);
557     MEM_freeN(gps->points);
558     gps->points = NULL;
559     gps->dvert = NULL;
560     gps->totpoints = 0;
561     return false;
562   }
563
564   new_pt = MEM_callocN(sizeof(bGPDspoint) * new_count, "gp_stroke_points_trimmed");
565
566   for (int i = 0; i < new_count; i++) {
567     memcpy(&new_pt[i], &pt[i + index_from], sizeof(bGPDspoint));
568   }
569
570   if (gps->dvert) {
571     new_dv = MEM_callocN(sizeof(MDeformVert) * new_count, "gp_stroke_dverts_trimmed");
572     for (int i = 0; i < new_count; i++) {
573       dv = &gps->dvert[i + index_from];
574       new_dv[i].flag = dv->flag;
575       new_dv[i].totweight = dv->totweight;
576       new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
577                                  "gp_stroke_dverts_dw_trimmed");
578       for (int j = 0; j < dv->totweight; j++) {
579         new_dv[i].dw[j].weight = dv->dw[j].weight;
580         new_dv[i].dw[j].def_nr = dv->dw[j].def_nr;
581       }
582     }
583     MEM_freeN(gps->dvert);
584     gps->dvert = new_dv;
585   }
586
587   MEM_freeN(gps->points);
588   gps->points = new_pt;
589   gps->totpoints = new_count;
590
591   return true;
592 }
593
594 bool BKE_gpencil_stroke_split(bGPDframe *gpf,
595                               bGPDstroke *gps,
596                               const int before_index,
597                               bGPDstroke **remaining_gps)
598 {
599   bGPDstroke *new_gps;
600   bGPDspoint *pt = gps->points, *new_pt;
601   MDeformVert *dv, *new_dv;
602
603   if (before_index >= gps->totpoints || before_index == 0) {
604     return false;
605   }
606
607   const int new_count = gps->totpoints - before_index;
608   const int old_count = before_index;
609
610   /* Handle remaining segments first. */
611
612   new_gps = BKE_gpencil_stroke_add_existing_style(
613       gpf, gps, gps->mat_nr, new_count, gps->thickness);
614
615   new_pt = new_gps->points; /* Allocated from above. */
616
617   for (int i = 0; i < new_count; i++) {
618     memcpy(&new_pt[i], &pt[i + before_index], sizeof(bGPDspoint));
619   }
620
621   if (gps->dvert) {
622     new_dv = MEM_callocN(sizeof(MDeformVert) * new_count,
623                          "gp_stroke_dverts_remaining(MDeformVert)");
624     for (int i = 0; i < new_count; i++) {
625       dv = &gps->dvert[i + before_index];
626       new_dv[i].flag = dv->flag;
627       new_dv[i].totweight = dv->totweight;
628       new_dv[i].dw = MEM_callocN(sizeof(MDeformWeight) * dv->totweight,
629                                  "gp_stroke_dverts_dw_remaining(MDeformWeight)");
630       for (int j = 0; j < dv->totweight; j++) {
631         new_dv[i].dw[j].weight = dv->dw[j].weight;
632         new_dv[i].dw[j].def_nr = dv->dw[j].def_nr;
633       }
634     }
635     new_gps->dvert = new_dv;
636   }
637
638   (*remaining_gps) = new_gps;
639
640   /* Trim the original stroke into a shorter one.
641    * Keep the end point. */
642
643   BKE_gpencil_stroke_trim_points(gps, 0, old_count);
644   BKE_gpencil_stroke_geometry_update(gps);
645   return true;
646 }
647
648 /**
649  * Shrink the stroke by length.
650  * \param gps: Stroke to shrink
651  * \param dist: delta length
652  */
653 bool BKE_gpencil_stroke_shrink(bGPDstroke *gps, const float dist)
654 {
655   bGPDspoint *pt = gps->points, *second_last;
656   int i;
657
658   if (gps->totpoints < 2 || dist < FLT_EPSILON) {
659     return false;
660   }
661
662   second_last = &pt[gps->totpoints - 2];
663
664   float len1, this_len1, cut_len1;
665   float len2, this_len2, cut_len2;
666   int index_start, index_end;
667
668   len1 = len2 = this_len1 = this_len2 = cut_len1 = cut_len2 = 0.0f;
669
670   i = 1;
671   while (len1 < dist && gps->totpoints > i - 1) {
672     this_len1 = len_v3v3(&pt[i].x, &pt[i + 1].x);
673     len1 += this_len1;
674     cut_len1 = len1 - dist;
675     i++;
676   }
677   index_start = i - 2;
678
679   i = 2;
680   while (len2 < dist && gps->totpoints >= i) {
681     second_last = &pt[gps->totpoints - i];
682     this_len2 = len_v3v3(&second_last[1].x, &second_last->x);
683     len2 += this_len2;
684     cut_len2 = len2 - dist;
685     i++;
686   }
687   index_end = gps->totpoints - i + 2;
688
689   if (len1 < dist || len2 < dist || index_end <= index_start) {
690     index_start = index_end = 0; /* empty stroke */
691   }
692
693   if ((index_end == index_start + 1) && (cut_len1 + cut_len2 > 1.0f)) {
694     index_start = index_end = 0; /* no length left to cut */
695   }
696
697   BKE_gpencil_stroke_trim_points(gps, index_start, index_end);
698
699   if (gps->totpoints == 0) {
700     return false;
701   }
702
703   pt = gps->points;
704
705   float cut1 = cut_len1 / this_len1;
706   float cut2 = cut_len2 / this_len2;
707
708   float result1[3], result2[3];
709
710   interp_v3_v3v3(result1, &pt[1].x, &pt[0].x, cut1);
711   interp_v3_v3v3(result2, &pt[gps->totpoints - 2].x, &pt[gps->totpoints - 1].x, cut2);
712
713   copy_v3_v3(&pt[0].x, result1);
714   copy_v3_v3(&pt[gps->totpoints - 1].x, result2);
715
716   return true;
717 }
718
719 /**
720  * Apply smooth to stroke point
721  * \param gps: Stroke to smooth
722  * \param i: Point index
723  * \param inf: Amount of smoothing to apply
724  */
725 bool BKE_gpencil_stroke_smooth(bGPDstroke *gps, int i, float inf)
726 {
727   bGPDspoint *pt = &gps->points[i];
728   float sco[3] = {0.0f};
729
730   /* Do nothing if not enough points to smooth out */
731   if (gps->totpoints <= 2) {
732     return false;
733   }
734
735   /* Only affect endpoints by a fraction of the normal strength,
736    * to prevent the stroke from shrinking too much
737    */
738   if ((i == 0) || (i == gps->totpoints - 1)) {
739     inf *= 0.1f;
740   }
741
742   /* Compute smoothed coordinate by taking the ones nearby */
743   /* XXX: This is potentially slow,
744    *      and suffers from accumulation error as earlier points are handled before later ones. */
745   {
746     /* XXX: this is hardcoded to look at 2 points on either side of the current one
747      * (i.e. 5 items total). */
748     const int steps = 2;
749     const float average_fac = 1.0f / (float)(steps * 2 + 1);
750     int step;
751
752     /* add the point itself */
753     madd_v3_v3fl(sco, &pt->x, average_fac);
754
755     /* n-steps before/after current point */
756     /* XXX: review how the endpoints are treated by this algorithm. */
757     /* XXX: falloff measures should also introduce some weighting variations,
758      *      so that further-out points get less weight. */
759     for (step = 1; step <= steps; step++) {
760       bGPDspoint *pt1, *pt2;
761       int before = i - step;
762       int after = i + step;
763
764       CLAMP_MIN(before, 0);
765       CLAMP_MAX(after, gps->totpoints - 1);
766
767       pt1 = &gps->points[before];
768       pt2 = &gps->points[after];
769
770       /* add both these points to the average-sum (s += p[i]/n) */
771       madd_v3_v3fl(sco, &pt1->x, average_fac);
772       madd_v3_v3fl(sco, &pt2->x, average_fac);
773     }
774   }
775
776   /* Based on influence factor, blend between original and optimal smoothed coordinate */
777   interp_v3_v3v3(&pt->x, &pt->x, sco, inf);
778
779   return true;
780 }
781
782 /**
783  * Apply smooth for strength to stroke point */
784 bool BKE_gpencil_stroke_smooth_strength(bGPDstroke *gps, int point_index, float influence)
785 {
786   bGPDspoint *ptb = &gps->points[point_index];
787
788   /* Do nothing if not enough points */
789   if ((gps->totpoints <= 2) || (point_index < 1)) {
790     return false;
791   }
792   /* Only affect endpoints by a fraction of the normal influence */
793   float inf = influence;
794   if ((point_index == 0) || (point_index == gps->totpoints - 1)) {
795     inf *= 0.01f;
796   }
797   /* Limit max influence to reduce pop effect. */
798   CLAMP_MAX(inf, 0.98f);
799
800   float total = 0.0f;
801   float max_strength = 0.0f;
802   const int steps = 4;
803   const float average_fac = 1.0f / (float)(steps * 2 + 1);
804   int step;
805
806   /* add the point itself */
807   total += ptb->strength * average_fac;
808   max_strength = ptb->strength;
809
810   /* n-steps before/after current point */
811   for (step = 1; step <= steps; step++) {
812     bGPDspoint *pt1, *pt2;
813     int before = point_index - step;
814     int after = point_index + step;
815
816     CLAMP_MIN(before, 0);
817     CLAMP_MAX(after, gps->totpoints - 1);
818
819     pt1 = &gps->points[before];
820     pt2 = &gps->points[after];
821
822     /* add both these points to the average-sum (s += p[i]/n) */
823     total += pt1->strength * average_fac;
824     total += pt2->strength * average_fac;
825     /* Save max value. */
826     if (max_strength < pt1->strength) {
827       max_strength = pt1->strength;
828     }
829     if (max_strength < pt2->strength) {
830       max_strength = pt2->strength;
831     }
832   }
833
834   /* Based on influence factor, blend between original and optimal smoothed value. */
835   ptb->strength = interpf(ptb->strength, total, inf);
836   /* Clamp to maximum stroke strength to avoid weird results. */
837   CLAMP_MAX(ptb->strength, max_strength);
838
839   return true;
840 }
841
842 /**
843  * Apply smooth for thickness to stroke point (use pressure) */
844 bool BKE_gpencil_stroke_smooth_thickness(bGPDstroke *gps, int point_index, float influence)
845 {
846   bGPDspoint *ptb = &gps->points[point_index];
847
848   /* Do nothing if not enough points */
849   if ((gps->totpoints <= 2) || (point_index < 1)) {
850     return false;
851   }
852   /* Only affect endpoints by a fraction of the normal influence */
853   float inf = influence;
854   if ((point_index == 0) || (point_index == gps->totpoints - 1)) {
855     inf *= 0.01f;
856   }
857   /* Limit max influence to reduce pop effect. */
858   CLAMP_MAX(inf, 0.98f);
859
860   float total = 0.0f;
861   float max_pressure = 0.0f;
862   const int steps = 4;
863   const float average_fac = 1.0f / (float)(steps * 2 + 1);
864   int step;
865
866   /* add the point itself */
867   total += ptb->pressure * average_fac;
868   max_pressure = ptb->pressure;
869
870   /* n-steps before/after current point */
871   for (step = 1; step <= steps; step++) {
872     bGPDspoint *pt1, *pt2;
873     int before = point_index - step;
874     int after = point_index + step;
875
876     CLAMP_MIN(before, 0);
877     CLAMP_MAX(after, gps->totpoints - 1);
878
879     pt1 = &gps->points[before];
880     pt2 = &gps->points[after];
881
882     /* add both these points to the average-sum (s += p[i]/n) */
883     total += pt1->pressure * average_fac;
884     total += pt2->pressure * average_fac;
885     /* Save max value. */
886     if (max_pressure < pt1->pressure) {
887       max_pressure = pt1->pressure;
888     }
889     if (max_pressure < pt2->pressure) {
890       max_pressure = pt2->pressure;
891     }
892   }
893
894   /* Based on influence factor, blend between original and optimal smoothed value. */
895   ptb->pressure = interpf(ptb->pressure, total, inf);
896   /* Clamp to maximum stroke thickness to avoid weird results. */
897   CLAMP_MAX(ptb->pressure, max_pressure);
898   return true;
899 }
900
901 /**
902  * Apply smooth for UV rotation to stroke point (use pressure).
903  */
904 bool BKE_gpencil_stroke_smooth_uv(bGPDstroke *gps, int point_index, float influence)
905 {
906   bGPDspoint *ptb = &gps->points[point_index];
907
908   /* Do nothing if not enough points */
909   if (gps->totpoints <= 2) {
910     return false;
911   }
912
913   /* Compute theoretical optimal value */
914   bGPDspoint *pta, *ptc;
915   int before = point_index - 1;
916   int after = point_index + 1;
917
918   CLAMP_MIN(before, 0);
919   CLAMP_MAX(after, gps->totpoints - 1);
920
921   pta = &gps->points[before];
922   ptc = &gps->points[after];
923
924   /* the optimal value is the corresponding to the interpolation of the pressure
925    * at the distance of point b
926    */
927   float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
928   /* sometimes the factor can be wrong due stroke geometry, so use middle point */
929   if ((fac < 0.0f) || (fac > 1.0f)) {
930     fac = 0.5f;
931   }
932   float optimal = interpf(ptc->uv_rot, pta->uv_rot, fac);
933
934   /* Based on influence factor, blend between original and optimal */
935   ptb->uv_rot = interpf(optimal, ptb->uv_rot, influence);
936   CLAMP(ptb->uv_rot, -M_PI_2, M_PI_2);
937
938   return true;
939 }
940 /* Get points of stroke always flat to view not affected by camera view or view position */
941 void BKE_gpencil_stroke_2d_flat(const bGPDspoint *points,
942                                 int totpoints,
943                                 float (*points2d)[2],
944                                 int *r_direction)
945 {
946   BLI_assert(totpoints >= 2);
947
948   const bGPDspoint *pt0 = &points[0];
949   const bGPDspoint *pt1 = &points[1];
950   const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
951
952   float locx[3];
953   float locy[3];
954   float loc3[3];
955   float normal[3];
956
957   /* local X axis (p0 -> p1) */
958   sub_v3_v3v3(locx, &pt1->x, &pt0->x);
959
960   /* point vector at 3/4 */
961   float v3[3];
962   if (totpoints == 2) {
963     mul_v3_v3fl(v3, &pt3->x, 0.001f);
964   }
965   else {
966     copy_v3_v3(v3, &pt3->x);
967   }
968
969   sub_v3_v3v3(loc3, v3, &pt0->x);
970
971   /* vector orthogonal to polygon plane */
972   cross_v3_v3v3(normal, locx, loc3);
973
974   /* local Y axis (cross to normal/x axis) */
975   cross_v3_v3v3(locy, normal, locx);
976
977   /* Normalize vectors */
978   normalize_v3(locx);
979   normalize_v3(locy);
980
981   /* Get all points in local space */
982   for (int i = 0; i < totpoints; i++) {
983     const bGPDspoint *pt = &points[i];
984     float loc[3];
985
986     /* Get local space using first point as origin */
987     sub_v3_v3v3(loc, &pt->x, &pt0->x);
988
989     points2d[i][0] = dot_v3v3(loc, locx);
990     points2d[i][1] = dot_v3v3(loc, locy);
991   }
992
993   /* Concave (-1), Convex (1), or Autodetect (0)? */
994   *r_direction = (int)locy[2];
995 }
996
997 /* Get points of stroke always flat to view not affected by camera view or view position
998  * using another stroke as reference
999  */
1000 void BKE_gpencil_stroke_2d_flat_ref(const bGPDspoint *ref_points,
1001                                     int ref_totpoints,
1002                                     const bGPDspoint *points,
1003                                     int totpoints,
1004                                     float (*points2d)[2],
1005                                     const float scale,
1006                                     int *r_direction)
1007 {
1008   BLI_assert(totpoints >= 2);
1009
1010   const bGPDspoint *pt0 = &ref_points[0];
1011   const bGPDspoint *pt1 = &ref_points[1];
1012   const bGPDspoint *pt3 = &ref_points[(int)(ref_totpoints * 0.75)];
1013
1014   float locx[3];
1015   float locy[3];
1016   float loc3[3];
1017   float normal[3];
1018
1019   /* local X axis (p0 -> p1) */
1020   sub_v3_v3v3(locx, &pt1->x, &pt0->x);
1021
1022   /* point vector at 3/4 */
1023   float v3[3];
1024   if (totpoints == 2) {
1025     mul_v3_v3fl(v3, &pt3->x, 0.001f);
1026   }
1027   else {
1028     copy_v3_v3(v3, &pt3->x);
1029   }
1030
1031   sub_v3_v3v3(loc3, v3, &pt0->x);
1032
1033   /* vector orthogonal to polygon plane */
1034   cross_v3_v3v3(normal, locx, loc3);
1035
1036   /* local Y axis (cross to normal/x axis) */
1037   cross_v3_v3v3(locy, normal, locx);
1038
1039   /* Normalize vectors */
1040   normalize_v3(locx);
1041   normalize_v3(locy);
1042
1043   /* Get all points in local space */
1044   for (int i = 0; i < totpoints; i++) {
1045     const bGPDspoint *pt = &points[i];
1046     float loc[3];
1047     float v1[3];
1048     float vn[3] = {0.0f, 0.0f, 0.0f};
1049
1050     /* apply scale to extremes of the stroke to get better collision detection
1051      * the scale is divided to get more control in the UI parameter
1052      */
1053     /* first point */
1054     if (i == 0) {
1055       const bGPDspoint *pt_next = &points[i + 1];
1056       sub_v3_v3v3(vn, &pt->x, &pt_next->x);
1057       normalize_v3(vn);
1058       mul_v3_fl(vn, scale / 10.0f);
1059       add_v3_v3v3(v1, &pt->x, vn);
1060     }
1061     /* last point */
1062     else if (i == totpoints - 1) {
1063       const bGPDspoint *pt_prev = &points[i - 1];
1064       sub_v3_v3v3(vn, &pt->x, &pt_prev->x);
1065       normalize_v3(vn);
1066       mul_v3_fl(vn, scale / 10.0f);
1067       add_v3_v3v3(v1, &pt->x, vn);
1068     }
1069     else {
1070       copy_v3_v3(v1, &pt->x);
1071     }
1072
1073     /* Get local space using first point as origin (ref stroke) */
1074     sub_v3_v3v3(loc, v1, &pt0->x);
1075
1076     points2d[i][0] = dot_v3v3(loc, locx);
1077     points2d[i][1] = dot_v3v3(loc, locy);
1078   }
1079
1080   /* Concave (-1), Convex (1), or Autodetect (0)? */
1081   *r_direction = (int)locy[2];
1082 }
1083
1084 /* calc texture coordinates using flat projected points */
1085 static void gpencil_calc_stroke_fill_uv(const float (*points2d)[2],
1086                                         bGPDstroke *gps,
1087                                         const float minv[2],
1088                                         float maxv[2],
1089                                         float (*r_uv)[2])
1090 {
1091   const float s = sin(gps->uv_rotation);
1092   const float c = cos(gps->uv_rotation);
1093
1094   /* Calc center for rotation. */
1095   float center[2] = {0.5f, 0.5f};
1096   float d[2];
1097   d[0] = maxv[0] - minv[0];
1098   d[1] = maxv[1] - minv[1];
1099   for (int i = 0; i < gps->totpoints; i++) {
1100     r_uv[i][0] = (points2d[i][0] - minv[0]) / d[0];
1101     r_uv[i][1] = (points2d[i][1] - minv[1]) / d[1];
1102
1103     /* Apply translation. */
1104     add_v2_v2(r_uv[i], gps->uv_translation);
1105
1106     /* Apply Rotation. */
1107     r_uv[i][0] -= center[0];
1108     r_uv[i][1] -= center[1];
1109
1110     float x = r_uv[i][0] * c - r_uv[i][1] * s;
1111     float y = r_uv[i][0] * s + r_uv[i][1] * c;
1112
1113     r_uv[i][0] = x + center[0];
1114     r_uv[i][1] = y + center[1];
1115
1116     /* Apply scale. */
1117     if (gps->uv_scale != 0.0f) {
1118       mul_v2_fl(r_uv[i], 1.0f / gps->uv_scale);
1119     }
1120   }
1121 }
1122
1123 /* Triangulate stroke for high quality fill (this is done only if cache is null or stroke was
1124  * modified) */
1125 void BKE_gpencil_stroke_fill_triangulate(bGPDstroke *gps)
1126 {
1127   BLI_assert(gps->totpoints >= 3);
1128
1129   /* allocate memory for temporary areas */
1130   gps->tot_triangles = gps->totpoints - 2;
1131   uint(*tmp_triangles)[3] = MEM_mallocN(sizeof(*tmp_triangles) * gps->tot_triangles,
1132                                         "GP Stroke temp triangulation");
1133   float(*points2d)[2] = MEM_mallocN(sizeof(*points2d) * gps->totpoints,
1134                                     "GP Stroke temp 2d points");
1135   float(*uv)[2] = MEM_mallocN(sizeof(*uv) * gps->totpoints, "GP Stroke temp 2d uv data");
1136
1137   int direction = 0;
1138
1139   /* convert to 2d and triangulate */
1140   BKE_gpencil_stroke_2d_flat(gps->points, gps->totpoints, points2d, &direction);
1141   BLI_polyfill_calc(points2d, (uint)gps->totpoints, direction, tmp_triangles);
1142
1143   /* calc texture coordinates automatically */
1144   float minv[2];
1145   float maxv[2];
1146   /* first needs bounding box data */
1147   ARRAY_SET_ITEMS(minv, -1.0f, -1.0f);
1148   ARRAY_SET_ITEMS(maxv, 1.0f, 1.0f);
1149
1150   /* calc uv data */
1151   gpencil_calc_stroke_fill_uv(points2d, gps, minv, maxv, uv);
1152
1153   /* Save triangulation data. */
1154   if (gps->tot_triangles > 0) {
1155     MEM_SAFE_FREE(gps->triangles);
1156     gps->triangles = MEM_callocN(sizeof(*gps->triangles) * gps->tot_triangles,
1157                                  "GP Stroke triangulation");
1158
1159     for (int i = 0; i < gps->tot_triangles; i++) {
1160       memcpy(gps->triangles[i].verts, tmp_triangles[i], sizeof(uint[3]));
1161     }
1162
1163     /* Copy UVs to bGPDspoint. */
1164     for (int i = 0; i < gps->totpoints; i++) {
1165       copy_v2_v2(gps->points[i].uv_fill, uv[i]);
1166     }
1167   }
1168   else {
1169     /* No triangles needed - Free anything allocated previously */
1170     if (gps->triangles) {
1171       MEM_freeN(gps->triangles);
1172     }
1173
1174     gps->triangles = NULL;
1175   }
1176
1177   /* clear memory */
1178   MEM_SAFE_FREE(tmp_triangles);
1179   MEM_SAFE_FREE(points2d);
1180   MEM_SAFE_FREE(uv);
1181 }
1182
1183 /* texture coordinate utilities */
1184 void BKE_gpencil_stroke_uv_update(bGPDstroke *gps)
1185 {
1186   if (gps == NULL || gps->totpoints == 0) {
1187     return;
1188   }
1189
1190   bGPDspoint *pt = gps->points;
1191   float totlen = 0.0f;
1192   pt[0].uv_fac = totlen;
1193   for (int i = 1; i < gps->totpoints; i++) {
1194     totlen += len_v3v3(&pt[i - 1].x, &pt[i].x);
1195     pt[i].uv_fac = totlen;
1196   }
1197 }
1198
1199 /* Recalc the internal geometry caches for fill and uvs. */
1200 void BKE_gpencil_stroke_geometry_update(bGPDstroke *gps)
1201 {
1202   if (gps == NULL) {
1203     return;
1204   }
1205
1206   if (gps->totpoints > 2) {
1207     BKE_gpencil_stroke_fill_triangulate(gps);
1208   }
1209   else {
1210     gps->tot_triangles = 0;
1211     MEM_SAFE_FREE(gps->triangles);
1212   }
1213
1214   /* calc uv data along the stroke */
1215   BKE_gpencil_stroke_uv_update(gps);
1216
1217   /* Calc stroke bounding box. */
1218   BKE_gpencil_stroke_boundingbox_calc(gps);
1219 }
1220
1221 float BKE_gpencil_stroke_length(const bGPDstroke *gps, bool use_3d)
1222 {
1223   if (!gps->points || gps->totpoints < 2) {
1224     return 0.0f;
1225   }
1226   float *last_pt = &gps->points[0].x;
1227   int i;
1228   bGPDspoint *pt;
1229   float total_length = 0.0f;
1230   for (i = 1; i < gps->totpoints; i++) {
1231     pt = &gps->points[i];
1232     if (use_3d) {
1233       total_length += len_v3v3(&pt->x, last_pt);
1234     }
1235     else {
1236       total_length += len_v2v2(&pt->x, last_pt);
1237     }
1238     last_pt = &pt->x;
1239   }
1240   return total_length;
1241 }
1242
1243 /**
1244  * Trim stroke to the first intersection or loop
1245  * \param gps: Stroke data
1246  */
1247 bool BKE_gpencil_stroke_trim(bGPDstroke *gps)
1248 {
1249   if (gps->totpoints < 4) {
1250     return false;
1251   }
1252   bool intersect = false;
1253   int start, end;
1254   float point[3];
1255   /* loop segments from start until we have an intersection */
1256   for (int i = 0; i < gps->totpoints - 2; i++) {
1257     start = i;
1258     bGPDspoint *a = &gps->points[start];
1259     bGPDspoint *b = &gps->points[start + 1];
1260     for (int j = start + 2; j < gps->totpoints - 1; j++) {
1261       end = j + 1;
1262       bGPDspoint *c = &gps->points[j];
1263       bGPDspoint *d = &gps->points[end];
1264       float pointb[3];
1265       /* get intersection */
1266       if (isect_line_line_v3(&a->x, &b->x, &c->x, &d->x, point, pointb)) {
1267         if (len_v3(point) > 0.0f) {
1268           float closest[3];
1269           /* check intersection is on both lines */
1270           float lambda = closest_to_line_v3(closest, point, &a->x, &b->x);
1271           if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
1272             continue;
1273           }
1274           lambda = closest_to_line_v3(closest, point, &c->x, &d->x);
1275           if ((lambda <= 0.0f) || (lambda >= 1.0f)) {
1276             continue;
1277           }
1278           else {
1279             intersect = true;
1280             break;
1281           }
1282         }
1283       }
1284     }
1285     if (intersect) {
1286       break;
1287     }
1288   }
1289
1290   /* trim unwanted points */
1291   if (intersect) {
1292
1293     /* save points */
1294     bGPDspoint *old_points = MEM_dupallocN(gps->points);
1295     MDeformVert *old_dvert = NULL;
1296     MDeformVert *dvert_src = NULL;
1297
1298     if (gps->dvert != NULL) {
1299       old_dvert = MEM_dupallocN(gps->dvert);
1300     }
1301
1302     /* resize gps */
1303     int newtot = end - start + 1;
1304
1305     gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
1306     if (gps->dvert != NULL) {
1307       gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
1308     }
1309
1310     for (int i = 0; i < newtot; i++) {
1311       int idx = start + i;
1312       bGPDspoint *pt_src = &old_points[idx];
1313       bGPDspoint *pt_new = &gps->points[i];
1314       memcpy(pt_new, pt_src, sizeof(bGPDspoint));
1315       if (gps->dvert != NULL) {
1316         dvert_src = &old_dvert[idx];
1317         MDeformVert *dvert = &gps->dvert[i];
1318         memcpy(dvert, dvert_src, sizeof(MDeformVert));
1319         if (dvert_src->dw) {
1320           memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
1321         }
1322       }
1323       if (idx == start || idx == end) {
1324         copy_v3_v3(&pt_new->x, point);
1325       }
1326     }
1327
1328     gps->totpoints = newtot;
1329
1330     MEM_SAFE_FREE(old_points);
1331     MEM_SAFE_FREE(old_dvert);
1332   }
1333
1334   BKE_gpencil_stroke_geometry_update(gps);
1335
1336   return intersect;
1337 }
1338
1339 /**
1340  * Close stroke
1341  * \param gps: Stroke to close
1342  */
1343 bool BKE_gpencil_stroke_close(bGPDstroke *gps)
1344 {
1345   bGPDspoint *pt1 = NULL;
1346   bGPDspoint *pt2 = NULL;
1347
1348   /* Only can close a stroke with 3 points or more. */
1349   if (gps->totpoints < 3) {
1350     return false;
1351   }
1352
1353   /* Calc average distance between points to get same level of sampling. */
1354   float dist_tot = 0.0f;
1355   for (int i = 0; i < gps->totpoints - 1; i++) {
1356     pt1 = &gps->points[i];
1357     pt2 = &gps->points[i + 1];
1358     dist_tot += len_v3v3(&pt1->x, &pt2->x);
1359   }
1360   /* Calc the average distance. */
1361   float dist_avg = dist_tot / (gps->totpoints - 1);
1362
1363   /* Calc distance between last and first point. */
1364   pt1 = &gps->points[gps->totpoints - 1];
1365   pt2 = &gps->points[0];
1366   float dist_close = len_v3v3(&pt1->x, &pt2->x);
1367
1368   /* if the distance to close is very small, don't need add points and just enable cyclic. */
1369   if (dist_close <= dist_avg) {
1370     gps->flag |= GP_STROKE_CYCLIC;
1371     return true;
1372   }
1373
1374   /* Calc number of points required using the average distance. */
1375   int tot_newpoints = MAX2(dist_close / dist_avg, 1);
1376
1377   /* Resize stroke array. */
1378   int old_tot = gps->totpoints;
1379   gps->totpoints += tot_newpoints;
1380   gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
1381   if (gps->dvert != NULL) {
1382     gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
1383   }
1384
1385   /* Generate new points */
1386   pt1 = &gps->points[old_tot - 1];
1387   pt2 = &gps->points[0];
1388   bGPDspoint *pt = &gps->points[old_tot];
1389   for (int i = 1; i < tot_newpoints + 1; i++, pt++) {
1390     float step = (tot_newpoints > 1) ? ((float)i / (float)tot_newpoints) : 0.99f;
1391     /* Clamp last point to be near, but not on top of first point. */
1392     if ((tot_newpoints > 1) && (i == tot_newpoints)) {
1393       step *= 0.99f;
1394     }
1395
1396     /* Average point. */
1397     interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step);
1398     pt->pressure = interpf(pt2->pressure, pt1->pressure, step);
1399     pt->strength = interpf(pt2->strength, pt1->strength, step);
1400     pt->flag = 0;
1401     interp_v4_v4v4(pt->vert_color, pt1->vert_color, pt2->vert_color, step);
1402
1403     /* Set weights. */
1404     if (gps->dvert != NULL) {
1405       MDeformVert *dvert1 = &gps->dvert[old_tot - 1];
1406       MDeformWeight *dw1 = BKE_defvert_ensure_index(dvert1, 0);
1407       float weight_1 = dw1 ? dw1->weight : 0.0f;
1408
1409       MDeformVert *dvert2 = &gps->dvert[0];
1410       MDeformWeight *dw2 = BKE_defvert_ensure_index(dvert2, 0);
1411       float weight_2 = dw2 ? dw2->weight : 0.0f;
1412
1413       MDeformVert *dvert_final = &gps->dvert[old_tot + i - 1];
1414       dvert_final->totweight = 0;
1415       MDeformWeight *dw = BKE_defvert_ensure_index(dvert_final, 0);
1416       if (dvert_final->dw) {
1417         dw->weight = interpf(weight_2, weight_1, step);
1418       }
1419     }
1420   }
1421
1422   /* Enable cyclic flag. */
1423   gps->flag |= GP_STROKE_CYCLIC;
1424
1425   return true;
1426 }
1427 /* Dissolve points in stroke */
1428 void BKE_gpencil_dissolve_points(bGPDframe *gpf, bGPDstroke *gps, const short tag)
1429 {
1430   bGPDspoint *pt;
1431   MDeformVert *dvert = NULL;
1432   int i;
1433
1434   int tot = gps->totpoints; /* number of points in new buffer */
1435   /* first pass: count points to remove */
1436   /* Count how many points are selected (i.e. how many to remove) */
1437   for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1438     if (pt->flag & tag) {
1439       /* selected point - one of the points to remove */
1440       tot--;
1441     }
1442   }
1443
1444   /* if no points are left, we simply delete the entire stroke */
1445   if (tot <= 0) {
1446     /* remove the entire stroke */
1447     if (gps->points) {
1448       MEM_freeN(gps->points);
1449     }
1450     if (gps->dvert) {
1451       BKE_gpencil_free_stroke_weights(gps);
1452       MEM_freeN(gps->dvert);
1453     }
1454     if (gps->triangles) {
1455       MEM_freeN(gps->triangles);
1456     }
1457     BLI_freelinkN(&gpf->strokes, gps);
1458   }
1459   else {
1460     /* just copy all points to keep into a smaller buffer */
1461     bGPDspoint *new_points = MEM_callocN(sizeof(bGPDspoint) * tot, "new gp stroke points copy");
1462     bGPDspoint *npt = new_points;
1463
1464     MDeformVert *new_dvert = NULL;
1465     MDeformVert *ndvert = NULL;
1466
1467     if (gps->dvert != NULL) {
1468       new_dvert = MEM_callocN(sizeof(MDeformVert) * tot, "new gp stroke weights copy");
1469       ndvert = new_dvert;
1470     }
1471
1472     (gps->dvert != NULL) ? dvert = gps->dvert : NULL;
1473     for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
1474       if ((pt->flag & tag) == 0) {
1475         *npt = *pt;
1476         npt++;
1477
1478         if (gps->dvert != NULL) {
1479           *ndvert = *dvert;
1480           ndvert->dw = MEM_dupallocN(dvert->dw);
1481           ndvert++;
1482         }
1483       }
1484       if (gps->dvert != NULL) {
1485         dvert++;
1486       }
1487     }
1488
1489     /* free the old buffer */
1490     if (gps->points) {
1491       MEM_freeN(gps->points);
1492     }
1493     if (gps->dvert) {
1494       BKE_gpencil_free_stroke_weights(gps);
1495       MEM_freeN(gps->dvert);
1496     }
1497
1498     /* save the new buffer */
1499     gps->points = new_points;
1500     gps->dvert = new_dvert;
1501     gps->totpoints = tot;
1502
1503     /* triangles cache needs to be recalculated */
1504     BKE_gpencil_stroke_geometry_update(gps);
1505   }
1506 }
1507
1508 /* Merge by distance ------------------------------------- */
1509 /* Reduce a series of points when the distance is below a threshold.
1510  * Special case for first and last points (both are keeped) for other points,
1511  * the merge point always is at first point.
1512  * \param gpf: Grease Pencil frame
1513  * \param gps: Grease Pencil stroke
1514  * \param threshold: Distance between points
1515  * \param use_unselected: Set to true to analyze all stroke and not only selected points
1516  */
1517 void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
1518                                        bGPDstroke *gps,
1519                                        const float threshold,
1520                                        const bool use_unselected)
1521 {
1522   bGPDspoint *pt = NULL;
1523   bGPDspoint *pt_next = NULL;
1524   float tagged = false;
1525   /* Use square distance to speed up loop */
1526   const float th_square = threshold * threshold;
1527   /* Need to have something to merge. */
1528   if (gps->totpoints < 2) {
1529     return;
1530   }
1531   int i = 0;
1532   int step = 1;
1533   while ((i < gps->totpoints - 1) && (i + step < gps->totpoints)) {
1534     pt = &gps->points[i];
1535     if (pt->flag & GP_SPOINT_TAG) {
1536       i++;
1537       step = 1;
1538       continue;
1539     }
1540     pt_next = &gps->points[i + step];
1541     /* Do not recalc tagged points. */
1542     if (pt_next->flag & GP_SPOINT_TAG) {
1543       step++;
1544       continue;
1545     }
1546     /* Check if contiguous points are selected. */
1547     if (!use_unselected) {
1548       if (((pt->flag & GP_SPOINT_SELECT) == 0) || ((pt_next->flag & GP_SPOINT_SELECT) == 0)) {
1549         i++;
1550         step = 1;
1551         continue;
1552       }
1553     }
1554     float len_square = len_squared_v3v3(&pt->x, &pt_next->x);
1555     if (len_square <= th_square) {
1556       tagged = true;
1557       if (i != gps->totpoints - 1) {
1558         /* Tag second point for delete. */
1559         pt_next->flag |= GP_SPOINT_TAG;
1560       }
1561       else {
1562         pt->flag |= GP_SPOINT_TAG;
1563       }
1564       /* Jump to next pair of points, keeping first point segment equals.*/
1565       step++;
1566     }
1567     else {
1568       /* Analyze next point. */
1569       i++;
1570       step = 1;
1571     }
1572   }
1573
1574   /* Always untag extremes. */
1575   pt = &gps->points[0];
1576   pt->flag &= ~GP_SPOINT_TAG;
1577   pt = &gps->points[gps->totpoints - 1];
1578   pt->flag &= ~GP_SPOINT_TAG;
1579
1580   /* Dissolve tagged points */
1581   if (tagged) {
1582     BKE_gpencil_dissolve_points(gpf, gps, GP_SPOINT_TAG);
1583   }
1584
1585   /* Calc geometry data. */
1586   BKE_gpencil_stroke_geometry_update(gps);
1587 }
1588
1589 /* Helper: Check materials with same color. */
1590 static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
1591 {
1592   Material *ma = NULL;
1593   float color_cu[4];
1594   linearrgb_to_srgb_v3_v3(color_cu, color);
1595   float hsv1[4];
1596   rgb_to_hsv_v(color_cu, hsv1);
1597   hsv1[3] = color[3];
1598
1599   for (int i = 1; i <= ob_gp->totcol; i++) {
1600     ma = BKE_object_material_get(ob_gp, i);
1601     MaterialGPencilStyle *gp_style = ma->gp_style;
1602     /* Check color with small tolerance (better in HSV). */
1603     float hsv2[4];
1604     rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
1605     hsv2[3] = gp_style->fill_rgba[3];
1606     if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
1607         (compare_v4v4(hsv1, hsv2, 0.01f))) {
1608       *r_mat = ma;
1609       return i - 1;
1610     }
1611   }
1612
1613   *r_mat = NULL;
1614   return -1;
1615 }
1616
1617 /* Helper: Add gpencil material using curve material as base. */
1618 static Material *gpencil_add_from_curve_material(Main *bmain,
1619                                                  Object *ob_gp,
1620                                                  const float cu_color[4],
1621                                                  const bool gpencil_lines,
1622                                                  const bool fill,
1623                                                  int *r_idx)
1624 {
1625   Material *mat_gp = BKE_gpencil_object_material_new(
1626       bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
1627   MaterialGPencilStyle *gp_style = mat_gp->gp_style;
1628
1629   /* Stroke color. */
1630   if (gpencil_lines) {
1631     ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
1632     gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
1633   }
1634   else {
1635     linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
1636     gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
1637   }
1638
1639   /* Fill color. */
1640   linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
1641   /* Fill is false if the original curve hasn't material assigned, so enable it. */
1642   if (fill) {
1643     gp_style->flag |= GP_MATERIAL_FILL_SHOW;
1644   }
1645
1646   /* Check at least one is enabled. */
1647   if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
1648       ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
1649     gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
1650   }
1651
1652   return mat_gp;
1653 }
1654
1655 /* Helper: Create new stroke section. */
1656 static void gpencil_add_new_points(bGPDstroke *gps,
1657                                    float *coord_array,
1658                                    float pressure,
1659                                    int init,
1660                                    int totpoints,
1661                                    const float init_co[3],
1662                                    bool last)
1663 {
1664   for (int i = 0; i < totpoints; i++) {
1665     bGPDspoint *pt = &gps->points[i + init];
1666     copy_v3_v3(&pt->x, &coord_array[3 * i]);
1667     /* Be sure the last point is not on top of the first point of the curve or
1668      * the close of the stroke will produce glitches. */
1669     if ((last) && (i > 0) && (i == totpoints - 1)) {
1670       float dist = len_v3v3(init_co, &pt->x);
1671       if (dist < 0.1f) {
1672         /* Interpolate between previous point and current to back slightly. */
1673         bGPDspoint *pt_prev = &gps->points[i + init - 1];
1674         interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
1675       }
1676     }
1677
1678     pt->pressure = pressure;
1679     pt->strength = 1.0f;
1680   }
1681 }
1682
1683 /* Helper: Get the first collection that includes the object. */
1684 static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
1685 {
1686   Collection *mycol = NULL;
1687   FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
1688     LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
1689       if ((mycol == NULL) && (cob->ob == ob)) {
1690         mycol = collection;
1691       }
1692     }
1693   }
1694   FOREACH_SCENE_COLLECTION_END;
1695
1696   return mycol;
1697 }
1698
1699 /* Helper: Convert one spline to grease pencil stroke. */
1700 static void gpencil_convert_spline(Main *bmain,
1701                                    Object *ob_gp,
1702                                    Object *ob_cu,
1703                                    const bool gpencil_lines,
1704                                    const bool only_stroke,
1705                                    bGPDframe *gpf,
1706                                    Nurb *nu)
1707 {
1708   Curve *cu = (Curve *)ob_cu->data;
1709   bool cyclic = true;
1710
1711   /* Create Stroke. */
1712   bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
1713   gps->thickness = 10.0f;
1714   gps->fill_opacity_fac = 1.0f;
1715   gps->hardeness = 1.0f;
1716   gps->uv_scale = 1.0f;
1717
1718   ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
1719   ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
1720   gps->inittime = 0.0f;
1721
1722   gps->flag &= ~GP_STROKE_SELECT;
1723   gps->flag |= GP_STROKE_3DSPACE;
1724
1725   gps->mat_nr = 0;
1726   /* Count total points
1727    * The total of points must consider that last point of each segment is equal to the first
1728    * point of next segment.
1729    */
1730   int totpoints = 0;
1731   int segments = 0;
1732   int resolu = nu->resolu + 1;
1733   segments = nu->pntsu;
1734   if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
1735     segments--;
1736     cyclic = false;
1737   }
1738   totpoints = (resolu * segments) - (segments - 1);
1739
1740   /* Materials
1741    * Notice: The color of the material is the color of viewport and not the final shader color.
1742    */
1743   Material *mat_gp = NULL;
1744   bool fill = true;
1745   /* Check if grease pencil has a material with same color.*/
1746   float color[4];
1747   if ((cu->mat) && (*cu->mat)) {
1748     Material *mat_cu = *cu->mat;
1749     copy_v4_v4(color, &mat_cu->r);
1750   }
1751   else {
1752     /* Gray (unassigned from SVG add-on) */
1753     zero_v4(color);
1754     add_v3_fl(color, 0.6f);
1755     color[3] = 1.0f;
1756     fill = false;
1757   }
1758
1759   /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
1760    * there is only one color, the stroke must not be closed, fill to false and use for
1761    * stroke the fill color.
1762    */
1763   bool do_stroke = false;
1764   if (ob_cu->totcol == 1) {
1765     Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
1766     if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
1767       do_stroke = true;
1768     }
1769   }
1770
1771   int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
1772   if ((ob_cu->totcol > 0) && (r_idx < 0)) {
1773     Material *mat_curve = BKE_object_material_get(ob_cu, 1);
1774     mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
1775
1776     if ((mat_curve) && (mat_curve->gp_style != NULL)) {
1777       MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
1778       MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
1779
1780       copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
1781       gp_style_gp->fill_style = gp_style_cur->fill_style;
1782       gp_style_gp->mix_factor = gp_style_cur->mix_factor;
1783     }
1784
1785     /* If object has more than 1 material, use second material for stroke color. */
1786     if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
1787       mat_curve = BKE_object_material_get(ob_cu, 2);
1788       if (mat_curve) {
1789         linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
1790         mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
1791       }
1792     }
1793     else if ((only_stroke) || (do_stroke)) {
1794       /* Also use the first color if the fill is none for stroke color. */
1795       if (ob_cu->totcol > 0) {
1796         mat_curve = BKE_object_material_get(ob_cu, 1);
1797         if (mat_curve) {
1798           copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
1799           mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
1800           /* Set fill and stroke depending of curve type (3D or 2D). */
1801           if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
1802             mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
1803             mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
1804           }
1805           else {
1806             mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
1807             mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
1808           }
1809         }
1810       }
1811     }
1812   }
1813   CLAMP_MIN(r_idx, 0);
1814
1815   /* Assign material index to stroke. */
1816   gps->mat_nr = r_idx;
1817
1818   /* Add stroke to frame.*/
1819   BLI_addtail(&gpf->strokes, gps);
1820
1821   float *coord_array = NULL;
1822   float init_co[3];
1823
1824   switch (nu->type) {
1825     case CU_POLY: {
1826       /* Allocate memory for storage points. */
1827       gps->totpoints = nu->pntsu;
1828       gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
1829       /* Increase thickness for this type. */
1830       gps->thickness = 10.0f;
1831
1832       /* Get all curve points */
1833       for (int s = 0; s < gps->totpoints; s++) {
1834         BPoint *bp = &nu->bp[s];
1835         bGPDspoint *pt = &gps->points[s];
1836         copy_v3_v3(&pt->x, bp->vec);
1837         pt->pressure = bp->radius;
1838         pt->strength = 1.0f;
1839       }
1840       break;
1841     }
1842     case CU_BEZIER: {
1843       /* Allocate memory for storage points. */
1844       gps->totpoints = totpoints;
1845       gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
1846
1847       int init = 0;
1848       resolu = nu->resolu + 1;
1849       segments = nu->pntsu;
1850       if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
1851         segments--;
1852       }
1853       /* Get all interpolated curve points of Beziert */
1854       for (int s = 0; s < segments; s++) {
1855         int inext = (s + 1) % nu->pntsu;
1856         BezTriple *prevbezt = &nu->bezt[s];
1857         BezTriple *bezt = &nu->bezt[inext];
1858         bool last = (bool)(s == segments - 1);
1859
1860         coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
1861
1862         for (int j = 0; j < 3; j++) {
1863           BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
1864                                         prevbezt->vec[2][j],
1865                                         bezt->vec[0][j],
1866                                         bezt->vec[1][j],
1867                                         coord_array + j,
1868                                         resolu - 1,
1869                                         3 * sizeof(float));
1870         }
1871         /* Save first point coordinates. */
1872         if (s == 0) {
1873           copy_v3_v3(init_co, &coord_array[0]);
1874         }
1875         /* Add points to the stroke */
1876         gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
1877         /* Free memory. */
1878         MEM_SAFE_FREE(coord_array);
1879
1880         /* As the last point of segment is the first point of next segment, back one array
1881          * element to avoid duplicated points on the same location.
1882          */
1883         init += resolu - 1;
1884       }
1885       break;
1886     }
1887     case CU_NURBS: {
1888       if (nu->pntsv == 1) {
1889
1890         int nurb_points;
1891         if (nu->flagu & CU_NURB_CYCLIC) {
1892           resolu++;
1893           nurb_points = nu->pntsu * resolu;
1894         }
1895         else {
1896           nurb_points = (nu->pntsu - 1) * resolu;
1897         }
1898         /* Get all curve points. */
1899         coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
1900         BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
1901
1902         /* Allocate memory for storage points. */
1903         gps->totpoints = nurb_points - 1;
1904         gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
1905
1906         /* Add points. */
1907         gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
1908
1909         MEM_SAFE_FREE(coord_array);
1910       }
1911       break;
1912     }
1913     default: {
1914       break;
1915     }
1916   }
1917   /* Cyclic curve, close stroke. */
1918   if ((cyclic) && (!do_stroke)) {
1919     BKE_gpencil_stroke_close(gps);
1920   }
1921
1922   /* Recalc fill geometry. */
1923   BKE_gpencil_stroke_geometry_update(gps);
1924 }
1925
1926 /* Convert a curve object to grease pencil stroke.
1927  *
1928  * \param bmain: Main thread pointer
1929  * \param scene: Original scene.
1930  * \param ob_gp: Grease pencil object to add strokes.
1931  * \param ob_cu: Curve to convert.
1932  * \param gpencil_lines: Use lines for strokes.
1933  * \param use_collections: Create layers using collection names.
1934  * \param only_stroke: The material must be only stroke without fill.
1935  */
1936 void BKE_gpencil_convert_curve(Main *bmain,
1937                                Scene *scene,
1938                                Object *ob_gp,
1939                                Object *ob_cu,
1940                                const bool gpencil_lines,
1941                                const bool use_collections,
1942                                const bool only_stroke)
1943 {
1944   if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
1945     return;
1946   }
1947
1948   Curve *cu = (Curve *)ob_cu->data;
1949   bGPdata *gpd = (bGPdata *)ob_gp->data;
1950   bGPDlayer *gpl = NULL;
1951
1952   /* If the curve is empty, cancel. */
1953   if (cu->nurb.first == NULL) {
1954     return;
1955   }
1956
1957   /* Check if there is an active layer. */
1958   if (use_collections) {
1959     Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
1960     if (collection != NULL) {
1961       gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
1962       if (gpl == NULL) {
1963         gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
1964       }
1965     }
1966   }
1967
1968   if (gpl == NULL) {
1969     gpl = BKE_gpencil_layer_active_get(gpd);
1970     if (gpl == NULL) {
1971       gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
1972     }
1973   }
1974
1975   /* Check if there is an active frame and add if needed. */
1976   bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
1977
1978   /* Read all splines of the curve and create a stroke for each. */
1979   LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
1980     gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
1981   }
1982
1983   /* Tag for recalculation */
1984   DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
1985 }
1986
1987 /* Apply Transforms */
1988 void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
1989 {
1990   if (gpd == NULL) {
1991     return;
1992   }
1993
1994   const float scalef = mat4_to_scale(mat);
1995   LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
1996     /* FIXME: For now, we just skip parented layers.
1997      * Otherwise, we have to update each frame to find
1998      * the current parent position/effects.
1999      */
2000     if (gpl->parent) {
2001       continue;
2002     }
2003
2004     LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
2005       LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
2006         bGPDspoint *pt;
2007         int i;
2008
2009         for (pt = gps->points, i = 0; i < gps->totpoints; pt++, i++) {
2010           mul_m4_v3(mat, &pt->x);
2011           pt->pressure *= scalef;
2012         }
2013
2014         /* Distortion may mean we need to re-triangulate. */
2015         BKE_gpencil_stroke_geometry_update(gps);
2016       }
2017     }
2018   }
2019 }
2020 /** \} */