Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / object / object_shader_fx.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_types.h"
31 #include "DNA_shader_fx_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 "BLT_translation.h"
40
41 #include "BKE_context.h"
42 #include "BKE_main.h"
43 #include "BKE_shader_fx.h"
44 #include "BKE_report.h"
45 #include "BKE_object.h"
46
47 #include "DEG_depsgraph.h"
48 #include "DEG_depsgraph_build.h"
49 #include "DEG_depsgraph_query.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53 #include "RNA_enum_types.h"
54
55 #include "ED_object.h"
56 #include "ED_screen.h"
57
58 #include "WM_api.h"
59 #include "WM_types.h"
60
61 #include "object_intern.h"
62
63 /******************************** API ****************************/
64
65 ShaderFxData *ED_object_shaderfx_add(
66     ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type)
67 {
68   ShaderFxData *new_fx = NULL;
69   const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type);
70
71   if (ob->type != OB_GPENCIL) {
72     BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2);
73     return NULL;
74   }
75
76   if (fxi->flags & eShaderFxTypeFlag_Single) {
77     if (BKE_shaderfx_findByType(ob, type)) {
78       BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed");
79       return NULL;
80     }
81   }
82
83   /* get new effect data to add */
84   new_fx = BKE_shaderfx_new(type);
85
86   BLI_addtail(&ob->shader_fx, new_fx);
87
88   if (name) {
89     BLI_strncpy_utf8(new_fx->name, name, sizeof(new_fx->name));
90   }
91
92   /* make sure effect data has unique name */
93   BKE_shaderfx_unique_name(&ob->shader_fx, new_fx);
94
95   bGPdata *gpd = ob->data;
96   DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
97
98   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
99   DEG_relations_tag_update(bmain);
100
101   return new_fx;
102 }
103
104 /* Return true if the object has a effect of type 'type' other than
105  * the shaderfx pointed to be 'exclude', otherwise returns false. */
106 static bool UNUSED_FUNCTION(object_has_shaderfx)(const Object *ob,
107                                                  const ShaderFxData *exclude,
108                                                  ShaderFxType type)
109 {
110   ShaderFxData *fx;
111
112   for (fx = ob->shader_fx.first; fx; fx = fx->next) {
113     if ((fx != exclude) && (fx->type == type)) {
114       return true;
115     }
116   }
117
118   return false;
119 }
120
121 static bool object_shaderfx_remove(Main *bmain,
122                                    Object *ob,
123                                    ShaderFxData *fx,
124                                    bool *UNUSED(r_sort_depsgraph))
125 {
126   /* It seems on rapid delete it is possible to
127    * get called twice on same effect, so make
128    * sure it is in list. */
129   if (BLI_findindex(&ob->shader_fx, fx) == -1) {
130     return 0;
131   }
132
133   DEG_relations_tag_update(bmain);
134
135   BLI_remlink(&ob->shader_fx, fx);
136   BKE_shaderfx_free(fx);
137   BKE_object_free_derived_caches(ob);
138
139   return 1;
140 }
141
142 bool ED_object_shaderfx_remove(ReportList *reports, Main *bmain, Object *ob, ShaderFxData *fx)
143 {
144   bool sort_depsgraph = false;
145   bool ok;
146
147   ok = object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
148
149   if (!ok) {
150     BKE_reportf(reports, RPT_ERROR, "Effect '%s' not in object '%s'", fx->name, ob->id.name);
151     return 0;
152   }
153
154   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
155   DEG_relations_tag_update(bmain);
156
157   return 1;
158 }
159
160 void ED_object_shaderfx_clear(Main *bmain, Object *ob)
161 {
162   ShaderFxData *fx = ob->shader_fx.first;
163   bool sort_depsgraph = false;
164
165   if (!fx) {
166     return;
167   }
168
169   while (fx) {
170     ShaderFxData *next_fx;
171
172     next_fx = fx->next;
173
174     object_shaderfx_remove(bmain, ob, fx, &sort_depsgraph);
175
176     fx = next_fx;
177   }
178
179   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
180   DEG_relations_tag_update(bmain);
181 }
182
183 int ED_object_shaderfx_move_up(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
184 {
185   if (fx->prev) {
186     BLI_remlink(&ob->shader_fx, fx);
187     BLI_insertlinkbefore(&ob->shader_fx, fx->prev, fx);
188   }
189
190   return 1;
191 }
192
193 int ED_object_shaderfx_move_down(ReportList *UNUSED(reports), Object *ob, ShaderFxData *fx)
194 {
195   if (fx->next) {
196     BLI_remlink(&ob->shader_fx, fx);
197     BLI_insertlinkafter(&ob->shader_fx, fx->next, fx);
198   }
199
200   return 1;
201 }
202
203 /************************ add effect operator *********************/
204
205 static int shaderfx_add_exec(bContext *C, wmOperator *op)
206 {
207   Main *bmain = CTX_data_main(C);
208   Scene *scene = CTX_data_scene(C);
209   Object *ob = ED_object_active_context(C);
210   int type = RNA_enum_get(op->ptr, "type");
211
212   if (!ED_object_shaderfx_add(op->reports, bmain, scene, ob, NULL, type)) {
213     return OPERATOR_CANCELLED;
214   }
215
216   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
217
218   return OPERATOR_FINISHED;
219 }
220
221 static const EnumPropertyItem *shaderfx_add_itemf(bContext *C,
222                                                   PointerRNA *UNUSED(ptr),
223                                                   PropertyRNA *UNUSED(prop),
224                                                   bool *r_free)
225 {
226   Object *ob = ED_object_active_context(C);
227   EnumPropertyItem *item = NULL;
228   const EnumPropertyItem *fx_item, *group_item = NULL;
229   const ShaderFxTypeInfo *mti;
230   int totitem = 0, a;
231
232   if (!ob) {
233     return rna_enum_object_shaderfx_type_items;
234   }
235
236   for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) {
237     fx_item = &rna_enum_object_shaderfx_type_items[a];
238     if (fx_item->identifier[0]) {
239       mti = BKE_shaderfxType_getInfo(fx_item->value);
240
241       if (mti->flags & eShaderFxTypeFlag_NoUserAdd) {
242         continue;
243       }
244     }
245     else {
246       group_item = fx_item;
247       fx_item = NULL;
248
249       continue;
250     }
251
252     if (group_item) {
253       RNA_enum_item_add(&item, &totitem, group_item);
254       group_item = NULL;
255     }
256
257     RNA_enum_item_add(&item, &totitem, fx_item);
258   }
259
260   RNA_enum_item_end(&item, &totitem);
261   *r_free = true;
262
263   return item;
264 }
265
266 void OBJECT_OT_shaderfx_add(wmOperatorType *ot)
267 {
268   /* identifiers */
269   ot->name = "Add Effect";
270   ot->description = "Add a visual effect to the active object";
271   ot->idname = "OBJECT_OT_shaderfx_add";
272
273   /* api callbacks */
274   ot->invoke = WM_menu_invoke;
275   ot->exec = shaderfx_add_exec;
276   ot->poll = ED_operator_object_active_editable;
277
278   /* flags */
279   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
280
281   /* properties */
282   ot->prop = RNA_def_enum(
283       ot->srna, "type", rna_enum_object_shaderfx_type_items, eShaderFxType_Blur, "Type", "");
284   RNA_def_enum_funcs(ot->prop, shaderfx_add_itemf);
285   RNA_def_property_translation_context(ot->prop,
286                                        BLT_I18NCONTEXT_ID_ID); /* Abused, for "Light"... */
287 }
288
289 /* -------------------------------------------------------------------- */
290 /** \name Generic Functions for Operators Using Names and Data Context
291  * \{ */
292
293 static bool edit_shaderfx_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag)
294 {
295   PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", rna_type);
296   Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
297
298   if (!ptr.data) {
299     CTX_wm_operator_poll_msg_set(C, "Context missing 'shaderfx'");
300     return 0;
301   }
302
303   if (!ob || ID_IS_LINKED(ob)) {
304     return 0;
305   }
306   if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) {
307     return 0;
308   }
309   if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) {
310     return 0;
311   }
312
313   if (ID_IS_STATIC_OVERRIDE(ob)) {
314     CTX_wm_operator_poll_msg_set(C, "Cannot edit shaderfxs coming from static override");
315     return (((ShaderFxData *)ptr.data)->flag & eShaderFxFlag_StaticOverride_Local) != 0;
316   }
317
318   return 1;
319 }
320
321 static bool edit_shaderfx_poll(bContext *C)
322 {
323   return edit_shaderfx_poll_generic(C, &RNA_ShaderFx, 0);
324 }
325
326 static void edit_shaderfx_properties(wmOperatorType *ot)
327 {
328   PropertyRNA *prop = RNA_def_string(
329       ot->srna, "shaderfx", NULL, MAX_NAME, "Shader", "Name of the shaderfx to edit");
330   RNA_def_property_flag(prop, PROP_HIDDEN);
331 }
332
333 static int edit_shaderfx_invoke_properties(bContext *C, wmOperator *op)
334 {
335   ShaderFxData *fx;
336
337   if (RNA_struct_property_is_set(op->ptr, "shaderfx")) {
338     return true;
339   }
340   else {
341     PointerRNA ptr = CTX_data_pointer_get_type(C, "shaderfx", &RNA_ShaderFx);
342     if (ptr.data) {
343       fx = ptr.data;
344       RNA_string_set(op->ptr, "shaderfx", fx->name);
345       return true;
346     }
347   }
348
349   return false;
350 }
351
352 static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int type)
353 {
354   char shaderfx_name[MAX_NAME];
355   ShaderFxData *fx;
356   RNA_string_get(op->ptr, "shaderfx", shaderfx_name);
357
358   fx = BKE_shaderfx_findByName(ob, shaderfx_name);
359
360   if (fx && type != 0 && fx->type != type) {
361     fx = NULL;
362   }
363
364   return fx;
365 }
366
367 /** \} */
368
369 /************************ remove shaderfx operator *********************/
370
371 static int shaderfx_remove_exec(bContext *C, wmOperator *op)
372 {
373   Main *bmain = CTX_data_main(C);
374   Object *ob = ED_object_active_context(C);
375   ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
376
377   if (!fx || !ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
378     return OPERATOR_CANCELLED;
379   }
380
381   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
382
383   return OPERATOR_FINISHED;
384 }
385
386 static int shaderfx_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
387 {
388   if (edit_shaderfx_invoke_properties(C, op)) {
389     return shaderfx_remove_exec(C, op);
390   }
391   else {
392     return OPERATOR_CANCELLED;
393   }
394 }
395
396 void OBJECT_OT_shaderfx_remove(wmOperatorType *ot)
397 {
398   ot->name = "Remove Grease Pencil Modifier";
399   ot->description = "Remove a shaderfx from the active grease pencil object";
400   ot->idname = "OBJECT_OT_shaderfx_remove";
401
402   ot->invoke = shaderfx_remove_invoke;
403   ot->exec = shaderfx_remove_exec;
404   ot->poll = edit_shaderfx_poll;
405
406   /* flags */
407   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
408   edit_shaderfx_properties(ot);
409 }
410
411 /************************ move up shaderfx operator *********************/
412
413 static int shaderfx_move_up_exec(bContext *C, wmOperator *op)
414 {
415   Object *ob = ED_object_active_context(C);
416   ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
417
418   if (!fx || !ED_object_shaderfx_move_up(op->reports, ob, fx)) {
419     return OPERATOR_CANCELLED;
420   }
421
422   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
423   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
424
425   return OPERATOR_FINISHED;
426 }
427
428 static int shaderfx_move_up_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
429 {
430   if (edit_shaderfx_invoke_properties(C, op)) {
431     return shaderfx_move_up_exec(C, op);
432   }
433   else {
434     return OPERATOR_CANCELLED;
435   }
436 }
437
438 void OBJECT_OT_shaderfx_move_up(wmOperatorType *ot)
439 {
440   ot->name = "Move Up Modifier";
441   ot->description = "Move shaderfx up in the stack";
442   ot->idname = "OBJECT_OT_shaderfx_move_up";
443
444   ot->invoke = shaderfx_move_up_invoke;
445   ot->exec = shaderfx_move_up_exec;
446   ot->poll = edit_shaderfx_poll;
447
448   /* flags */
449   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
450   edit_shaderfx_properties(ot);
451 }
452
453 /************************ move down shaderfx operator *********************/
454
455 static int shaderfx_move_down_exec(bContext *C, wmOperator *op)
456 {
457   Object *ob = ED_object_active_context(C);
458   ShaderFxData *fx = edit_shaderfx_property_get(op, ob, 0);
459
460   if (!fx || !ED_object_shaderfx_move_down(op->reports, ob, fx)) {
461     return OPERATOR_CANCELLED;
462   }
463
464   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
465   WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
466
467   return OPERATOR_FINISHED;
468 }
469
470 static int shaderfx_move_down_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
471 {
472   if (edit_shaderfx_invoke_properties(C, op)) {
473     return shaderfx_move_down_exec(C, op);
474   }
475   else {
476     return OPERATOR_CANCELLED;
477   }
478 }
479
480 void OBJECT_OT_shaderfx_move_down(wmOperatorType *ot)
481 {
482   ot->name = "Move Down Modifier";
483   ot->description = "Move shaderfx down in the stack";
484   ot->idname = "OBJECT_OT_shaderfx_move_down";
485
486   ot->invoke = shaderfx_move_down_invoke;
487   ot->exec = shaderfx_move_down_exec;
488   ot->poll = edit_shaderfx_poll;
489
490   /* flags */
491   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
492   edit_shaderfx_properties(ot);
493 }