Fix T81079: Switch object ignoring visibility settings
[blender.git] / source / blender / editors / object / object_facemap_ops.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  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edobj
22  */
23
24 #include <string.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "BLI_listbase.h"
29 #include "BLI_math.h"
30 #include "BLI_utildefines.h"
31
32 #include "DNA_mesh_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_workspace_types.h"
35
36 #include "BKE_context.h"
37 #include "BKE_customdata.h"
38 #include "BKE_editmesh.h"
39 #include "BKE_object.h"
40 #include "BKE_object_deform.h"
41 #include "BKE_object_facemap.h"
42
43 #include "DEG_depsgraph.h"
44
45 #include "RNA_access.h"
46 #include "RNA_define.h"
47
48 #include "WM_api.h"
49 #include "WM_types.h"
50
51 #include "ED_mesh.h"
52 #include "ED_object.h"
53
54 #include "object_intern.h"
55
56 /* called while not in editmode */
57 void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum)
58 {
59   int fmap_nr;
60   if (GS(((ID *)ob->data)->name) != ID_ME) {
61     return;
62   }
63
64   /* get the face map number, exit if it can't be found */
65   fmap_nr = BLI_findindex(&ob->fmaps, fmap);
66
67   if (fmap_nr != -1) {
68     int *facemap;
69     Mesh *me = ob->data;
70
71     /* if there's is no facemap layer then create one */
72     if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) {
73       facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly);
74     }
75
76     facemap[facenum] = fmap_nr;
77   }
78 }
79
80 /* called while not in editmode */
81 void ED_object_facemap_face_remove(Object *ob, bFaceMap *fmap, int facenum)
82 {
83   int fmap_nr;
84   if (GS(((ID *)ob->data)->name) != ID_ME) {
85     return;
86   }
87
88   /* get the face map number, exit if it can't be found */
89   fmap_nr = BLI_findindex(&ob->fmaps, fmap);
90
91   if (fmap_nr != -1) {
92     int *facemap;
93     Mesh *me = ob->data;
94
95     if ((facemap = CustomData_get_layer(&me->pdata, CD_FACEMAP)) == NULL) {
96       return;
97     }
98
99     facemap[facenum] = -1;
100   }
101 }
102
103 static void object_fmap_remap_edit_mode(Object *ob, const int *remap)
104 {
105   if (ob->type != OB_MESH) {
106     return;
107   }
108
109   Mesh *me = ob->data;
110   if (me->edit_mesh) {
111     BMEditMesh *em = me->edit_mesh;
112     const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
113
114     if (cd_fmap_offset != -1) {
115       BMFace *efa;
116       BMIter iter;
117       int *map;
118
119       BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
120         map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
121
122         if (map && *map != -1) {
123           *map = remap[*map];
124         }
125       }
126     }
127   }
128 }
129
130 static void object_fmap_remap_object_mode(Object *ob, const int *remap)
131 {
132   if (ob->type != OB_MESH) {
133     return;
134   }
135
136   Mesh *me = ob->data;
137   if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
138     int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
139     if (map) {
140       for (int i = 0; i < me->totpoly; i++) {
141         if (map[i] != -1) {
142           map[i] = remap[map[i]];
143         }
144       }
145     }
146   }
147 }
148
149 static void object_facemap_remap(Object *ob, const int *remap)
150 {
151   if (BKE_object_is_in_editmode(ob)) {
152     object_fmap_remap_edit_mode(ob, remap);
153   }
154   else {
155     object_fmap_remap_object_mode(ob, remap);
156   }
157 }
158
159 static bool face_map_supported_poll(bContext *C)
160 {
161   Object *ob = ED_object_context(C);
162   ID *data = (ob) ? ob->data : NULL;
163   return (ob && !ID_IS_LINKED(ob) && !ID_IS_OVERRIDE_LIBRARY(ob) && ob->type == OB_MESH && data &&
164           !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data));
165 }
166
167 static bool face_map_supported_edit_mode_poll(bContext *C)
168 {
169   Object *ob = ED_object_context(C);
170
171   if (face_map_supported_poll(C)) {
172     if (ob->mode == OB_MODE_EDIT) {
173       return true;
174     }
175   }
176   return false;
177 }
178
179 static int face_map_add_exec(bContext *C, wmOperator *UNUSED(op))
180 {
181   Object *ob = ED_object_context(C);
182
183   BKE_object_facemap_add(ob);
184   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
185   WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
186   WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
187
188   return OPERATOR_FINISHED;
189 }
190
191 void OBJECT_OT_face_map_add(struct wmOperatorType *ot)
192 {
193   /* identifiers */
194   ot->name = "Add Face Map";
195   ot->idname = "OBJECT_OT_face_map_add";
196   ot->description = "Add a new face map to the active object";
197
198   /* api callbacks */
199   ot->poll = face_map_supported_poll;
200   ot->exec = face_map_add_exec;
201
202   /* flags */
203   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
204 }
205
206 static int face_map_remove_exec(bContext *C, wmOperator *UNUSED(op))
207 {
208   Object *ob = ED_object_context(C);
209   bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
210
211   if (fmap) {
212     BKE_object_facemap_remove(ob, fmap);
213     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
214     WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
215     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
216   }
217   return OPERATOR_FINISHED;
218 }
219
220 void OBJECT_OT_face_map_remove(struct wmOperatorType *ot)
221 {
222   /* identifiers */
223   ot->name = "Remove Face Map";
224   ot->idname = "OBJECT_OT_face_map_remove";
225   ot->description = "Remove a face map from the active object";
226
227   /* api callbacks */
228   ot->poll = face_map_supported_poll;
229   ot->exec = face_map_remove_exec;
230
231   /* flags */
232   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
233 }
234
235 static int face_map_assign_exec(bContext *C, wmOperator *UNUSED(op))
236 {
237   Object *ob = ED_object_context(C);
238   bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
239
240   if (fmap) {
241     Mesh *me = ob->data;
242     BMEditMesh *em = me->edit_mesh;
243     BMFace *efa;
244     BMIter iter;
245     int *map;
246     int cd_fmap_offset;
247
248     if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) {
249       BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
250     }
251
252     cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
253
254     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
255       map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
256
257       if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
258         *map = ob->actfmap - 1;
259       }
260     }
261
262     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
263     WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
264     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
265   }
266   return OPERATOR_FINISHED;
267 }
268
269 void OBJECT_OT_face_map_assign(struct wmOperatorType *ot)
270 {
271   /* identifiers */
272   ot->name = "Assign Face Map";
273   ot->idname = "OBJECT_OT_face_map_assign";
274   ot->description = "Assign faces to a face map";
275
276   /* api callbacks */
277   ot->poll = face_map_supported_edit_mode_poll;
278   ot->exec = face_map_assign_exec;
279
280   /* flags */
281   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
282 }
283
284 static int face_map_remove_from_exec(bContext *C, wmOperator *UNUSED(op))
285 {
286   Object *ob = ED_object_context(C);
287   bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
288
289   if (fmap) {
290     Mesh *me = ob->data;
291     BMEditMesh *em = me->edit_mesh;
292     BMFace *efa;
293     BMIter iter;
294     int *map;
295     int cd_fmap_offset;
296     int mapindex = ob->actfmap - 1;
297
298     if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) {
299       return OPERATOR_CANCELLED;
300     }
301
302     cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
303
304     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
305       map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
306
307       if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && *map == mapindex) {
308         *map = -1;
309       }
310     }
311
312     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
313     WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
314     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
315   }
316   return OPERATOR_FINISHED;
317 }
318
319 void OBJECT_OT_face_map_remove_from(struct wmOperatorType *ot)
320 {
321   /* identifiers */
322   ot->name = "Remove from Face Map";
323   ot->idname = "OBJECT_OT_face_map_remove_from";
324   ot->description = "Remove faces from a face map";
325
326   /* api callbacks */
327   ot->poll = face_map_supported_edit_mode_poll;
328   ot->exec = face_map_remove_from_exec;
329
330   /* flags */
331   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
332 }
333
334 static void fmap_select(Object *ob, bool select)
335 {
336   Mesh *me = ob->data;
337   BMEditMesh *em = me->edit_mesh;
338   BMFace *efa;
339   BMIter iter;
340   int *map;
341   int cd_fmap_offset;
342   int mapindex = ob->actfmap - 1;
343
344   if (!CustomData_has_layer(&em->bm->pdata, CD_FACEMAP)) {
345     BM_data_layer_add(em->bm, &em->bm->pdata, CD_FACEMAP);
346   }
347
348   cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
349
350   BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
351     map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
352
353     if (*map == mapindex) {
354       BM_face_select_set(em->bm, efa, select);
355     }
356   }
357 }
358
359 static int face_map_select_exec(bContext *C, wmOperator *UNUSED(op))
360 {
361   Object *ob = ED_object_context(C);
362   bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
363
364   if (fmap) {
365     fmap_select(ob, true);
366
367     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
368     WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
369     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
370   }
371   return OPERATOR_FINISHED;
372 }
373
374 void OBJECT_OT_face_map_select(struct wmOperatorType *ot)
375 {
376   /* identifiers */
377   ot->name = "Select Face Map Faces";
378   ot->idname = "OBJECT_OT_face_map_select";
379   ot->description = "Select faces belonging to a face map";
380
381   /* api callbacks */
382   ot->poll = face_map_supported_edit_mode_poll;
383   ot->exec = face_map_select_exec;
384
385   /* flags */
386   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
387 }
388
389 static int face_map_deselect_exec(bContext *C, wmOperator *UNUSED(op))
390 {
391   Object *ob = ED_object_context(C);
392   bFaceMap *fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
393
394   if (fmap) {
395     fmap_select(ob, false);
396
397     DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
398     WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
399     WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
400   }
401   return OPERATOR_FINISHED;
402 }
403
404 void OBJECT_OT_face_map_deselect(struct wmOperatorType *ot)
405 {
406   /* identifiers */
407   ot->name = "Deselect Face Map Faces";
408   ot->idname = "OBJECT_OT_face_map_deselect";
409   ot->description = "Deselect faces belonging to a face map";
410
411   /* api callbacks */
412   ot->poll = face_map_supported_edit_mode_poll;
413   ot->exec = face_map_deselect_exec;
414
415   /* flags */
416   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
417 }
418
419 static int face_map_move_exec(bContext *C, wmOperator *op)
420 {
421   Object *ob = ED_object_context(C);
422   bFaceMap *fmap;
423   int dir = RNA_enum_get(op->ptr, "direction");
424
425   fmap = BLI_findlink(&ob->fmaps, ob->actfmap - 1);
426   if (!fmap) {
427     return OPERATOR_CANCELLED;
428   }
429
430   if (!fmap->prev && !fmap->next) {
431     return OPERATOR_CANCELLED;
432   }
433
434   int pos1 = BLI_findindex(&ob->fmaps, fmap);
435   int pos2 = pos1 - dir;
436   int len = BLI_listbase_count(&ob->fmaps);
437   int *map = MEM_mallocN(len * sizeof(*map), __func__);
438
439   if (!IN_RANGE(pos2, -1, len)) {
440     const int offset = len - dir;
441     for (int i = 0; i < len; i++) {
442       map[i] = (i + offset) % len;
443     }
444     pos2 = map[pos1];
445   }
446   else {
447     range_vn_i(map, len, 0);
448     SWAP(int, map[pos1], map[pos2]);
449   }
450
451   void *prev = fmap->prev;
452   void *next = fmap->next;
453   BLI_remlink(&ob->fmaps, fmap);
454   if (dir == 1) { /*up*/
455     BLI_insertlinkbefore(&ob->fmaps, prev, fmap);
456   }
457   else { /*down*/
458     BLI_insertlinkafter(&ob->fmaps, next, fmap);
459   }
460
461   /* Iterate through mesh and substitute the indices as necessary. */
462   object_facemap_remap(ob, map);
463   MEM_freeN(map);
464
465   ob->actfmap = pos2 + 1;
466
467   DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
468   WM_event_add_notifier(C, NC_GEOM | ND_VERTEX_GROUP, ob);
469
470   return OPERATOR_FINISHED;
471 }
472
473 void OBJECT_OT_face_map_move(wmOperatorType *ot)
474 {
475   static EnumPropertyItem fmap_slot_move[] = {
476       {1, "UP", 0, "Up", ""},
477       {-1, "DOWN", 0, "Down", ""},
478       {0, NULL, 0, NULL, NULL},
479   };
480
481   /* identifiers */
482   ot->name = "Move Face Map";
483   ot->idname = "OBJECT_OT_face_map_move";
484   ot->description = "Move the active face map up/down in the list";
485
486   /* api callbacks */
487   ot->poll = face_map_supported_poll;
488   ot->exec = face_map_move_exec;
489
490   /* flags */
491   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
492
493   RNA_def_enum(
494       ot->srna, "direction", fmap_slot_move, 0, "Direction", "Direction to move, UP or DOWN");
495 }