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