Merge branch 'blender2.7'
[blender.git] / source / blender / blenkernel / intern / gpencil_modifier.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2017, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Antonio Vazquez
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26  /** \file blender/blenkernel/intern/gpencil_modifier.c
27   *  \ingroup bke
28   */
29
30
31 #include <stdio.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_blenlib.h"
36 #include "BLI_utildefines.h"
37 #include "BLI_math_vector.h"
38 #include "BLI_string_utils.h"
39
40 #include "BLT_translation.h"
41
42 #include "DNA_meshdata_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_gpencil_types.h"
46 #include "DNA_gpencil_modifier_types.h"
47
48 #include "BKE_library.h"
49 #include "BKE_library_query.h"
50 #include "BKE_gpencil.h"
51 #include "BKE_lattice.h"
52 #include "BKE_gpencil_modifier.h"
53 #include "BKE_object.h"
54
55 #include "DEG_depsgraph.h"
56 #include "DEG_depsgraph_query.h"
57
58 #include "MOD_gpencil_modifiertypes.h"
59
60 static GpencilModifierTypeInfo *modifier_gpencil_types[NUM_GREASEPENCIL_MODIFIER_TYPES] = { NULL };
61
62 /* *************************************************** */
63 /* Geometry Utilities */
64
65 /* calculate stroke normal using some points */
66 void BKE_gpencil_stroke_normal(const bGPDstroke *gps, float r_normal[3])
67 {
68         if (gps->totpoints < 3) {
69                 zero_v3(r_normal);
70                 return;
71         }
72
73         bGPDspoint *points = gps->points;
74         int totpoints = gps->totpoints;
75
76         const bGPDspoint *pt0 = &points[0];
77         const bGPDspoint *pt1 = &points[1];
78         const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
79
80         float vec1[3];
81         float vec2[3];
82
83         /* initial vector (p0 -> p1) */
84         sub_v3_v3v3(vec1, &pt1->x, &pt0->x);
85
86         /* point vector at 3/4 */
87         sub_v3_v3v3(vec2, &pt3->x, &pt0->x);
88
89         /* vector orthogonal to polygon plane */
90         cross_v3_v3v3(r_normal, vec1, vec2);
91
92         /* Normalize vector */
93         normalize_v3(r_normal);
94 }
95
96 /* Get points of stroke always flat to view not affected by camera view or view position */
97 static void gpencil_stroke_project_2d(const bGPDspoint *points, int totpoints, vec2f *points2d)
98 {
99         const bGPDspoint *pt0 = &points[0];
100         const bGPDspoint *pt1 = &points[1];
101         const bGPDspoint *pt3 = &points[(int)(totpoints * 0.75)];
102
103         float locx[3];
104         float locy[3];
105         float loc3[3];
106         float normal[3];
107
108         /* local X axis (p0 -> p1) */
109         sub_v3_v3v3(locx, &pt1->x, &pt0->x);
110
111         /* point vector at 3/4 */
112         sub_v3_v3v3(loc3, &pt3->x, &pt0->x);
113
114         /* vector orthogonal to polygon plane */
115         cross_v3_v3v3(normal, locx, loc3);
116
117         /* local Y axis (cross to normal/x axis) */
118         cross_v3_v3v3(locy, normal, locx);
119
120         /* Normalize vectors */
121         normalize_v3(locx);
122         normalize_v3(locy);
123
124         /* Get all points in local space */
125         for (int i = 0; i < totpoints; i++) {
126                 const bGPDspoint *pt = &points[i];
127                 float loc[3];
128
129                 /* Get local space using first point as origin */
130                 sub_v3_v3v3(loc, &pt->x, &pt0->x);
131
132                 vec2f *point = &points2d[i];
133                 point->x = dot_v3v3(loc, locx);
134                 point->y = dot_v3v3(loc, locy);
135         }
136
137 }
138
139 /* Stroke Simplify ------------------------------------- */
140
141 /* Reduce a series of points to a simplified version, but
142  * maintains the general shape of the series
143  *
144  * Ramer - Douglas - Peucker algorithm
145  * by http ://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
146  */
147 static void gpencil_rdp_stroke(bGPDstroke *gps, vec2f *points2d, float epsilon)
148 {
149         vec2f *old_points2d = points2d;
150         int totpoints = gps->totpoints;
151         char *marked = NULL;
152         char work;
153
154         int start = 1;
155         int end = gps->totpoints - 2;
156
157         marked = MEM_callocN(totpoints, "GP marked array");
158         marked[start] = 1;
159         marked[end] = 1;
160
161         work = 1;
162         int totmarked = 0;
163         /* while still reducing */
164         while (work) {
165                 int ls, le;
166                 work = 0;
167
168                 ls = start;
169                 le = start + 1;
170
171                 /* while not over interval */
172                 while (ls < end) {
173                         int max_i = 0;
174                         float v1[2];
175                         /* divided to get more control */
176                         float max_dist = epsilon / 10.0f;
177
178                         /* find the next marked point */
179                         while (marked[le] == 0) {
180                                 le++;
181                         }
182
183                         /* perpendicular vector to ls-le */
184                         v1[1] = old_points2d[le].x - old_points2d[ls].x;
185                         v1[0] = old_points2d[ls].y - old_points2d[le].y;
186
187                         for (int i = ls + 1; i < le; i++) {
188                                 float mul;
189                                 float dist;
190                                 float v2[2];
191
192                                 v2[0] = old_points2d[i].x - old_points2d[ls].x;
193                                 v2[1] = old_points2d[i].y - old_points2d[ls].y;
194
195                                 if (v2[0] == 0 && v2[1] == 0) {
196                                         continue;
197                                 }
198
199                                 mul = (float)(v1[0] * v2[0] + v1[1] * v2[1]) / (float)(v2[0] * v2[0] + v2[1] * v2[1]);
200
201                                 dist = mul * mul * (v2[0] * v2[0] + v2[1] * v2[1]);
202
203                                 if (dist > max_dist) {
204                                         max_dist = dist;
205                                         max_i = i;
206                                 }
207                         }
208
209                         if (max_i != 0) {
210                                 work = 1;
211                                 marked[max_i] = 1;
212                                 totmarked++;
213                         }
214
215                         ls = le;
216                         le = ls + 1;
217                 }
218         }
219
220         /* adding points marked */
221         bGPDspoint *old_points = MEM_dupallocN(gps->points);
222         MDeformVert *old_dvert = NULL;
223         MDeformVert *dvert_src = NULL;
224
225         if (gps->dvert != NULL) {
226                 old_dvert = MEM_dupallocN(gps->dvert);
227         }
228         /* resize gps */
229         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
230         gps->tot_triangles = 0;
231
232         int j = 0;
233         for (int i = 0; i < totpoints; i++) {
234                 bGPDspoint *pt_src = &old_points[i];
235                 bGPDspoint *pt = &gps->points[j];
236
237                 if ((marked[i]) || (i == 0) || (i == totpoints - 1)) {
238                         memcpy(pt, pt_src, sizeof(bGPDspoint));
239                         if (gps->dvert != NULL) {
240                                 dvert_src = &old_dvert[i];
241                                 MDeformVert *dvert = &gps->dvert[j];
242                                 memcpy(dvert, dvert_src, sizeof(MDeformVert));
243                                 if (dvert_src->dw) {
244                                         memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
245                                 }
246                         }
247                         j++;
248                 }
249                 else {
250                         if (gps->dvert != NULL) {
251                                 dvert_src = &old_dvert[i];
252                                 BKE_gpencil_free_point_weights(dvert_src);
253                         }
254                 }
255         }
256
257         gps->totpoints = j;
258
259         MEM_SAFE_FREE(old_points);
260         MEM_SAFE_FREE(old_dvert);
261         MEM_SAFE_FREE(marked);
262 }
263
264 /* Simplify stroke using Ramer-Douglas-Peucker algorithm */
265 void BKE_gpencil_simplify_stroke(bGPDstroke *gps, float factor)
266 {
267         /* first create temp data and convert points to 2D */
268         vec2f *points2d = MEM_mallocN(sizeof(vec2f) * gps->totpoints, "GP Stroke temp 2d points");
269
270         gpencil_stroke_project_2d(gps->points, gps->totpoints, points2d);
271
272         gpencil_rdp_stroke(gps, points2d, factor);
273
274         MEM_SAFE_FREE(points2d);
275 }
276
277 /* Simplify alternate vertex of stroke except extremes */
278 void BKE_gpencil_simplify_fixed(bGPDstroke *gps)
279 {
280         if (gps->totpoints < 5) {
281                 return;
282         }
283
284         /* save points */
285         bGPDspoint *old_points = MEM_dupallocN(gps->points);
286         MDeformVert *old_dvert = NULL;
287         MDeformVert *dvert_src = NULL;
288
289         if (gps->dvert != NULL) {
290                 old_dvert = MEM_dupallocN(gps->dvert);
291         }
292
293         /* resize gps */
294         int newtot = (gps->totpoints - 2) / 2;
295         if (((gps->totpoints - 2) % 2) > 0) {
296                 newtot++;
297         }
298         newtot += 2;
299
300         gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * newtot);
301         if (gps->dvert != NULL) {
302                 gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * newtot);
303         }
304         gps->flag |= GP_STROKE_RECALC_GEOMETRY;
305         gps->tot_triangles = 0;
306
307         int j = 0;
308         for (int i = 0; i < gps->totpoints; i++) {
309                 bGPDspoint *pt_src = &old_points[i];
310                 bGPDspoint *pt = &gps->points[j];
311
312
313                 if ((i == 0) || (i == gps->totpoints - 1) || ((i % 2) > 0.0)) {
314                         memcpy(pt, pt_src, sizeof(bGPDspoint));
315                         if (gps->dvert != NULL) {
316                                 dvert_src = &old_dvert[i];
317                                 MDeformVert *dvert = &gps->dvert[j];
318                                 memcpy(dvert, dvert_src, sizeof(MDeformVert));
319                                 if (dvert_src->dw) {
320                                         memcpy(dvert->dw, dvert_src->dw, sizeof(MDeformWeight));
321                                 }
322                         }
323                         j++;
324                 }
325                 else {
326                         if (gps->dvert != NULL) {
327                                 dvert_src = &old_dvert[i];
328                                 BKE_gpencil_free_point_weights(dvert_src);
329                         }
330                 }
331         }
332
333         gps->totpoints = j;
334
335         MEM_SAFE_FREE(old_points);
336         MEM_SAFE_FREE(old_dvert);
337 }
338
339 /* *************************************************** */
340 /* Modifier Utilities */
341
342 /* Lattice Modifier ---------------------------------- */
343 /* Usually, evaluation of the lattice modifier is self-contained.
344  * However, since GP's modifiers operate on a per-stroke basis,
345  * we need to these two extra functions that called before/after
346  * each loop over all the geometry being evaluated.
347  */
348
349  /* init lattice deform data */
350 void BKE_gpencil_lattice_init(Object *ob)
351 {
352         GpencilModifierData *md;
353         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
354                 if (md->type == eGpencilModifierType_Lattice) {
355                         LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
356                         Object *latob = NULL;
357
358                         latob = mmd->object;
359                         if ((!latob) || (latob->type != OB_LATTICE)) {
360                                 return;
361                         }
362                         if (mmd->cache_data) {
363                                 end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
364                         }
365
366                         /* init deform data */
367                         mmd->cache_data = (struct LatticeDeformData *)init_latt_deform(latob, ob);
368                 }
369         }
370 }
371
372 /* clear lattice deform data */
373 void BKE_gpencil_lattice_clear(Object *ob)
374 {
375         GpencilModifierData *md;
376         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
377                 if (md->type == eGpencilModifierType_Lattice) {
378                         LatticeGpencilModifierData *mmd = (LatticeGpencilModifierData *)md;
379                         if ((mmd) && (mmd->cache_data)) {
380                                 end_latt_deform((struct LatticeDeformData *)mmd->cache_data);
381                                 mmd->cache_data = NULL;
382                         }
383                 }
384         }
385 }
386
387 /* *************************************************** */
388 /* Modifier Methods - Evaluation Loops, etc. */
389
390 /* check if exist geometry modifiers */
391 bool BKE_gpencil_has_geometry_modifiers(Object *ob)
392 {
393         GpencilModifierData *md;
394         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
395                 const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
396
397                 if (mti && mti->generateStrokes) {
398                         return true;
399                 }
400         }
401         return false;
402 }
403
404 /* check if exist time modifiers */
405 bool BKE_gpencil_has_time_modifiers(Object *ob)
406 {
407         GpencilModifierData *md;
408         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
409                 const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
410
411                 if (mti && mti->remapTime) {
412                         return true;
413                 }
414         }
415         return false;
416 }
417
418 /* apply stroke modifiers */
419 void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *UNUSED(gpf), bGPDstroke *gps, bool is_render)
420 {
421         GpencilModifierData *md;
422         bGPdata *gpd = ob->data;
423         const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
424
425         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
426                 if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
427                         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
428
429                         if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
430                                 continue;
431                         }
432
433                         if (mti && mti->deformStroke) {
434                                 mti->deformStroke(md, depsgraph, ob, gpl, gps);
435
436                                 /* some modifiers could require a recalc of fill triangulation data */
437                                 if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) {
438                                         if (ELEM(md->type,
439                                                  eGpencilModifierType_Armature,
440                                                  eGpencilModifierType_Hook,
441                                                  eGpencilModifierType_Lattice,
442                                                  eGpencilModifierType_Offset))
443                                         {
444
445                                                 gps->flag |= GP_STROKE_RECALC_GEOMETRY;
446                                         }
447                                 }
448                         }
449                 }
450         }
451 }
452
453 /* apply stroke geometry modifiers */
454 void BKE_gpencil_geometry_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bool is_render)
455 {
456         GpencilModifierData *md;
457         bGPdata *gpd = ob->data;
458         const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
459
460         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
461                 if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
462                         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
463
464                         if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
465                                 continue;
466                         }
467
468                         if (mti->generateStrokes) {
469                                 mti->generateStrokes(md, depsgraph, ob, gpl, gpf);
470                         }
471                 }
472         }
473 }
474
475 /* apply time modifiers */
476 int BKE_gpencil_time_modifier(Depsgraph *depsgraph, Scene *scene, Object *ob,
477         bGPDlayer *gpl, int cfra, bool is_render)
478 {
479         GpencilModifierData *md;
480         bGPdata *gpd = ob->data;
481         const bool is_edit = GPENCIL_ANY_EDIT_MODE(gpd);
482         int nfra = cfra;
483
484         for (md = ob->greasepencil_modifiers.first; md; md = md->next) {
485                 if (GPENCIL_MODIFIER_ACTIVE(md, is_render)) {
486                         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
487
488                         if (GPENCIL_MODIFIER_EDIT(md, is_edit)) {
489                                 continue;
490                         }
491
492                         if (mti->remapTime) {
493                                 nfra = mti->remapTime(md, depsgraph, scene, ob, gpl, cfra);
494                                 /* if the frame number changed, don't evaluate more and return */
495                                 if (nfra != cfra) {
496                                         return nfra;
497                                 }
498                         }
499                 }
500         }
501
502         /* if no time modifier, return original frame number */
503         return nfra;
504 }
505 /* *************************************************** */
506
507 void BKE_gpencil_eval_geometry(Depsgraph *depsgraph,
508         bGPdata *gpd)
509 {
510         DEG_debug_print_eval(depsgraph, __func__, gpd->id.name, gpd);
511         int ctime = (int)DEG_get_ctime(depsgraph);
512
513         /* update active frame */
514         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
515                 gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
516         }
517
518         /* TODO: Move "derived_gpf" logic here from DRW_gpencil_populate_datablock()?
519          * This would be better than inventing our own logic for this stuff...
520          */
521
522          /* TODO: Move the following code to "BKE_gpencil_eval_done()" (marked as an exit node)
523           * later when there's more happening here. For now, let's just keep this in here to avoid
524           * needing to have one more node slowing down evaluation...
525           */
526         if (DEG_is_active(depsgraph)) {
527                 bGPdata *gpd_orig = (bGPdata *)DEG_get_original_id(&gpd->id);
528
529                 /* sync "actframe" changes back to main-db too,
530                  * so that editing tools work with copy-on-write
531                  * when the current frame changes
532                  */
533                 for (bGPDlayer *gpl = gpd_orig->layers.first; gpl; gpl = gpl->next) {
534                         gpl->actframe = BKE_gpencil_layer_getframe(gpl, ctime, GP_GETFRAME_USE_PREV);
535                 }
536         }
537 }
538
539 void BKE_gpencil_modifier_init(void)
540 {
541         /* Initialize modifier types */
542         gpencil_modifier_type_init(modifier_gpencil_types); /* MOD_gpencil_util.c */
543 }
544
545 GpencilModifierData *BKE_gpencil_modifier_new(int type)
546 {
547         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type);
548         GpencilModifierData *md = MEM_callocN(mti->struct_size, mti->struct_name);
549
550         /* note, this name must be made unique later */
551         BLI_strncpy(md->name, DATA_(mti->name), sizeof(md->name));
552
553         md->type = type;
554         md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render | eGpencilModifierMode_Expanded;
555         md->flag = eGpencilModifierFlag_StaticOverride_Local;
556
557         if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode)
558                 md->mode |= eGpencilModifierMode_Editmode;
559
560         if (mti->initData) mti->initData(md);
561
562         return md;
563 }
564
565 static void modifier_free_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
566 {
567         ID *id = *idpoin;
568         if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
569                 id_us_min(id);
570         }
571 }
572
573 void BKE_gpencil_modifier_free_ex(GpencilModifierData *md, const int flag)
574 {
575         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
576
577         if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
578                 if (mti->foreachIDLink) {
579                         mti->foreachIDLink(md, NULL, modifier_free_data_id_us_cb, NULL);
580                 }
581                 else if (mti->foreachObjectLink) {
582                         mti->foreachObjectLink(md, NULL, (GreasePencilObjectWalkFunc)modifier_free_data_id_us_cb, NULL);
583                 }
584         }
585
586         if (mti->freeData) mti->freeData(md);
587         if (md->error) MEM_freeN(md->error);
588
589         MEM_freeN(md);
590 }
591
592 void BKE_gpencil_modifier_free(GpencilModifierData *md)
593 {
594         BKE_gpencil_modifier_free_ex(md, 0);
595 }
596
597 /* check unique name */
598 bool BKE_gpencil_modifier_unique_name(ListBase *modifiers, GpencilModifierData *gmd)
599 {
600         if (modifiers && gmd) {
601                 const GpencilModifierTypeInfo *gmti = BKE_gpencil_modifierType_getInfo(gmd->type);
602                 return BLI_uniquename(modifiers, gmd, DATA_(gmti->name), '.', offsetof(GpencilModifierData, name), sizeof(gmd->name));
603         }
604         return false;
605 }
606
607 bool BKE_gpencil_modifier_dependsOnTime(GpencilModifierData *md)
608 {
609         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
610
611         return mti->dependsOnTime && mti->dependsOnTime(md);
612 }
613
614 const GpencilModifierTypeInfo *BKE_gpencil_modifierType_getInfo(GpencilModifierType type)
615 {
616         /* type unsigned, no need to check < 0 */
617         if (type < NUM_GREASEPENCIL_MODIFIER_TYPES && modifier_gpencil_types[type]->name[0] != '\0') {
618                 return modifier_gpencil_types[type];
619         }
620         else {
621                 return NULL;
622         }
623 }
624
625 void BKE_gpencil_modifier_copyData_generic(const GpencilModifierData *md_src, GpencilModifierData *md_dst)
626 {
627         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md_src->type);
628
629         /* md_dst may have already be fully initialized with some extra allocated data,
630          * we need to free it now to avoid memleak. */
631         if (mti->freeData) {
632                 mti->freeData(md_dst);
633         }
634
635         const size_t data_size = sizeof(GpencilModifierData);
636         const char *md_src_data = ((const char *)md_src) + data_size;
637         char       *md_dst_data = ((char *)md_dst) + data_size;
638         BLI_assert(data_size <= (size_t)mti->struct_size);
639         memcpy(md_dst_data, md_src_data, (size_t)mti->struct_size - data_size);
640 }
641
642 static void gpencil_modifier_copy_data_id_us_cb(void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int cb_flag)
643 {
644         ID *id = *idpoin;
645         if (id != NULL && (cb_flag & IDWALK_CB_USER) != 0) {
646                 id_us_plus(id);
647         }
648 }
649
650 void BKE_gpencil_modifier_copyData_ex(GpencilModifierData *md, GpencilModifierData *target, const int flag)
651 {
652         const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
653
654         target->mode = md->mode;
655         target->flag = md->flag;
656
657         if (mti->copyData) {
658                 mti->copyData(md, target);
659         }
660
661         if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
662                 if (mti->foreachIDLink) {
663                         mti->foreachIDLink(target, NULL, gpencil_modifier_copy_data_id_us_cb, NULL);
664                 }
665                 else if (mti->foreachObjectLink) {
666                         mti->foreachObjectLink(target, NULL, (GreasePencilObjectWalkFunc)gpencil_modifier_copy_data_id_us_cb, NULL);
667                 }
668         }
669 }
670
671 void BKE_gpencil_modifier_copyData(GpencilModifierData *md, GpencilModifierData *target)
672 {
673         BKE_gpencil_modifier_copyData_ex(md, target, 0);
674 }
675
676 GpencilModifierData *BKE_gpencil_modifiers_findByType(Object *ob, GpencilModifierType type)
677 {
678         GpencilModifierData *md = ob->greasepencil_modifiers.first;
679
680         for (; md; md = md->next)
681                 if (md->type == type)
682                         break;
683
684         return md;
685 }
686
687 void BKE_gpencil_modifiers_foreachIDLink(Object *ob, GreasePencilIDWalkFunc walk, void *userData)
688 {
689         GpencilModifierData *md = ob->greasepencil_modifiers.first;
690
691         for (; md; md = md->next) {
692                 const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
693
694                 if (mti->foreachIDLink) {
695                         mti->foreachIDLink(md, ob, walk, userData);
696                 }
697                 else if (mti->foreachObjectLink) {
698                         /* each Object can masquerade as an ID, so this should be OK */
699                         GreasePencilObjectWalkFunc fp = (GreasePencilObjectWalkFunc)walk;
700                         mti->foreachObjectLink(md, ob, fp, userData);
701                 }
702         }
703 }
704
705 void BKE_gpencil_modifiers_foreachTexLink(Object *ob, GreasePencilTexWalkFunc walk, void *userData)
706 {
707         GpencilModifierData *md = ob->greasepencil_modifiers.first;
708
709         for (; md; md = md->next) {
710                 const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type);
711
712                 if (mti->foreachTexLink)
713                         mti->foreachTexLink(md, ob, walk, userData);
714         }
715 }
716
717 GpencilModifierData *BKE_gpencil_modifiers_findByName(Object *ob, const char *name)
718 {
719         return BLI_findstring(&(ob->greasepencil_modifiers), name, offsetof(GpencilModifierData, name));
720 }
721
722 void BKE_gpencil_subdivide(bGPDstroke *gps, int level, int flag)
723 {
724         bGPDspoint *temp_points;
725         MDeformVert *temp_dverts = NULL;
726         MDeformVert *dvert = NULL;
727         MDeformVert *dvert_final = NULL;
728         MDeformVert *dvert_next = NULL;
729         int totnewpoints, oldtotpoints;
730         int i2;
731
732         for (int s = 0; s < level; s++) {
733                 totnewpoints = gps->totpoints - 1;
734                 /* duplicate points in a temp area */
735                 temp_points = MEM_dupallocN(gps->points);
736                 oldtotpoints = gps->totpoints;
737
738                 /* resize the points arrays */
739                 gps->totpoints += totnewpoints;
740                 gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
741                 if (gps->dvert != NULL) {
742                         temp_dverts = MEM_dupallocN(gps->dvert);
743                         gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
744                 }
745                 gps->flag |= GP_STROKE_RECALC_GEOMETRY;
746                 gps->tot_triangles = 0;
747
748                 /* move points from last to first to new place */
749                 i2 = gps->totpoints - 1;
750                 for (int i = oldtotpoints - 1; i > 0; i--) {
751                         bGPDspoint *pt = &temp_points[i];
752                         bGPDspoint *pt_final = &gps->points[i2];
753
754                         copy_v3_v3(&pt_final->x, &pt->x);
755                         pt_final->pressure = pt->pressure;
756                         pt_final->strength = pt->strength;
757                         pt_final->time = pt->time;
758                         pt_final->flag = pt->flag;
759
760                         if (gps->dvert != NULL) {
761                                 dvert = &temp_dverts[i];
762                                 dvert_final = &gps->dvert[i2];
763                                 dvert_final->totweight = dvert->totweight;
764                                 dvert_final->dw = dvert->dw;
765                         }
766                         i2 -= 2;
767                 }
768                 /* interpolate mid points */
769                 i2 = 1;
770                 for (int i = 0; i < oldtotpoints - 1; i++) {
771                         bGPDspoint *pt = &temp_points[i];
772                         bGPDspoint *next = &temp_points[i + 1];
773                         bGPDspoint *pt_final = &gps->points[i2];
774
775                         /* add a half way point */
776                         interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
777                         pt_final->pressure = interpf(pt->pressure, next->pressure, 0.5f);
778                         pt_final->strength = interpf(pt->strength, next->strength, 0.5f);
779                         CLAMP(pt_final->strength, GPENCIL_STRENGTH_MIN, 1.0f);
780                         pt_final->time = interpf(pt->time, next->time, 0.5f);
781
782                         if (gps->dvert != NULL) {
783                                 dvert = &temp_dverts[i];
784                                 dvert_next = &temp_dverts[i + 1];
785                                 dvert_final = &gps->dvert[i2];
786
787                                 dvert_final->totweight = dvert->totweight;
788                                 dvert_final->dw = MEM_dupallocN(dvert->dw);
789
790                                 /* interpolate weight values */
791                                 for (int d = 0; d < dvert->totweight; d++) {
792                                         MDeformWeight *dw_a = &dvert->dw[d];
793                                         if (dvert_next->totweight > d) {
794                                                 MDeformWeight *dw_b = &dvert_next->dw[d];
795                                                 MDeformWeight *dw_final = &dvert_final->dw[d];
796                                                 dw_final->weight = interpf(dw_a->weight, dw_b->weight, 0.5f);
797                                         }
798                                 }
799                         }
800
801                         i2 += 2;
802                 }
803
804                 MEM_SAFE_FREE(temp_points);
805                 MEM_SAFE_FREE(temp_dverts);
806
807                 /* move points to smooth stroke (not simple flag )*/
808                 if ((flag & GP_SUBDIV_SIMPLE) == 0) {
809                         /* duplicate points in a temp area with the new subdivide data */
810                         temp_points = MEM_dupallocN(gps->points);
811
812                         /* extreme points are not changed */
813                         for (int i = 0; i < gps->totpoints - 2; i++) {
814                                 bGPDspoint *pt = &temp_points[i];
815                                 bGPDspoint *next = &temp_points[i + 1];
816                                 bGPDspoint *pt_final = &gps->points[i + 1];
817
818                                 /* move point */
819                                 interp_v3_v3v3(&pt_final->x, &pt->x, &next->x, 0.5f);
820                         }
821                         /* free temp memory */
822                         MEM_SAFE_FREE(temp_points);
823                 }
824
825         }
826 }