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