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