6dadfbd75efafe4c54c2bfe9be7e5d1a806f26a3
[blender.git] / source / blender / editors / object / object_gpencil_modifier.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) 2018 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edobj
22  */
23
24 #include <math.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_gpencil_modifier_types.h"
31 #include "DNA_gpencil_types.h"
32 #include "DNA_object_types.h"
33 #include "DNA_scene_types.h"
34
35 #include "BLI_listbase.h"
36 #include "BLI_string_utf8.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_context.h"
40 #include "BKE_gpencil.h"
41 #include "BKE_gpencil_modifier.h"
42 #include "BKE_main.h"
43 #include "BKE_object.h"
44 #include "BKE_report.h"
45
46 #include "DEG_depsgraph.h"
47 #include "DEG_depsgraph_build.h"
48 #include "DEG_depsgraph_query.h"
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52 #include "RNA_enum_types.h"
53
54 #include "ED_object.h"
55 #include "ED_screen.h"
56
57 #include "WM_api.h"
58 #include "WM_types.h"
59
60 #include "object_intern.h"
61
62 /******************************** API ****************************/
63
64 GpencilModifierData *ED_object_gpencil_modifier_add(
65     ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
66 {
67   GpencilModifierData *new_md = NULL;
68   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type);
69
70   if (ob->type != OB_GPENCIL) {
71     BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
72     return NULL;
73   }
74
75   if (mti->flags & eGpencilModifierTypeFlag_Single) {
76     if (BKE_gpencil_modifiers_findby_type(ob, type)) {
77       BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
78       return NULL;
79     }
80   }
81
82   /* get new modifier data to add */
83   new_md = BKE_gpencil_modifier_new(type);
84
85   BLI_addtail(&ob->greasepencil_modifiers, new_md);
86
87   if (name) {
88     BLI_strncpy_utf8(new_md->name, name, sizeof(new_md->name));
89   }
90
91   /* make sure modifier data has unique name */
92   BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, new_md);
93
94   /* Enable edit mode visible by default. */
95   if (mti->flags & eGpencilModifierTypeFlag_SupportsEditmode) {
96     new_md->mode |= eGpencilModifierMode_Editmode;
97   }
98
99   bGPdata *gpd = ob->data;
100   DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
101
102   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
103   DEG_relations_tag_update(bmain);
104
105   return new_md;
106 }
107
108 static bool gpencil_object_modifier_remove(Main *bmain,
109                                            Object *ob,
110                                            GpencilModifierData *md,
111                                            bool *UNUSED(r_sort_depsgraph))
112 {
113   /* It seems on rapid delete it is possible to
114    * get called twice on same modifier, so make
115    * sure it is in list. */
116   if (BLI_findindex(&ob->greasepencil_modifiers, md) == -1) {
117     return 0;
118   }
119
120   DEG_relations_tag_update(bmain);
121
122   BLI_remlink(&ob->greasepencil_modifiers, md);
123   BKE_gpencil_modifier_free(md);
124   BKE_object_free_derived_caches(ob);
125
126   return 1;
127 }
128
129 bool ED_object_gpencil_modifier_remove(ReportList *reports,
130                                        Main *bmain,
131                                        Object *ob,
132                                        GpencilModifierData *md)
133 {
134   bool sort_depsgraph = false;
135   bool ok;
136
137   ok = gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
138
139   if (!ok) {
140     BKE_reportf(reports, RPT_ERROR, "Modifier '%s' not in object '%s'", md->name, ob->id.name);
141     return 0;
142   }
143
144   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
145   DEG_relations_tag_update(bmain);
146
147   return 1;
148 }
149
150 void ED_object_gpencil_modifier_clear(Main *bmain, Object *ob)
151 {
152   GpencilModifierData *md = ob->greasepencil_modifiers.first;
153   bool sort_depsgraph = false;
154
155   if (!md) {
156     return;
157   }
158
159   while (md) {
160     GpencilModifierData *next_md;
161
162     next_md = md->next;
163
164     gpencil_object_modifier_remove(bmain, ob, md, &sort_depsgraph);
165
166     md = next_md;
167   }
168
169   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
170   DEG_relations_tag_update(bmain);
171 }
172
173 int ED_object_gpencil_modifier_move_up(ReportList *UNUSED(reports),
174                                        Object *ob,
175                                        GpencilModifierData *md)
176 {
177   if (md->prev) {
178     BLI_remlink(&ob->greasepencil_modifiers, md);
179     BLI_insertlinkbefore(&ob->greasepencil_modifiers, md->prev, md);
180   }
181
182   return 1;
183 }
184
185 int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports),
186                                          Object *ob,
187                                          GpencilModifierData *md)
188 {
189   if (md->next) {
190     BLI_remlink(&ob->greasepencil_modifiers, md);
191     BLI_insertlinkafter(&ob->greasepencil_modifiers, md->next, md);
192   }
193
194   return 1;
195 }
196
197 bool ED_object_gpencil_modifier_move_to_index(ReportList *reports,
198                                               Object *ob,
199                                               GpencilModifierData *md,
200                                               const int index)
201 {
202   BLI_assert(md != NULL);
203   BLI_assert(index >= 0);
204   if (index >= BLI_listbase_count(&ob->greasepencil_modifiers)) {
205     BKE_report(reports, RPT_WARNING, "Cannot move modifier beyond the end of the stack");
206     return false;
207   }
208
209   int md_index = BLI_findindex(&ob->greasepencil_modifiers, md);
210   BLI_assert(md_index != -1);
211   if (md_index < index) {
212     /* Move modifier down in list. */
213     for (; md_index < index; md_index++) {
214       if (!ED_object_gpencil_modifier_move_down(reports, ob, md)) {
215         break;
216       }
217     }
218   }
219   else {
220     /* Move modifier up in list. */
221     for (; md_index > index; md_index--) {
222       if (!ED_object_gpencil_modifier_move_up(reports, ob, md)) {
223         break;
224       }
225     }
226   }
227
228   return true;
229 }
230
231 static int gpencil_modifier_apply_obdata(
232     ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md)
233 {
234   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
235
236   if (mti->isDisabled && mti->isDisabled(md, 0)) {
237     BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply");
238     return 0;
239   }
240
241   if (ob->type == OB_GPENCIL) {
242     if (ELEM(NULL, ob, ob->data)) {
243       return 0;
244     }
245     else if (mti->bakeModifier == NULL) {
246       BKE_report(reports, RPT_ERROR, "Not implemented");
247       return 0;
248     }
249     mti->bakeModifier(bmain, depsgraph, md, ob);
250     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
251   }
252   else {
253     BKE_report(reports, RPT_ERROR, "Cannot apply modifier for this object type");
254     return 0;
255   }
256
257   return 1;
258 }
259
260 int ED_object_gpencil_modifier_apply(Main *bmain,
261                                      ReportList *reports,
262                                      Depsgraph *depsgraph,
263                                      Object *ob,
264                                      GpencilModifierData *md,
265                                      int UNUSED(mode))
266 {
267
268   if (ob->type == OB_GPENCIL) {
269     if (ob->mode != OB_MODE_OBJECT) {
270       BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode");
271       return 0;
272     }
273
274     if (((ID *)ob->data)->us > 1) {
275       BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
276       return 0;
277     }
278   }
279   else if (((ID *)ob->data)->us > 1) {
280     BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied to multi-user data");
281     return 0;
282   }
283
284   if (md != ob->greasepencil_modifiers.first) {
285     BKE_report(reports, RPT_INFO, "Applied modifier was not first, result may not be as expected");
286   }
287
288   if (!gpencil_modifier_apply_obdata(reports, bmain, depsgraph, ob, md)) {
289     return 0;
290   }
291
292   BLI_remlink(&ob->greasepencil_modifiers, md);
293   BKE_gpencil_modifier_free(md);
294
295   return 1;
296 }
297
298 int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md)
299 {
300   GpencilModifierData *nmd;
301   const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type);
302   GpencilModifierType type = md->type;
303
304   if (mti->flags & eGpencilModifierTypeFlag_Single) {
305     if (BKE_gpencil_modifiers_findby_type(ob, type)) {
306       BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed");
307       return 0;
308     }
309   }
310
311   nmd = BKE_gpencil_modifier_new(md->type);
312   BKE_gpencil_modifier_copydata(md, nmd);
313   BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd);
314   BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd);
315
316   return 1;
317 }
318
319 /************************ add modifier operator *********************/
320
321 static int gpencil_modifier_add_exec(bContext *C, wmOperator *op)
322 {
323   Main *bmain = CTX_data_main(C);
324   Scene *scene = CTX_data_scene(C);
325   Object *ob = ED_object_active_context(C);
326   int type = RNA_enum_get(op->ptr, "type");
327
328   if (!ED_object_gpencil_modifier_add(op->reports, bmain, scene, ob, NULL, type)) {
329     return OPERATOR_CANCELLED;
330   }
331
332   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
333
334   return OPERATOR_FINISHED;
335 }
336
337 static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C,
338                                                           PointerRNA *UNUSED(ptr),
339                                                           PropertyRNA *UNUSED(prop),
340                                                           bool *r_free)
341 {
342   Object *ob = ED_object_active_context(C);
343   EnumPropertyItem *item = NULL;
344   const EnumPropertyItem *md_item, *group_item = NULL;
345   const GpencilModifierTypeInfo *mti;
346   int totitem = 0, a;
347
348   if (!ob) {
349     return rna_enum_object_greasepencil_modifier_type_items;
350   }
351
352   for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) {
353     md_item = &rna_enum_object_greasepencil_modifier_type_items[a];
354     if (md_item->identifier[0]) {
355       mti = BKE_gpencil_modifier_get_info(md_item->value);
356
357       if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) {
358         continue;
359       }
360     }
361     else {
362       group_item = md_item;
363       md_item = NULL;
364
365       continue;
366     }
367
368     if (group_item) {
369       RNA_enum_item_add(&item, &totitem, group_item);
370       group_item = NULL;
371     }
372
373     RNA_enum_item_add(&item, &totitem, md_item);
374   }
375
376   RNA_enum_item_end(&item, &totitem);
377   *r_free = true;
378
379   return item;
380 }
381
382 void OBJECT_OT_gpencil_modifier_add(wmOperatorType *ot)
383 {
384   PropertyRNA *prop;
385
386   /* identifiers */
387   ot->name = "Add Modifier";
388   ot->description = "Add a procedural operation/effect to the active grease pencil object";
389   ot->idname = "OBJECT_OT_gpencil_modifier_add";
390
391   /* api callbacks */
392   ot->invoke = WM_menu_invoke;
393   ot->exec = gpencil_modifier_add_exec;
394   ot->poll = ED_operator_object_active_editable;
395
396   /* flags */
397   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
398
399   /* properties */
400   prop = RNA_def_enum(ot->srna,
401                       "type",
402                       rna_enum_object_modifier_type_items,
403                       eGpencilModifierType_Thick,
404                       "Type",
405                       "");
406   RNA_def_enum_funcs(prop, gpencil_modifier_add_itemf);
407   ot->prop = prop;
408 }
409
410 /********** generic functions for operators using mod names and data context *********************/
411
412 static int gpencil_edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
413 {
414   PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
415   Object *ob = (ptr.owner_id) ? (Object *)ptr.owner_id : ED_object_active_context(C);
416
417   if (!ob || ID_IS_LINKED(ob)) {
418     return 0;
419   }
420   if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) {
421     return 0;
422   }
423   if (ptr.owner_id && ID_IS_LINKED(ptr.owner_id)) {
424     return 0;
425   }
426
427   if (ID_IS_OVERRIDE_LIBRARY(ob)) {
428     CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers coming from library override");
429     return (((GpencilModifierData *)ptr.data)->flag &
430             eGpencilModifierFlag_OverrideLibrary_Local) != 0;
431   }
432
433   return 1;
434 }
435
436 static bool gpencil_edit_modifier_poll(bContext *C)
437 {
438   return gpencil_edit_modifier_poll_generic(C, &RNA_GpencilModifier, 0);
439 }
440
441 static void gpencil_edit_modifier_properties(wmOperatorType *ot)
442 {
443   PropertyRNA *prop = RNA_def_string(
444       ot->srna, "modifier", NULL, MAX_NAME, "Modifier", "Name of the modifier to edit");
445   RNA_def_property_flag(prop, PROP_HIDDEN);
446 }
447
448 static int gpencil_edit_modifier_invoke_properties(bContext *C, wmOperator *op)
449 {
450   GpencilModifierData *md;
451
452   if (RNA_struct_property_is_set(op->ptr, "modifier")) {
453     return true;
454   }
455   else {
456     PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_GpencilModifier);
457     if (ptr.data) {
458       md = ptr.data;
459       RNA_string_set(op->ptr, "modifier", md->name);
460       return true;
461     }
462   }
463
464   return false;
465 }
466
467 static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op,
468                                                                Object *ob,
469                                                                int type)
470 {
471   char modifier_name[MAX_NAME];
472   GpencilModifierData *md;
473   RNA_string_get(op->ptr, "modifier", modifier_name);
474
475   md = BKE_gpencil_modifiers_findby_name(ob, modifier_name);
476
477   if (md && type != 0 && md->type != type) {
478     md = NULL;
479   }
480
481   return md;
482 }
483
484 /************************ remove modifier operator *********************/
485
486 static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
487 {
488   Main *bmain = CTX_data_main(C);
489   Object *ob = ED_object_active_context(C);
490   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
491
492   if (!md || !ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) {
493     return OPERATOR_CANCELLED;
494   }
495
496   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
497
498   return OPERATOR_FINISHED;
499 }
500
501 static int gpencil_modifier_remove_invoke(bContext *C,
502                                           wmOperator *op,
503                                           const wmEvent *UNUSED(event))
504 {
505   if (gpencil_edit_modifier_invoke_properties(C, op)) {
506     return gpencil_modifier_remove_exec(C, op);
507   }
508   else {
509     return OPERATOR_CANCELLED;
510   }
511 }
512
513 void OBJECT_OT_gpencil_modifier_remove(wmOperatorType *ot)
514 {
515   ot->name = "Remove Grease Pencil Modifier";
516   ot->description = "Remove a modifier from the active grease pencil object";
517   ot->idname = "OBJECT_OT_gpencil_modifier_remove";
518
519   ot->invoke = gpencil_modifier_remove_invoke;
520   ot->exec = gpencil_modifier_remove_exec;
521   ot->poll = gpencil_edit_modifier_poll;
522
523   /* flags */
524   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
525   gpencil_edit_modifier_properties(ot);
526 }
527
528 /************************ move up modifier operator *********************/
529
530 static int gpencil_modifier_move_up_exec(bContext *C, wmOperator *op)
531 {
532   Object *ob = ED_object_active_context(C);
533   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
534
535   if (!md || !ED_object_gpencil_modifier_move_up(op->reports, ob, md)) {
536     return OPERATOR_CANCELLED;
537   }
538
539   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
540   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
541
542   return OPERATOR_FINISHED;
543 }
544
545 static int gpencil_modifier_move_up_invoke(bContext *C,
546                                            wmOperator *op,
547                                            const wmEvent *UNUSED(event))
548 {
549   if (gpencil_edit_modifier_invoke_properties(C, op)) {
550     return gpencil_modifier_move_up_exec(C, op);
551   }
552   else {
553     return OPERATOR_CANCELLED;
554   }
555 }
556
557 void OBJECT_OT_gpencil_modifier_move_up(wmOperatorType *ot)
558 {
559   ot->name = "Move Up Modifier";
560   ot->description = "Move modifier up in the stack";
561   ot->idname = "OBJECT_OT_gpencil_modifier_move_up";
562
563   ot->invoke = gpencil_modifier_move_up_invoke;
564   ot->exec = gpencil_modifier_move_up_exec;
565   ot->poll = gpencil_edit_modifier_poll;
566
567   /* flags */
568   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
569   gpencil_edit_modifier_properties(ot);
570 }
571
572 /************************ move down modifier operator *********************/
573
574 static int gpencil_modifier_move_down_exec(bContext *C, wmOperator *op)
575 {
576   Object *ob = ED_object_active_context(C);
577   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
578
579   if (!md || !ED_object_gpencil_modifier_move_down(op->reports, ob, md)) {
580     return OPERATOR_CANCELLED;
581   }
582
583   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
584   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
585
586   return OPERATOR_FINISHED;
587 }
588
589 static int gpencil_modifier_move_down_invoke(bContext *C,
590                                              wmOperator *op,
591                                              const wmEvent *UNUSED(event))
592 {
593   if (gpencil_edit_modifier_invoke_properties(C, op)) {
594     return gpencil_modifier_move_down_exec(C, op);
595   }
596   else {
597     return OPERATOR_CANCELLED;
598   }
599 }
600
601 void OBJECT_OT_gpencil_modifier_move_down(wmOperatorType *ot)
602 {
603   ot->name = "Move Down Modifier";
604   ot->description = "Move modifier down in the stack";
605   ot->idname = "OBJECT_OT_gpencil_modifier_move_down";
606
607   ot->invoke = gpencil_modifier_move_down_invoke;
608   ot->exec = gpencil_modifier_move_down_exec;
609   ot->poll = gpencil_edit_modifier_poll;
610
611   /* flags */
612   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
613   gpencil_edit_modifier_properties(ot);
614 }
615
616 /* ************************* Move to Index Gpencil Modifier Operator ************************* */
617
618 static bool gpencil_modifier_move_to_index_poll(bContext *C)
619 {
620   return gpencil_edit_modifier_poll(C);
621 }
622
623 static int gpencil_modifier_move_to_index_exec(bContext *C, wmOperator *op)
624 {
625   Object *ob = ED_object_active_context(C);
626   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
627   int index = RNA_int_get(op->ptr, "index");
628
629   if (!ED_object_gpencil_modifier_move_to_index(op->reports, ob, md, index)) {
630     return OPERATOR_CANCELLED;
631   }
632
633   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
634   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
635
636   return OPERATOR_FINISHED;
637 }
638
639 static int gpencil_modifier_move_to_index_invoke(bContext *C,
640                                                  wmOperator *op,
641                                                  const wmEvent *UNUSED(event))
642 {
643   if (gpencil_edit_modifier_invoke_properties(C, op)) {
644     return gpencil_modifier_move_to_index_exec(C, op);
645   }
646   else {
647     return OPERATOR_CANCELLED;
648   }
649 }
650
651 void OBJECT_OT_gpencil_modifier_move_to_index(wmOperatorType *ot)
652 {
653   ot->name = "Move Active Modifier to Index";
654   ot->idname = "OBJECT_OT_gpencil_modifier_move_to_index";
655   ot->description =
656       "Change the modifier's position in the list so it evaluates after the set number of "
657       "others";
658
659   ot->invoke = gpencil_modifier_move_to_index_invoke;
660   ot->exec = gpencil_modifier_move_to_index_exec;
661   ot->poll = gpencil_modifier_move_to_index_poll;
662
663   /* flags */
664   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
665   edit_modifier_properties(ot);
666   RNA_def_int(
667       ot->srna, "index", 0, 0, INT_MAX, "Index", "The index to move the modifier to", 0, INT_MAX);
668 }
669
670 /************************ apply modifier operator *********************/
671
672 static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
673 {
674   Main *bmain = CTX_data_main(C);
675   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
676   Object *ob = ED_object_active_context(C);
677   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
678   int apply_as = RNA_enum_get(op->ptr, "apply_as");
679
680   if (!md || !ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {
681     return OPERATOR_CANCELLED;
682   }
683
684   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
685   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
686
687   return OPERATOR_FINISHED;
688 }
689
690 static int gpencil_modifier_apply_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
691 {
692   if (gpencil_edit_modifier_invoke_properties(C, op)) {
693     return gpencil_modifier_apply_exec(C, op);
694   }
695   else {
696     return OPERATOR_CANCELLED;
697   }
698 }
699
700 static const EnumPropertyItem gpencil_modifier_apply_as_items[] = {
701     {MODIFIER_APPLY_DATA, "DATA", 0, "Object Data", "Apply modifier to the object's data"},
702     {MODIFIER_APPLY_SHAPE,
703      "SHAPE",
704      0,
705      "New Shape",
706      "Apply deform-only modifier to a new shape on this object"},
707     {0, NULL, 0, NULL, NULL},
708 };
709
710 void OBJECT_OT_gpencil_modifier_apply(wmOperatorType *ot)
711 {
712   ot->name = "Apply Modifier";
713   ot->description = "Apply modifier and remove from the stack";
714   ot->idname = "OBJECT_OT_gpencil_modifier_apply";
715
716   ot->invoke = gpencil_modifier_apply_invoke;
717   ot->exec = gpencil_modifier_apply_exec;
718   ot->poll = gpencil_edit_modifier_poll;
719
720   /* flags */
721   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
722
723   RNA_def_enum(ot->srna,
724                "apply_as",
725                gpencil_modifier_apply_as_items,
726                MODIFIER_APPLY_DATA,
727                "Apply as",
728                "How to apply the modifier to the geometry");
729   gpencil_edit_modifier_properties(ot);
730 }
731
732 /************************ copy modifier operator *********************/
733
734 static int gpencil_modifier_copy_exec(bContext *C, wmOperator *op)
735 {
736   Object *ob = ED_object_active_context(C);
737   GpencilModifierData *md = gpencil_edit_modifier_property_get(op, ob, 0);
738
739   if (!md || !ED_object_gpencil_modifier_copy(op->reports, ob, md)) {
740     return OPERATOR_CANCELLED;
741   }
742
743   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
744   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
745
746   return OPERATOR_FINISHED;
747 }
748
749 static int gpencil_modifier_copy_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
750 {
751   if (gpencil_edit_modifier_invoke_properties(C, op)) {
752     return gpencil_modifier_copy_exec(C, op);
753   }
754   else {
755     return OPERATOR_CANCELLED;
756   }
757 }
758
759 void OBJECT_OT_gpencil_modifier_copy(wmOperatorType *ot)
760 {
761   ot->name = "Copy Modifier";
762   ot->description = "Duplicate modifier at the same position in the stack";
763   ot->idname = "OBJECT_OT_gpencil_modifier_copy";
764
765   ot->invoke = gpencil_modifier_copy_invoke;
766   ot->exec = gpencil_modifier_copy_exec;
767   ot->poll = gpencil_edit_modifier_poll;
768
769   /* flags */
770   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
771   gpencil_edit_modifier_properties(ot);
772 }