Blender  V2.93
object_facemap.c
Go to the documentation of this file.
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 
24 #include <string.h>
25 
26 #include "DNA_mesh_types.h"
27 #include "DNA_object_types.h"
28 
29 #include "BLI_listbase.h"
30 #include "BLI_string.h"
31 #include "BLI_string_utils.h"
32 #include "BLI_utildefines.h"
33 
34 #include "BKE_customdata.h"
35 #include "BKE_editmesh.h"
36 #include "BKE_object.h"
37 #include "BKE_object_deform.h"
38 #include "BKE_object_facemap.h" /* own include */
39 
40 #include "BLT_translation.h"
41 
42 #include "MEM_guardedalloc.h"
43 
44 #include "RNA_access.h"
45 #include "RNA_define.h"
46 
47 static bool fmap_unique_check(void *arg, const char *name)
48 {
49  struct {
50  Object *ob;
51  void *fm;
52  } *data = arg;
53 
54  bFaceMap *fmap;
55 
56  for (fmap = data->ob->fmaps.first; fmap; fmap = fmap->next) {
57  if (data->fm != fmap) {
58  if (STREQ(fmap->name, name)) {
59  return true;
60  }
61  }
62  }
63 
64  return false;
65 }
66 
68 {
69  bFaceMap *outfmap;
70 
71  if (!infmap) {
72  return NULL;
73  }
74 
75  outfmap = MEM_callocN(sizeof(bFaceMap), "copy facemap");
76 
77  /* For now, just copy everything over. */
78  memcpy(outfmap, infmap, sizeof(bFaceMap));
79 
80  outfmap->next = outfmap->prev = NULL;
81 
82  return outfmap;
83 }
84 
85 void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
86 {
87  bFaceMap *fmap, *fmapn;
88 
89  BLI_listbase_clear(outbase);
90 
91  for (fmap = inbase->first; fmap; fmap = fmap->next) {
92  fmapn = fmap_duplicate(fmap);
93  BLI_addtail(outbase, fmapn);
94  }
95 }
96 
98 {
99  struct {
100  Object *ob;
101  void *fmap;
102  } data;
103  data.ob = ob;
104  data.fmap = fmap;
105 
106  BLI_uniquename_cb(fmap_unique_check, &data, DATA_("Group"), '.', fmap->name, sizeof(fmap->name));
107 }
108 
110 {
111  bFaceMap *fmap;
112 
113  if (!ob || ob->type != OB_MESH) {
114  return NULL;
115  }
116 
117  fmap = MEM_callocN(sizeof(bFaceMap), __func__);
118 
119  BLI_strncpy(fmap->name, name, sizeof(fmap->name));
120 
121  BLI_addtail(&ob->fmaps, fmap);
122 
123  ob->actfmap = BLI_listbase_count(&ob->fmaps);
124 
126 
127  return fmap;
128 }
129 
131 {
132  return BKE_object_facemap_add_name(ob, DATA_("FaceMap"));
133 }
134 
135 static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
136 {
137  const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
138 
139  if (ob->type == OB_MESH) {
140  Mesh *me = ob->data;
141 
142  if (me->edit_mesh) {
143  BMEditMesh *em = me->edit_mesh;
144  const int cd_fmap_offset = CustomData_get_offset(&em->bm->pdata, CD_FACEMAP);
145 
146  if (cd_fmap_offset != -1) {
147  BMFace *efa;
148  BMIter iter;
149  int *map;
150 
151  if (purge) {
152  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
153  map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
154 
155  if (map) {
156  if (*map == fmap_nr) {
157  *map = -1;
158  }
159  else if (*map > fmap_nr) {
160  *map -= 1;
161  }
162  }
163  }
164  }
165  else {
166  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
167  map = BM_ELEM_CD_GET_VOID_P(efa, cd_fmap_offset);
168 
169  if (map && *map == fmap_nr &&
170  (!do_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT))) {
171  *map = -1;
172  }
173  }
174  }
175  }
176 
177  if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
178  ob->actfmap--;
179  }
180 
181  BLI_remlink(&ob->fmaps, fmap);
182  MEM_freeN(fmap);
183  }
184  }
185 }
186 
187 static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
188 {
189  const int fmap_nr = BLI_findindex(&ob->fmaps, fmap);
190 
191  if (ob->type == OB_MESH) {
192  Mesh *me = ob->data;
193 
194  if (CustomData_has_layer(&me->pdata, CD_FACEMAP)) {
195  int *map = CustomData_get_layer(&me->pdata, CD_FACEMAP);
196  int i;
197 
198  if (map) {
199  for (i = 0; i < me->totpoly; i++) {
200  if (map[i] == fmap_nr) {
201  map[i] = -1;
202  }
203  else if (purge && map[i] > fmap_nr) {
204  map[i]--;
205  }
206  }
207  }
208  }
209 
210  if (ob->actfmap == BLI_listbase_count(&ob->fmaps)) {
211  ob->actfmap--;
212  }
213 
214  BLI_remlink(&ob->fmaps, fmap);
215  MEM_freeN(fmap);
216  }
217 }
218 
219 static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
220 {
221  if (is_edit_mode) {
222  object_fmap_remove_edit_mode(ob, fmap, false, purge);
223  }
224  else {
225  object_fmap_remove_object_mode(ob, fmap, purge);
226  }
227 }
228 
230 {
231  fmap_remove_exec(ob, fmap, BKE_object_is_in_editmode(ob), true);
232 }
233 
235 {
236  bFaceMap *fmap = (bFaceMap *)ob->fmaps.first;
237 
238  if (fmap) {
239  const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob);
240 
241  while (fmap) {
242  bFaceMap *next_fmap = fmap->next;
243  fmap_remove_exec(ob, fmap, edit_mode, false);
244  fmap = next_fmap;
245  }
246  }
247  /* remove all face-maps */
248  if (ob->type == OB_MESH) {
249  Mesh *me = ob->data;
250  CustomData_free_layer(&me->pdata, CD_FACEMAP, me->totpoly, 0);
251  }
252  ob->actfmap = 0;
253 }
254 
255 int BKE_object_facemap_name_index(Object *ob, const char *name)
256 {
257  return (name) ? BLI_findstringindex(&ob->fmaps, name, offsetof(bFaceMap, name)) : -1;
258 }
259 
261 {
262  return BLI_findstring(&ob->fmaps, name, offsetof(bFaceMap, name));
263 }
264 
265 int *BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
266 {
267  /* Build src to merged mapping of facemap indices. */
268  if (BLI_listbase_is_empty(&ob_src->fmaps) || BLI_listbase_is_empty(&ob_dst->fmaps)) {
269  *r_map_len = 0;
270  return NULL;
271  }
272 
273  *r_map_len = BLI_listbase_count(&ob_src->fmaps);
274  int *fmap_index_map = MEM_malloc_arrayN(
275  *r_map_len, sizeof(*fmap_index_map), "defgroup index map create");
276  bool is_fmap_remap_needed = false;
277 
278  int i = 0;
279  for (bFaceMap *fmap_src = ob_src->fmaps.first; fmap_src; fmap_src = fmap_src->next, i++) {
280  fmap_index_map[i] = BKE_object_facemap_name_index(ob_dst, fmap_src->name);
281  is_fmap_remap_needed = is_fmap_remap_needed || (fmap_index_map[i] != i);
282  }
283 
284  if (!is_fmap_remap_needed) {
285  MEM_freeN(fmap_index_map);
286  fmap_index_map = NULL;
287  *r_map_len = 0;
288  }
289 
290  return fmap_index_map;
291 }
292 
293 void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
294 {
295  if (map == NULL || map_len == 0) {
296  return;
297  }
298  for (int i = 0; i < fmap_len; i++, fmap++) {
299  *fmap = (*fmap < map_len && *fmap != -1) ? map[*fmap] : -1;
300  }
301 }
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_free_layer(struct CustomData *data, int type, int totelem, int index)
Definition: customdata.c:2655
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode_vgroup(const struct Object *ob)
bool BKE_object_is_in_editmode(const struct Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
Functions for dealing with object face-maps.
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:128
void * BLI_findstring(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_findstringindex(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
Definition: string_utils.c:294
#define STREQ(a, b)
#define DATA_(msgid)
@ CD_FACEMAP
Object is a sort of wrapper for general info.
@ OB_MESH
Read Guarded memory(de)allocation.
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:48
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
bFaceMap * BKE_object_facemap_add(Object *ob)
int BKE_object_facemap_name_index(Object *ob, const char *name)
void BKE_object_facemap_clear(Object *ob)
bFaceMap * BKE_object_facemap_find_name(Object *ob, const char *name)
bFaceMap * BKE_object_facemap_add_name(Object *ob, const char *name)
void BKE_object_facemap_copy_list(ListBase *outbase, const ListBase *inbase)
static bool fmap_unique_check(void *arg, const char *name)
void BKE_object_facemap_remove(Object *ob, bFaceMap *fmap)
static void fmap_remove_exec(Object *ob, bFaceMap *fmap, const bool is_edit_mode, const bool purge)
static void object_fmap_remove_object_mode(Object *ob, bFaceMap *fmap, bool purge)
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
int * BKE_object_facemap_index_map_create(Object *ob_src, Object *ob_dst, int *r_map_len)
static bFaceMap * fmap_duplicate(bFaceMap *infmap)
static void object_fmap_remove_edit_mode(Object *ob, bFaceMap *fmap, bool do_selected, bool purge)
void BKE_object_facemap_unique_name(Object *ob, bFaceMap *fmap)
struct BMesh * bm
Definition: BKE_editmesh.h:52
CustomData pdata
Definition: bmesh_class.h:337
void * first
Definition: DNA_listBase.h:47
struct BMEditMesh * edit_mesh
int totpoly
ustring name
Definition: node.h:174
unsigned short actfmap
void * data
ListBase fmaps
struct bFaceMap * next
struct bFaceMap * prev
char name[64]