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 
17 /** \file
18  * \ingroup bmesh
19  *
20  * BMesh operator access.
21  */
22 
23 #include "MEM_guardedalloc.h"
24 
25 #include "BLI_listbase.h"
26 #include "BLI_math.h"
27 #include "BLI_memarena.h"
28 #include "BLI_mempool.h"
29 #include "BLI_string.h"
30 #include "BLI_utildefines.h"
31 
32 #include "BLT_translation.h"
33 
34 #include "bmesh.h"
35 #include "intern/bmesh_private.h"
36 
37 /* forward declarations */
38 static void bmo_flag_layer_alloc(BMesh *bm);
39 static void bmo_flag_layer_free(BMesh *bm);
40 static void bmo_flag_layer_clear(BMesh *bm);
41 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier);
42 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
43                                       const char *identifier);
44 
45 static const char *bmo_error_messages[] = {
46     NULL,
47     N_("Could not connect vertices"),
48     N_("Could not dissolve faces"),
49     N_("Invalid selection"),
50     N_("Internal mesh error"),
51     N_("Convex hull failed"),
52 };
53 
54 BLI_STATIC_ASSERT(ARRAY_SIZE(bmo_error_messages) == BMERR_TOTAL, "message mismatch");
55 
56 /* operator slot type information - size of one element of the type given. */
57 const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
58     0,                /*  0: BMO_OP_SLOT_SENTINEL */
59     sizeof(int),      /*  1: BMO_OP_SLOT_BOOL */
60     sizeof(int),      /*  2: BMO_OP_SLOT_INT */
61     sizeof(float),    /*  3: BMO_OP_SLOT_FLT */
62     sizeof(void *),   /*  4: BMO_OP_SLOT_PNT */
63     sizeof(void *),   /*  5: BMO_OP_SLOT_PNT */
64     0,                /*  6: unused */
65     0,                /*  7: unused */
66     sizeof(float[3]), /*  8: BMO_OP_SLOT_VEC */
67     sizeof(void *),   /*  9: BMO_OP_SLOT_ELEMENT_BUF */
68     sizeof(void *),   /* 10: BMO_OP_SLOT_MAPPING */
69 };
70 
71 /* Dummy slot so there is something to return when slot name lookup fails */
72 // static BMOpSlot BMOpEmptySlot = {0};
73 
BMO_op_flag_enable(BMesh * UNUSED (bm),BMOperator * op,const int op_flag)74 void BMO_op_flag_enable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
75 {
76   op->flag |= op_flag;
77 }
78 
BMO_op_flag_disable(BMesh * UNUSED (bm),BMOperator * op,const int op_flag)79 void BMO_op_flag_disable(BMesh *UNUSED(bm), BMOperator *op, const int op_flag)
80 {
81   op->flag &= ~op_flag;
82 }
83 
84 /**
85  * \brief BMESH OPSTACK PUSH
86  *
87  * Pushes the opstack down one level and allocates a new flag layer if appropriate.
88  */
BMO_push(BMesh * bm,BMOperator * UNUSED (op))89 void BMO_push(BMesh *bm, BMOperator *UNUSED(op))
90 {
91   bm->toolflag_index++;
92 
93   BLI_assert(bm->totflags > 0);
94 
95   /* add flag layer, if appropriate */
96   if (bm->toolflag_index > 0) {
97     bmo_flag_layer_alloc(bm);
98   }
99   else {
100     bmo_flag_layer_clear(bm);
101   }
102 }
103 
104 /**
105  * \brief BMESH OPSTACK POP
106  *
107  * Pops the opstack one level and frees a flag layer if appropriate
108  *
109  * BMESH_TODO: investigate NOT freeing flag layers.
110  */
BMO_pop(BMesh * bm)111 void BMO_pop(BMesh *bm)
112 {
113   if (bm->toolflag_index > 0) {
114     bmo_flag_layer_free(bm);
115   }
116 
117   bm->toolflag_index--;
118 }
119 
120 /* use for both slot_types_in and slot_types_out */
bmo_op_slots_init(const BMOSlotType * slot_types,BMOpSlot * slot_args)121 static void bmo_op_slots_init(const BMOSlotType *slot_types, BMOpSlot *slot_args)
122 {
123   BMOpSlot *slot;
124   uint i;
125   for (i = 0; slot_types[i].type; i++) {
126     slot = &slot_args[i];
127     slot->slot_name = slot_types[i].name;
128     slot->slot_type = slot_types[i].type;
129     slot->slot_subtype = slot_types[i].subtype;
130     // slot->index = i;  // UNUSED
131 
132     switch (slot->slot_type) {
133       case BMO_OP_SLOT_MAPPING:
134         slot->data.ghash = BLI_ghash_ptr_new("bmesh slot map hash");
135         break;
136       case BMO_OP_SLOT_INT:
137         if (ELEM(slot->slot_subtype.intg,
138                  BMO_OP_SLOT_SUBTYPE_INT_ENUM,
139                  BMO_OP_SLOT_SUBTYPE_INT_FLAG)) {
140           slot->data.enum_data.flags = slot_types[i].enum_flags;
141           /* Set the first value of the enum as the default value. */
142           slot->data.i = slot->data.enum_data.flags[0].value;
143         }
144       default:
145         break;
146     }
147   }
148 }
149 
bmo_op_slots_free(const BMOSlotType * slot_types,BMOpSlot * slot_args)150 static void bmo_op_slots_free(const BMOSlotType *slot_types, BMOpSlot *slot_args)
151 {
152   BMOpSlot *slot;
153   uint i;
154   for (i = 0; slot_types[i].type; i++) {
155     slot = &slot_args[i];
156     switch (slot->slot_type) {
157       case BMO_OP_SLOT_MAPPING:
158         BLI_ghash_free(slot->data.ghash, NULL, NULL);
159         break;
160       default:
161         break;
162     }
163   }
164 }
165 
166 /**
167  * \brief BMESH OPSTACK INIT OP
168  *
169  * Initializes an operator structure to a certain type
170  */
BMO_op_init(BMesh * bm,BMOperator * op,const int flag,const char * opname)171 void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
172 {
173   int opcode = BMO_opcode_from_opname(opname);
174 
175 #ifdef DEBUG
176   BM_ELEM_INDEX_VALIDATE(bm, "pre bmo", opname);
177 #else
178   (void)bm;
179 #endif
180 
181   if (opcode == -1) {
182     opcode = 0; /* error!, already printed, have a better way to handle this? */
183   }
184 
185   memset(op, 0, sizeof(BMOperator));
186   op->type = opcode;
187   op->type_flag = bmo_opdefines[opcode]->type_flag;
188   op->flag = flag;
189 
190   /* initialize the operator slot types */
191   bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_in, op->slots_in);
192   bmo_op_slots_init(bmo_opdefines[opcode]->slot_types_out, op->slots_out);
193 
194   /* callback */
195   op->exec = bmo_opdefines[opcode]->exec;
196 
197   /* memarena, used for operator's slot buffers */
198   op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
199   BLI_memarena_use_calloc(op->arena);
200 }
201 
202 /**
203  * \brief BMESH OPSTACK EXEC OP
204  *
205  * Executes a passed in operator.
206  *
207  * This handles the allocation and freeing of temporary flag
208  * layers and starting/stopping the modeling loop.
209  * Can be called from other operators exec callbacks as well.
210  */
BMO_op_exec(BMesh * bm,BMOperator * op)211 void BMO_op_exec(BMesh *bm, BMOperator *op)
212 {
213   /* allocate tool flags on demand */
214   BM_mesh_elem_toolflags_ensure(bm);
215 
216   BMO_push(bm, op);
217 
218   if (bm->toolflag_index == 1) {
219     bmesh_edit_begin(bm, op->type_flag);
220   }
221   op->exec(bm, op);
222 
223   if (bm->toolflag_index == 1) {
224     bmesh_edit_end(bm, op->type_flag);
225   }
226 
227   BMO_pop(bm);
228 }
229 
230 /**
231  * \brief BMESH OPSTACK FINISH OP
232  *
233  * Does housekeeping chores related to finishing up an operator.
234  */
BMO_op_finish(BMesh * bm,BMOperator * op)235 void BMO_op_finish(BMesh *bm, BMOperator *op)
236 {
237   bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_in, op->slots_in);
238   bmo_op_slots_free(bmo_opdefines[op->type]->slot_types_out, op->slots_out);
239 
240   BLI_memarena_free(op->arena);
241 
242 #ifdef DEBUG
243   BM_ELEM_INDEX_VALIDATE(bm, "post bmo", bmo_opdefines[op->type]->opname);
244 
245   /* avoid accidental re-use */
246   memset(op, 0xff, sizeof(*op));
247 #else
248   (void)bm;
249 #endif
250 }
251 
252 /**
253  * \brief BMESH OPSTACK HAS SLOT
254  *
255  * \return Success if the slot if found.
256  */
BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * identifier)257 bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
258 {
259   int slot_code = bmo_name_to_slotcode(slot_args, identifier);
260   return (slot_code >= 0);
261 }
262 
263 /**
264  * \brief BMESH OPSTACK GET SLOT
265  *
266  * Returns a pointer to the slot of type 'slot_code'
267  */
BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * identifier)268 BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
269 {
270   int slot_code = bmo_name_to_slotcode_check(slot_args, identifier);
271 
272   if (UNLIKELY(slot_code < 0)) {
273     // return &BMOpEmptySlot;
274     BLI_assert(0);
275     return NULL; /* better crash */
276   }
277 
278   return &slot_args[slot_code];
279 }
280 
281 /**
282  * \brief BMESH OPSTACK COPY SLOT
283  *
284  * define used.
285  * Copies data from one slot to another.
286  */
_bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],const char * slot_name_src,BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],const char * slot_name_dst,struct MemArena * arena_dst)287 void _bmo_slot_copy(BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
288                     const char *slot_name_src,
289                     BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
290                     const char *slot_name_dst,
291                     struct MemArena *arena_dst)
292 {
293   BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
294   BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
295 
296   if (slot_src == slot_dst) {
297     return;
298   }
299 
300   BLI_assert(slot_src->slot_type == slot_dst->slot_type);
301   if (slot_src->slot_type != slot_dst->slot_type) {
302     return;
303   }
304 
305   if (slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
306     /* do buffer copy */
307     slot_dst->data.buf = NULL;
308     slot_dst->len = slot_src->len;
309     if (slot_dst->len) {
310       /* check dest has all flags enabled that the source has */
311       const eBMOpSlotSubType_Elem src_elem_flag = (slot_src->slot_subtype.elem & BM_ALL_NOLOOP);
312       const eBMOpSlotSubType_Elem dst_elem_flag = (slot_dst->slot_subtype.elem & BM_ALL_NOLOOP);
313 
314       if ((src_elem_flag | dst_elem_flag) == dst_elem_flag) {
315         /* pass */
316       }
317       else {
318         /* check types */
319         const uint tot = slot_src->len;
320         uint i;
321         uint out = 0;
322         BMElem **ele_src = (BMElem **)slot_src->data.buf;
323         for (i = 0; i < tot; i++, ele_src++) {
324           if ((*ele_src)->head.htype & dst_elem_flag) {
325             out++;
326           }
327         }
328         if (out != tot) {
329           slot_dst->len = out;
330         }
331       }
332 
333       if (slot_dst->len) {
334         const int slot_alloc_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type] * slot_dst->len;
335         slot_dst->data.buf = BLI_memarena_alloc(arena_dst, slot_alloc_size);
336         if (slot_src->len == slot_dst->len) {
337           memcpy(slot_dst->data.buf, slot_src->data.buf, slot_alloc_size);
338         }
339         else {
340           /* only copy compatible elements */
341           const uint tot = slot_src->len;
342           uint i;
343           BMElem **ele_src = (BMElem **)slot_src->data.buf;
344           BMElem **ele_dst = (BMElem **)slot_dst->data.buf;
345           for (i = 0; i < tot; i++, ele_src++) {
346             if ((*ele_src)->head.htype & dst_elem_flag) {
347               *ele_dst = *ele_src;
348               ele_dst++;
349             }
350           }
351         }
352       }
353     }
354   }
355   else if (slot_dst->slot_type == BMO_OP_SLOT_MAPPING) {
356     GHashIterator gh_iter;
357     GHASH_ITER (gh_iter, slot_src->data.ghash) {
358       void *key = BLI_ghashIterator_getKey(&gh_iter);
359       void *val = BLI_ghashIterator_getValue(&gh_iter);
360       BLI_ghash_insert(slot_dst->data.ghash, key, val);
361     }
362   }
363   else {
364     slot_dst->data = slot_src->data;
365   }
366 }
367 
368 /*
369  * BMESH OPSTACK SET XXX
370  *
371  * Sets the value of a slot depending on its type
372  */
373 
BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const float f)374 void BMO_slot_float_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float f)
375 {
376   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
377   BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
378   if (!(slot->slot_type == BMO_OP_SLOT_FLT)) {
379     return;
380   }
381 
382   slot->data.f = f;
383 }
384 
BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const int i)385 void BMO_slot_int_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int i)
386 {
387   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
388   BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
389   if (!(slot->slot_type == BMO_OP_SLOT_INT)) {
390     return;
391   }
392 
393   slot->data.i = i;
394 }
395 
BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const bool i)396 void BMO_slot_bool_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const bool i)
397 {
398   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
399   BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
400   if (!(slot->slot_type == BMO_OP_SLOT_BOOL)) {
401     return;
402   }
403 
404   slot->data.i = i;
405 }
406 
407 /* only supports square mats */
BMO_slot_mat_set(BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const float * mat,int size)408 void BMO_slot_mat_set(BMOperator *op,
409                       BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
410                       const char *slot_name,
411                       const float *mat,
412                       int size)
413 {
414   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
415   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
416   if (!(slot->slot_type == BMO_OP_SLOT_MAT)) {
417     return;
418   }
419 
420   slot->len = 4;
421   slot->data.p = BLI_memarena_alloc(op->arena, sizeof(float[4][4]));
422 
423   if (size == 4) {
424     copy_m4_m4(slot->data.p, (float(*)[4])mat);
425   }
426   else if (size == 3) {
427     copy_m4_m3(slot->data.p, (float(*)[3])mat);
428   }
429   else {
430     fprintf(stderr, "%s: invalid size argument %d (bmesh internal error)\n", __func__, size);
431 
432     zero_m4(slot->data.p);
433   }
434 }
435 
BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,float r_mat[4][4])436 void BMO_slot_mat4_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
437                        const char *slot_name,
438                        float r_mat[4][4])
439 {
440   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
441   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
442   if (!(slot->slot_type == BMO_OP_SLOT_MAT)) {
443     return;
444   }
445 
446   if (slot->data.p) {
447     copy_m4_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
448   }
449   else {
450     unit_m4(r_mat);
451   }
452 }
453 
BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,float r_mat[3][3])454 void BMO_slot_mat3_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
455                        const char *slot_name,
456                        float r_mat[3][3])
457 {
458   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
459   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAT);
460   if (!(slot->slot_type == BMO_OP_SLOT_MAT)) {
461     return;
462   }
463 
464   if (slot->data.p) {
465     copy_m3_m4(r_mat, BMO_SLOT_AS_MATRIX(slot));
466   }
467   else {
468     unit_m3(r_mat);
469   }
470 }
471 
BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,void * p)472 void BMO_slot_ptr_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, void *p)
473 {
474   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
475   BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
476   if (!(slot->slot_type == BMO_OP_SLOT_PTR)) {
477     return;
478   }
479 
480   slot->data.p = p;
481 }
482 
BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const float vec[3])483 void BMO_slot_vec_set(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
484                       const char *slot_name,
485                       const float vec[3])
486 {
487   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
488   BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
489   if (!(slot->slot_type == BMO_OP_SLOT_VEC)) {
490     return;
491   }
492 
493   copy_v3_v3(slot->data.vec, vec);
494 }
495 
BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)496 float BMO_slot_float_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
497 {
498   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
499   BLI_assert(slot->slot_type == BMO_OP_SLOT_FLT);
500   if (!(slot->slot_type == BMO_OP_SLOT_FLT)) {
501     return 0.0f;
502   }
503 
504   return slot->data.f;
505 }
506 
BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)507 int BMO_slot_int_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
508 {
509   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
510   BLI_assert(slot->slot_type == BMO_OP_SLOT_INT);
511   if (!(slot->slot_type == BMO_OP_SLOT_INT)) {
512     return 0;
513   }
514 
515   return slot->data.i;
516 }
517 
BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)518 bool BMO_slot_bool_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
519 {
520   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
521   BLI_assert(slot->slot_type == BMO_OP_SLOT_BOOL);
522   if (!(slot->slot_type == BMO_OP_SLOT_BOOL)) {
523     return 0;
524   }
525 
526   return slot->data.i;
527 }
528 
529 /* if you want a copy of the elem buffer */
BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,int * len)530 void *BMO_slot_as_arrayN(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int *len)
531 {
532   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
533   void **ret;
534 
535   /* could add support for mapping type */
536   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
537 
538   ret = MEM_mallocN(sizeof(void *) * slot->len, __func__);
539   memcpy(ret, slot->data.buf, sizeof(void *) * slot->len);
540   *len = slot->len;
541   return ret;
542 }
543 
BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)544 void *BMO_slot_ptr_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
545 {
546   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
547   BLI_assert(slot->slot_type == BMO_OP_SLOT_PTR);
548   if (!(slot->slot_type == BMO_OP_SLOT_PTR)) {
549     return NULL;
550   }
551 
552   return slot->data.p;
553 }
554 
BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,float r_vec[3])555 void BMO_slot_vec_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, float r_vec[3])
556 {
557   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
558   BLI_assert(slot->slot_type == BMO_OP_SLOT_VEC);
559   if (!(slot->slot_type == BMO_OP_SLOT_VEC)) {
560     return;
561   }
562 
563   copy_v3_v3(r_vec, slot->data.vec);
564 }
565 
566 /*
567  * BMO_COUNTFLAG
568  *
569  * Counts the number of elements of a certain type that have a
570  * specific flag enabled (or disabled if test_for_enabled is false).
571  */
572 
bmo_mesh_flag_count(BMesh * bm,const char htype,const short oflag,const bool test_for_enabled)573 static int bmo_mesh_flag_count(BMesh *bm,
574                                const char htype,
575                                const short oflag,
576                                const bool test_for_enabled)
577 {
578   int count_vert = 0, count_edge = 0, count_face = 0;
579 
580   if (htype & BM_VERT) {
581     BMIter iter;
582     BMVert *ele;
583     BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
584       if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
585         count_vert++;
586       }
587     }
588   }
589   if (htype & BM_EDGE) {
590     BMIter iter;
591     BMEdge *ele;
592     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
593       if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
594         count_edge++;
595       }
596     }
597   }
598   if (htype & BM_FACE) {
599     BMIter iter;
600     BMFace *ele;
601     BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
602       if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) {
603         count_face++;
604       }
605     }
606   }
607 
608   return (count_vert + count_edge + count_face);
609 }
610 
BMO_mesh_enabled_flag_count(BMesh * bm,const char htype,const short oflag)611 int BMO_mesh_enabled_flag_count(BMesh *bm, const char htype, const short oflag)
612 {
613   return bmo_mesh_flag_count(bm, htype, oflag, true);
614 }
615 
BMO_mesh_disabled_flag_count(BMesh * bm,const char htype,const short oflag)616 int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag)
617 {
618   return bmo_mesh_flag_count(bm, htype, oflag, false);
619 }
620 
BMO_mesh_flag_disable_all(BMesh * bm,BMOperator * UNUSED (op),const char htype,const short oflag)621 void BMO_mesh_flag_disable_all(BMesh *bm,
622                                BMOperator *UNUSED(op),
623                                const char htype,
624                                const short oflag)
625 {
626   if (htype & BM_VERT) {
627     BMIter iter;
628     BMVert *ele;
629     BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
630       BMO_vert_flag_disable(bm, ele, oflag);
631     }
632   }
633   if (htype & BM_EDGE) {
634     BMIter iter;
635     BMEdge *ele;
636     BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
637       BMO_edge_flag_disable(bm, ele, oflag);
638     }
639   }
640   if (htype & BM_FACE) {
641     BMIter iter;
642     BMFace *ele;
643     BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
644       BMO_face_flag_disable(bm, ele, oflag);
645     }
646   }
647 }
648 
BMO_mesh_selected_remap(BMesh * bm,BMOpSlot * slot_vert_map,BMOpSlot * slot_edge_map,BMOpSlot * slot_face_map,const bool check_select)649 void BMO_mesh_selected_remap(BMesh *bm,
650                              BMOpSlot *slot_vert_map,
651                              BMOpSlot *slot_edge_map,
652                              BMOpSlot *slot_face_map,
653                              const bool check_select)
654 {
655   if (bm->selected.first) {
656     BMEditSelection *ese, *ese_next;
657     BMOpSlot *slot_elem_map;
658 
659     for (ese = bm->selected.first; ese; ese = ese_next) {
660       ese_next = ese->next;
661 
662       switch (ese->htype) {
663         case BM_VERT:
664           slot_elem_map = slot_vert_map;
665           break;
666         case BM_EDGE:
667           slot_elem_map = slot_edge_map;
668           break;
669         default:
670           slot_elem_map = slot_face_map;
671           break;
672       }
673 
674       ese->ele = BMO_slot_map_elem_get(slot_elem_map, ese->ele);
675 
676       if (UNLIKELY((ese->ele == NULL) ||
677                    (check_select && (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false)))) {
678         BLI_remlink(&bm->selected, ese);
679         MEM_freeN(ese);
680       }
681     }
682   }
683 
684   if (bm->act_face) {
685     BMFace *f = BMO_slot_map_elem_get(slot_face_map, bm->act_face);
686     if (f) {
687       bm->act_face = f;
688     }
689   }
690 }
691 
BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)692 int BMO_slot_buffer_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
693 {
694   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
695   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
696 
697   /* check if its actually a buffer */
698   if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF) {
699     return 0;
700   }
701 
702   return slot->len;
703 }
704 
BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)705 int BMO_slot_map_count(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
706 {
707   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
708   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
709   return BLI_ghash_len(slot->data.ghash);
710 }
711 
712 /* inserts a key/value mapping into a mapping slot.  note that it copies the
713  * value, it doesn't store a reference to it. */
714 
BMO_slot_map_insert(BMOperator * op,BMOpSlot * slot,const void * element,const void * data)715 void BMO_slot_map_insert(BMOperator *op, BMOpSlot *slot, const void *element, const void *data)
716 {
717   (void)op; /* Ignored in release builds. */
718 
719   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
720   BMO_ASSERT_SLOT_IN_OP(slot, op);
721 
722   BLI_ghash_insert(slot->data.ghash, (void *)element, (void *)data);
723 }
724 
725 #if 0
726 void *bmo_slot_buffer_grow(BMesh *bm, BMOperator *op, int slot_code, int totadd)
727 {
728   BMOpSlot *slot = &op->slots[slot_code];
729   void *tmp;
730   ssize_t allocsize;
731 
732   BLI_assert(slot->slottype == BMO_OP_SLOT_ELEMENT_BUF);
733 
734   /* check if its actually a buffer */
735   if (slot->slottype != BMO_OP_SLOT_ELEMENT_BUF) {
736     return NULL;
737   }
738 
739   if (slot->flag & BMOS_DYNAMIC_ARRAY) {
740     if (slot->len >= slot->size) {
741       slot->size = (slot->size + 1 + totadd) * 2;
742 
743       allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] *
744                   slot->size;
745       slot->data.buf = MEM_recallocN_id(slot->data.buf, allocsize, "opslot dynamic array");
746     }
747 
748     slot->len += totadd;
749   }
750   else {
751     slot->flag |= BMOS_DYNAMIC_ARRAY;
752     slot->len += totadd;
753     slot->size = slot->len + 2;
754 
755     allocsize = BMO_OPSLOT_TYPEINFO[bmo_opdefines[op->type]->slot_types[slot_code].type] *
756                 slot->len;
757 
758     tmp = slot->data.buf;
759     slot->data.buf = MEM_callocN(allocsize, "opslot dynamic array");
760     memcpy(slot->data.buf, tmp, allocsize);
761   }
762 
763   return slot->data.buf;
764 }
765 #endif
766 
BMO_slot_map_to_flag(BMesh * bm,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag)767 void BMO_slot_map_to_flag(BMesh *bm,
768                           BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
769                           const char *slot_name,
770                           const char htype,
771                           const short oflag)
772 {
773   GHashIterator gh_iter;
774   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
775   BMElemF *ele_f;
776 
777   BLI_assert(slot->slot_type == BMO_OP_SLOT_MAPPING);
778 
779   GHASH_ITER (gh_iter, slot->data.ghash) {
780     ele_f = BLI_ghashIterator_getKey(&gh_iter);
781     if (ele_f->head.htype & htype) {
782       BMO_elem_flag_enable(bm, ele_f, oflag);
783     }
784   }
785 }
786 
BMO_slot_buffer_alloc(BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const int len)787 void *BMO_slot_buffer_alloc(BMOperator *op,
788                             BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
789                             const char *slot_name,
790                             const int len)
791 {
792   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
793 
794   /* check if its actually a buffer */
795   if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF) {
796     return NULL;
797   }
798 
799   slot->len = len;
800   if (len) {
801     slot->data.buf = BLI_memarena_alloc(op->arena, BMO_OPSLOT_TYPEINFO[slot->slot_type] * len);
802   }
803   else {
804     slot->data.buf = NULL;
805   }
806 
807   return slot->data.buf;
808 }
809 
810 /**
811  * \brief BMO_ALL_TO_SLOT
812  *
813  * Copies all elements of a certain type into an operator slot.
814  */
BMO_slot_buffer_from_all(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype)815 void BMO_slot_buffer_from_all(BMesh *bm,
816                               BMOperator *op,
817                               BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
818                               const char *slot_name,
819                               const char htype)
820 {
821   BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
822   int totelement = 0, i = 0;
823 
824   BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
825   BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
826 
827   if (htype & BM_VERT) {
828     totelement += bm->totvert;
829   }
830   if (htype & BM_EDGE) {
831     totelement += bm->totedge;
832   }
833   if (htype & BM_FACE) {
834     totelement += bm->totface;
835   }
836 
837   if (totelement) {
838     BMIter iter;
839     BMHeader *ele;
840 
841     BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
842 
843     /* TODO - collapse these loops into one */
844 
845     if (htype & BM_VERT) {
846       BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
847         output->data.buf[i] = ele;
848         i++;
849       }
850     }
851 
852     if (htype & BM_EDGE) {
853       BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
854         output->data.buf[i] = ele;
855         i++;
856       }
857     }
858 
859     if (htype & BM_FACE) {
860       BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
861         output->data.buf[i] = ele;
862         i++;
863       }
864     }
865   }
866 }
867 
868 /**
869  * \brief BMO_HEADERFLAG_TO_SLOT
870  *
871  * Copies elements of a certain type, which have a certain header flag
872  * enabled/disabled into a slot for an operator.
873  */
bmo_slot_buffer_from_hflag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const char hflag,const bool test_for_enabled)874 static void bmo_slot_buffer_from_hflag(BMesh *bm,
875                                        BMOperator *op,
876                                        BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
877                                        const char *slot_name,
878                                        const char htype,
879                                        const char hflag,
880                                        const bool test_for_enabled)
881 {
882   BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
883   int totelement = 0, i = 0;
884   const bool respecthide = ((op->flag & BMO_FLAG_RESPECT_HIDE) != 0) &&
885                            ((hflag & BM_ELEM_HIDDEN) == 0);
886 
887   BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
888   BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
889   BLI_assert((output->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
890 
891   if (test_for_enabled) {
892     totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, respecthide);
893   }
894   else {
895     totelement = BM_mesh_elem_hflag_count_disabled(bm, htype, hflag, respecthide);
896   }
897 
898   if (totelement) {
899     BMIter iter;
900     BMElem *ele;
901 
902     BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
903 
904     /* TODO - collapse these loops into one */
905 
906     if (htype & BM_VERT) {
907       BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
908         if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
909             BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
910           output->data.buf[i] = ele;
911           i++;
912         }
913       }
914     }
915 
916     if (htype & BM_EDGE) {
917       BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
918         if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
919             BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
920           output->data.buf[i] = ele;
921           i++;
922         }
923       }
924     }
925 
926     if (htype & BM_FACE) {
927       BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
928         if ((!respecthide || !BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) &&
929             BM_elem_flag_test_bool(ele, hflag) == test_for_enabled) {
930           output->data.buf[i] = ele;
931           i++;
932         }
933       }
934     }
935   }
936   else {
937     output->len = 0;
938   }
939 }
940 
BMO_slot_buffer_from_enabled_hflag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const char hflag)941 void BMO_slot_buffer_from_enabled_hflag(BMesh *bm,
942                                         BMOperator *op,
943                                         BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
944                                         const char *slot_name,
945                                         const char htype,
946                                         const char hflag)
947 {
948   bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, true);
949 }
950 
BMO_slot_buffer_from_disabled_hflag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const char hflag)951 void BMO_slot_buffer_from_disabled_hflag(BMesh *bm,
952                                          BMOperator *op,
953                                          BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
954                                          const char *slot_name,
955                                          const char htype,
956                                          const char hflag)
957 {
958   bmo_slot_buffer_from_hflag(bm, op, slot_args, slot_name, htype, hflag, false);
959 }
960 
BMO_slot_buffer_from_single(BMOperator * op,BMOpSlot * slot,BMHeader * ele)961 void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
962 {
963   BMO_ASSERT_SLOT_IN_OP(slot, op);
964   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
965   BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
966   BLI_assert(slot->len == 0 || slot->len == 1);
967 
968   BLI_assert(slot->slot_subtype.elem & ele->htype);
969 
970   slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(void *) * 4); /* XXX, why 'x4' ? */
971   slot->len = 1;
972   *slot->data.buf = ele;
973 }
974 
BMO_slot_buffer_from_array(BMOperator * op,BMOpSlot * slot,BMHeader ** ele_buffer,int ele_buffer_len)975 void BMO_slot_buffer_from_array(BMOperator *op,
976                                 BMOpSlot *slot,
977                                 BMHeader **ele_buffer,
978                                 int ele_buffer_len)
979 {
980   BMO_ASSERT_SLOT_IN_OP(slot, op);
981   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
982   BLI_assert(slot->len == 0 || slot->len == ele_buffer_len);
983 
984   if (slot->data.buf == NULL) {
985     slot->data.buf = BLI_memarena_alloc(op->arena, sizeof(*slot->data.buf) * ele_buffer_len);
986   }
987 
988   slot->len = ele_buffer_len;
989   memcpy(slot->data.buf, ele_buffer, ele_buffer_len * sizeof(*slot->data.buf));
990 }
991 
BMO_slot_buffer_get_single(BMOpSlot * slot)992 void *BMO_slot_buffer_get_single(BMOpSlot *slot)
993 {
994   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
995   BLI_assert(slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE);
996   BLI_assert(slot->len == 0 || slot->len == 1);
997 
998   return slot->len ? (BMHeader *)slot->data.buf[0] : NULL;
999 }
1000 
1001 /**
1002  * Copies the values from another slot to the end of the output slot.
1003  */
_bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],const char * slot_name_dst,BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],const char * slot_name_src,struct MemArena * arena_dst)1004 void _bmo_slot_buffer_append(BMOpSlot slot_args_dst[BMO_OP_MAX_SLOTS],
1005                              const char *slot_name_dst,
1006                              BMOpSlot slot_args_src[BMO_OP_MAX_SLOTS],
1007                              const char *slot_name_src,
1008                              struct MemArena *arena_dst)
1009 {
1010   BMOpSlot *slot_dst = BMO_slot_get(slot_args_dst, slot_name_dst);
1011   BMOpSlot *slot_src = BMO_slot_get(slot_args_src, slot_name_src);
1012 
1013   BLI_assert(slot_dst->slot_type == BMO_OP_SLOT_ELEMENT_BUF &&
1014              slot_src->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1015 
1016   if (slot_dst->len == 0) {
1017     /* output slot is empty, copy rather than append */
1018     _bmo_slot_copy(slot_args_src, slot_name_src, slot_args_dst, slot_name_dst, arena_dst);
1019   }
1020   else if (slot_src->len != 0) {
1021     int elem_size = BMO_OPSLOT_TYPEINFO[slot_dst->slot_type];
1022     int alloc_size = elem_size * (slot_dst->len + slot_src->len);
1023     /* allocate new buffer */
1024     void *buf = BLI_memarena_alloc(arena_dst, alloc_size);
1025 
1026     /* copy slot data */
1027     memcpy(buf, slot_dst->data.buf, elem_size * slot_dst->len);
1028     memcpy(
1029         ((char *)buf) + elem_size * slot_dst->len, slot_src->data.buf, elem_size * slot_src->len);
1030 
1031     slot_dst->data.buf = buf;
1032     slot_dst->len += slot_src->len;
1033   }
1034 }
1035 
1036 /**
1037  * \brief BMO_FLAG_TO_SLOT
1038  *
1039  * Copies elements of a certain type, which have a certain flag set
1040  * into an output slot for an operator.
1041  */
bmo_slot_buffer_from_flag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag,const bool test_for_enabled)1042 static void bmo_slot_buffer_from_flag(BMesh *bm,
1043                                       BMOperator *op,
1044                                       BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1045                                       const char *slot_name,
1046                                       const char htype,
1047                                       const short oflag,
1048                                       const bool test_for_enabled)
1049 {
1050   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1051   int totelement, i = 0;
1052 
1053   BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args);
1054 
1055   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1056   BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1057   BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
1058 
1059   if (test_for_enabled) {
1060     totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
1061   }
1062   else {
1063     totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
1064   }
1065 
1066   if (totelement) {
1067     BMIter iter;
1068     BMHeader *ele;
1069     BMHeader **ele_array;
1070 
1071     BMO_slot_buffer_alloc(op, slot_args, slot_name, totelement);
1072 
1073     ele_array = (BMHeader **)slot->data.buf;
1074 
1075     /* TODO - collapse these loops into one */
1076 
1077     if (htype & BM_VERT) {
1078       BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
1079         if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) {
1080           ele_array[i] = ele;
1081           i++;
1082         }
1083       }
1084     }
1085 
1086     if (htype & BM_EDGE) {
1087       BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
1088         if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) {
1089           ele_array[i] = ele;
1090           i++;
1091         }
1092       }
1093     }
1094 
1095     if (htype & BM_FACE) {
1096       BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
1097         if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) {
1098           ele_array[i] = ele;
1099           i++;
1100         }
1101       }
1102     }
1103   }
1104   else {
1105     slot->len = 0;
1106   }
1107 }
1108 
BMO_slot_buffer_from_enabled_flag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag)1109 void BMO_slot_buffer_from_enabled_flag(BMesh *bm,
1110                                        BMOperator *op,
1111                                        BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1112                                        const char *slot_name,
1113                                        const char htype,
1114                                        const short oflag)
1115 {
1116   bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, true);
1117 }
1118 
BMO_slot_buffer_from_disabled_flag(BMesh * bm,BMOperator * op,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag)1119 void BMO_slot_buffer_from_disabled_flag(BMesh *bm,
1120                                         BMOperator *op,
1121                                         BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1122                                         const char *slot_name,
1123                                         const char htype,
1124                                         const short oflag)
1125 {
1126   bmo_slot_buffer_from_flag(bm, op, slot_args, slot_name, htype, oflag, false);
1127 }
1128 
1129 /**
1130  * \brief BMO_FLAG_BUFFER
1131  *
1132  * Header Flags elements in a slots buffer, automatically
1133  * using the selection API where appropriate.
1134  */
BMO_slot_buffer_hflag_enable(BMesh * bm,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const char hflag,const bool do_flush)1135 void BMO_slot_buffer_hflag_enable(BMesh *bm,
1136                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1137                                   const char *slot_name,
1138                                   const char htype,
1139                                   const char hflag,
1140                                   const bool do_flush)
1141 {
1142   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1143   BMElem **data = (BMElem **)slot->data.buf;
1144   int i;
1145   const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1146   const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1147 
1148   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1149   BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1150   BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
1151 
1152   for (i = 0; i < slot->len; i++, data++) {
1153     if (!(htype & (*data)->head.htype)) {
1154       continue;
1155     }
1156 
1157     if (do_flush_select) {
1158       BM_elem_select_set(bm, *data, true);
1159     }
1160 
1161     if (do_flush_hide) {
1162       BM_elem_hide_set(bm, *data, false);
1163     }
1164 
1165     BM_elem_flag_enable(*data, hflag);
1166   }
1167 }
1168 
1169 /**
1170  * \brief BMO_FLAG_BUFFER
1171  *
1172  * Removes flags from elements in a slots buffer, automatically
1173  * using the selection API where appropriate.
1174  */
BMO_slot_buffer_hflag_disable(BMesh * bm,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const char hflag,const bool do_flush)1175 void BMO_slot_buffer_hflag_disable(BMesh *bm,
1176                                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1177                                    const char *slot_name,
1178                                    const char htype,
1179                                    const char hflag,
1180                                    const bool do_flush)
1181 {
1182   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1183   BMElem **data = (BMElem **)slot->data.buf;
1184   int i;
1185   const bool do_flush_select = (do_flush && (hflag & BM_ELEM_SELECT));
1186   const bool do_flush_hide = (do_flush && (hflag & BM_ELEM_HIDDEN));
1187 
1188   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1189   BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1190 
1191   for (i = 0; i < slot->len; i++, data++) {
1192     if (!(htype & (*data)->head.htype)) {
1193       continue;
1194     }
1195 
1196     if (do_flush_select) {
1197       BM_elem_select_set(bm, *data, false);
1198     }
1199 
1200     if (do_flush_hide) {
1201       BM_elem_hide_set(bm, *data, false);
1202     }
1203 
1204     BM_elem_flag_disable(*data, hflag);
1205   }
1206 }
1207 
1208 /**
1209  * \brief BMO_FLAG_BUFFER
1210  *
1211  * Flags elements in a slots buffer
1212  */
BMO_slot_buffer_flag_enable(BMesh * bm,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag)1213 void BMO_slot_buffer_flag_enable(BMesh *bm,
1214                                  BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1215                                  const char *slot_name,
1216                                  const char htype,
1217                                  const short oflag)
1218 {
1219   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1220   BMHeader **data = slot->data.p;
1221   int i;
1222 
1223   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1224   BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1225 
1226   for (i = 0; i < slot->len; i++) {
1227     if (!(htype & data[i]->htype)) {
1228       continue;
1229     }
1230 
1231     BMO_elem_flag_enable(bm, (BMElemF *)data[i], oflag);
1232   }
1233 }
1234 
1235 /**
1236  * \brief BMO_FLAG_BUFFER
1237  *
1238  * Removes flags from elements in a slots buffer
1239  */
BMO_slot_buffer_flag_disable(BMesh * bm,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char htype,const short oflag)1240 void BMO_slot_buffer_flag_disable(BMesh *bm,
1241                                   BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1242                                   const char *slot_name,
1243                                   const char htype,
1244                                   const short oflag)
1245 {
1246   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1247   BMHeader **data = (BMHeader **)slot->data.buf;
1248   int i;
1249 
1250   BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
1251   BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
1252 
1253   for (i = 0; i < slot->len; i++) {
1254     if (!(htype & data[i]->htype)) {
1255       continue;
1256     }
1257 
1258     BMO_elem_flag_disable(bm, (BMElemF *)data[i], oflag);
1259   }
1260 }
1261 
1262 /**
1263  * \brief ALLOC/FREE FLAG LAYER
1264  *
1265  * Used by operator stack to free/allocate
1266  * private flag data. This is allocated
1267  * using a mempool so the allocation/frees
1268  * should be quite fast.
1269  *
1270  * BMESH_TODO:
1271  * Investigate not freeing flag layers until
1272  * all operators have been executed. This would
1273  * save a lot of realloc potentially.
1274  */
bmo_flag_layer_alloc(BMesh * bm)1275 static void bmo_flag_layer_alloc(BMesh *bm)
1276 {
1277   /* set the index values since we are looping over all data anyway,
1278    * may save time later on */
1279 
1280   BLI_mempool *voldpool = bm->vtoolflagpool; /* old flag pool */
1281   BLI_mempool *eoldpool = bm->etoolflagpool; /* old flag pool */
1282   BLI_mempool *foldpool = bm->ftoolflagpool; /* old flag pool */
1283 
1284   /* store memcpy size for reuse */
1285   const size_t old_totflags_size = (bm->totflags * sizeof(BMFlagLayer));
1286 
1287   bm->totflags++;
1288 
1289   bm->vtoolflagpool = BLI_mempool_create(
1290       sizeof(BMFlagLayer) * bm->totflags, bm->totvert, 512, BLI_MEMPOOL_NOP);
1291   bm->etoolflagpool = BLI_mempool_create(
1292       sizeof(BMFlagLayer) * bm->totflags, bm->totedge, 512, BLI_MEMPOOL_NOP);
1293   bm->ftoolflagpool = BLI_mempool_create(
1294       sizeof(BMFlagLayer) * bm->totflags, bm->totface, 512, BLI_MEMPOOL_NOP);
1295 
1296   /* now go through and memcpy all the flags. Loops don't get a flag layer at this time.. */
1297   BMIter iter;
1298   int i;
1299 
1300   BMVert_OFlag *v_oflag;
1301   BLI_mempool *newpool = bm->vtoolflagpool;
1302   BM_ITER_MESH_INDEX (v_oflag, &iter, bm, BM_VERTS_OF_MESH, i) {
1303     void *oldflags = v_oflag->oflags;
1304     v_oflag->oflags = BLI_mempool_calloc(newpool);
1305     memcpy(v_oflag->oflags, oldflags, old_totflags_size);
1306     BM_elem_index_set(&v_oflag->base, i); /* set_inline */
1307     BM_ELEM_API_FLAG_CLEAR((BMElemF *)v_oflag);
1308   }
1309 
1310   BMEdge_OFlag *e_oflag;
1311   newpool = bm->etoolflagpool;
1312   BM_ITER_MESH_INDEX (e_oflag, &iter, bm, BM_EDGES_OF_MESH, i) {
1313     void *oldflags = e_oflag->oflags;
1314     e_oflag->oflags = BLI_mempool_calloc(newpool);
1315     memcpy(e_oflag->oflags, oldflags, old_totflags_size);
1316     BM_elem_index_set(&e_oflag->base, i); /* set_inline */
1317     BM_ELEM_API_FLAG_CLEAR((BMElemF *)e_oflag);
1318   }
1319 
1320   BMFace_OFlag *f_oflag;
1321   newpool = bm->ftoolflagpool;
1322   BM_ITER_MESH_INDEX (f_oflag, &iter, bm, BM_FACES_OF_MESH, i) {
1323     void *oldflags = f_oflag->oflags;
1324     f_oflag->oflags = BLI_mempool_calloc(newpool);
1325     memcpy(f_oflag->oflags, oldflags, old_totflags_size);
1326     BM_elem_index_set(&f_oflag->base, i); /* set_inline */
1327     BM_ELEM_API_FLAG_CLEAR((BMElemF *)f_oflag);
1328   }
1329 
1330   BLI_mempool_destroy(voldpool);
1331   BLI_mempool_destroy(eoldpool);
1332   BLI_mempool_destroy(foldpool);
1333 
1334   bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1335 }
1336 
bmo_flag_layer_free(BMesh * bm)1337 static void bmo_flag_layer_free(BMesh *bm)
1338 {
1339   /* set the index values since we are looping over all data anyway,
1340    * may save time later on */
1341 
1342   BLI_mempool *voldpool = bm->vtoolflagpool;
1343   BLI_mempool *eoldpool = bm->etoolflagpool;
1344   BLI_mempool *foldpool = bm->ftoolflagpool;
1345 
1346   /* store memcpy size for reuse */
1347   const size_t new_totflags_size = ((bm->totflags - 1) * sizeof(BMFlagLayer));
1348 
1349   /* de-increment the totflags first.. */
1350   bm->totflags--;
1351 
1352   bm->vtoolflagpool = BLI_mempool_create(new_totflags_size, bm->totvert, 512, BLI_MEMPOOL_NOP);
1353   bm->etoolflagpool = BLI_mempool_create(new_totflags_size, bm->totedge, 512, BLI_MEMPOOL_NOP);
1354   bm->ftoolflagpool = BLI_mempool_create(new_totflags_size, bm->totface, 512, BLI_MEMPOOL_NOP);
1355 
1356   /* now go through and memcpy all the flag */
1357   BMIter iter;
1358   int i;
1359 
1360   BMVert_OFlag *v_oflag;
1361   BLI_mempool *newpool = bm->vtoolflagpool;
1362   BM_ITER_MESH_INDEX (v_oflag, &iter, bm, BM_VERTS_OF_MESH, i) {
1363     void *oldflags = v_oflag->oflags;
1364     v_oflag->oflags = BLI_mempool_alloc(newpool);
1365     memcpy(v_oflag->oflags, oldflags, new_totflags_size);
1366     BM_elem_index_set(&v_oflag->base, i); /* set_inline */
1367     BM_ELEM_API_FLAG_CLEAR((BMElemF *)v_oflag);
1368   }
1369 
1370   BMEdge_OFlag *e_oflag;
1371   newpool = bm->etoolflagpool;
1372   BM_ITER_MESH_INDEX (e_oflag, &iter, bm, BM_EDGES_OF_MESH, i) {
1373     void *oldflags = e_oflag->oflags;
1374     e_oflag->oflags = BLI_mempool_alloc(newpool);
1375     memcpy(e_oflag->oflags, oldflags, new_totflags_size);
1376     BM_elem_index_set(&e_oflag->base, i); /* set_inline */
1377     BM_ELEM_API_FLAG_CLEAR((BMElemF *)e_oflag);
1378   }
1379 
1380   BMFace_OFlag *f_oflag;
1381   newpool = bm->ftoolflagpool;
1382   BM_ITER_MESH_INDEX (f_oflag, &iter, bm, BM_FACES_OF_MESH, i) {
1383     void *oldflags = f_oflag->oflags;
1384     f_oflag->oflags = BLI_mempool_alloc(newpool);
1385     memcpy(f_oflag->oflags, oldflags, new_totflags_size);
1386     BM_elem_index_set(&f_oflag->base, i); /* set_inline */
1387     BM_ELEM_API_FLAG_CLEAR((BMElemF *)f_oflag);
1388   }
1389 
1390   BLI_mempool_destroy(voldpool);
1391   BLI_mempool_destroy(eoldpool);
1392   BLI_mempool_destroy(foldpool);
1393 
1394   bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1395 }
1396 
bmo_flag_layer_clear(BMesh * bm)1397 static void bmo_flag_layer_clear(BMesh *bm)
1398 {
1399   /* set the index values since we are looping over all data anyway,
1400    * may save time later on */
1401   const BMFlagLayer zero_flag = {0};
1402 
1403   const int totflags_offset = bm->totflags - 1;
1404 
1405   /* now go through and memcpy all the flag */
1406   {
1407     BMIter iter;
1408     BMVert_OFlag *ele;
1409     int i;
1410     BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) {
1411       ele->oflags[totflags_offset] = zero_flag;
1412       BM_elem_index_set(&ele->base, i); /* set_inline */
1413     }
1414   }
1415   {
1416     BMIter iter;
1417     BMEdge_OFlag *ele;
1418     int i;
1419     BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) {
1420       ele->oflags[totflags_offset] = zero_flag;
1421       BM_elem_index_set(&ele->base, i); /* set_inline */
1422     }
1423   }
1424   {
1425     BMIter iter;
1426     BMFace_OFlag *ele;
1427     int i;
1428     BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) {
1429       ele->oflags[totflags_offset] = zero_flag;
1430       BM_elem_index_set(&ele->base, i); /* set_inline */
1431     }
1432   }
1433 
1434   bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
1435 }
1436 
BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name)1437 void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
1438 {
1439   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1440 
1441   if (slot->slot_type != BMO_OP_SLOT_ELEMENT_BUF) {
1442     return NULL;
1443   }
1444 
1445   return slot->data.buf ? *slot->data.buf : NULL;
1446 }
1447 
1448 /**
1449  * \brief New Iterator
1450  *
1451  * \param restrictmask: restricts the iteration to certain element types
1452  * (e.g. combination of BM_VERT, BM_EDGE, BM_FACE), if iterating
1453  * over an element buffer (not a mapping). */
BMO_iter_new(BMOIter * iter,BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * slot_name,const char restrictmask)1454 void *BMO_iter_new(BMOIter *iter,
1455                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS],
1456                    const char *slot_name,
1457                    const char restrictmask)
1458 {
1459   BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
1460 
1461   memset(iter, 0, sizeof(BMOIter));
1462 
1463   iter->slot = slot;
1464   iter->cur = 0;
1465   iter->restrictmask = restrictmask;
1466 
1467   if (iter->slot->slot_type == BMO_OP_SLOT_MAPPING) {
1468     BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
1469   }
1470   else if (iter->slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1471     BLI_assert(restrictmask & slot->slot_subtype.elem);
1472   }
1473   else {
1474     BLI_assert(0);
1475   }
1476 
1477   return BMO_iter_step(iter);
1478 }
1479 
BMO_iter_step(BMOIter * iter)1480 void *BMO_iter_step(BMOIter *iter)
1481 {
1482   BMOpSlot *slot = iter->slot;
1483   if (slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF) {
1484     BMHeader *ele;
1485 
1486     if (iter->cur >= slot->len) {
1487       return NULL;
1488     }
1489 
1490     ele = slot->data.buf[iter->cur++];
1491     while (!(iter->restrictmask & ele->htype)) {
1492       if (iter->cur >= slot->len) {
1493         return NULL;
1494       }
1495 
1496       ele = slot->data.buf[iter->cur++];
1497       BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1498     }
1499 
1500     BLI_assert((ele == NULL) || (slot->slot_subtype.elem & ele->htype));
1501 
1502     return ele;
1503   }
1504   if (slot->slot_type == BMO_OP_SLOT_MAPPING) {
1505     void *ret;
1506 
1507     if (BLI_ghashIterator_done(&iter->giter) == false) {
1508       ret = BLI_ghashIterator_getKey(&iter->giter);
1509       iter->val = BLI_ghashIterator_getValue_p(&iter->giter);
1510 
1511       BLI_ghashIterator_step(&iter->giter);
1512     }
1513     else {
1514       ret = NULL;
1515       iter->val = NULL;
1516     }
1517 
1518     return ret;
1519   }
1520   BLI_assert(0);
1521 
1522   return NULL;
1523 }
1524 
1525 /* used for iterating over mappings */
1526 
1527 /**
1528  * Returns a pointer to the key-value when iterating over mappings.
1529  * remember for pointer maps this will be a pointer to a pointer.
1530  */
BMO_iter_map_value_p(BMOIter * iter)1531 void **BMO_iter_map_value_p(BMOIter *iter)
1532 {
1533   return iter->val;
1534 }
1535 
BMO_iter_map_value_ptr(BMOIter * iter)1536 void *BMO_iter_map_value_ptr(BMOIter *iter)
1537 {
1538   BLI_assert(ELEM(iter->slot->slot_subtype.map,
1539                   BMO_OP_SLOT_SUBTYPE_MAP_ELEM,
1540                   BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL));
1541   return iter->val ? *iter->val : NULL;
1542 }
1543 
BMO_iter_map_value_float(BMOIter * iter)1544 float BMO_iter_map_value_float(BMOIter *iter)
1545 {
1546   BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_FLT);
1547   return **((float **)iter->val);
1548 }
1549 
BMO_iter_map_value_int(BMOIter * iter)1550 int BMO_iter_map_value_int(BMOIter *iter)
1551 {
1552   BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_INT);
1553   return **((int **)iter->val);
1554 }
1555 
BMO_iter_map_value_bool(BMOIter * iter)1556 bool BMO_iter_map_value_bool(BMOIter *iter)
1557 {
1558   BLI_assert(iter->slot->slot_subtype.map == BMO_OP_SLOT_SUBTYPE_MAP_BOOL);
1559   return **((bool **)iter->val);
1560 }
1561 
1562 /* error system */
1563 typedef struct BMOpError {
1564   struct BMOpError *next, *prev;
1565   int errorcode;
1566   BMOperator *op;
1567   const char *msg;
1568 } BMOpError;
1569 
BMO_error_clear(BMesh * bm)1570 void BMO_error_clear(BMesh *bm)
1571 {
1572   while (BMO_error_pop(bm, NULL, NULL)) {
1573     /* pass */
1574   }
1575 }
1576 
BMO_error_raise(BMesh * bm,BMOperator * owner,int errcode,const char * msg)1577 void BMO_error_raise(BMesh *bm, BMOperator *owner, int errcode, const char *msg)
1578 {
1579   BMOpError *err = MEM_callocN(sizeof(BMOpError), "bmop_error");
1580 
1581   err->errorcode = errcode;
1582   if (!msg) {
1583     msg = bmo_error_messages[errcode];
1584   }
1585   err->msg = msg;
1586   err->op = owner;
1587 
1588   BLI_addhead(&bm->errorstack, err);
1589 }
1590 
BMO_error_occurred(BMesh * bm)1591 bool BMO_error_occurred(BMesh *bm)
1592 {
1593   return (BLI_listbase_is_empty(&bm->errorstack) == false);
1594 }
1595 
1596 /* returns error code or 0 if no error */
BMO_error_get(BMesh * bm,const char ** msg,BMOperator ** op)1597 int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
1598 {
1599   BMOpError *err = bm->errorstack.first;
1600   if (!err) {
1601     return 0;
1602   }
1603 
1604   if (msg) {
1605     *msg = err->msg;
1606   }
1607   if (op) {
1608     *op = err->op;
1609   }
1610 
1611   return err->errorcode;
1612 }
1613 
BMO_error_pop(BMesh * bm,const char ** msg,BMOperator ** op)1614 int BMO_error_pop(BMesh *bm, const char **msg, BMOperator **op)
1615 {
1616   int errorcode = BMO_error_get(bm, msg, op);
1617 
1618   if (errorcode) {
1619     BMOpError *err = bm->errorstack.first;
1620 
1621     BLI_remlink(&bm->errorstack, bm->errorstack.first);
1622     MEM_freeN(err);
1623   }
1624 
1625   return errorcode;
1626 }
1627 
1628 #define NEXT_CHAR(fmt) ((fmt)[0] != 0 ? (fmt)[1] : 0)
1629 
bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * identifier)1630 static int bmo_name_to_slotcode(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1631 {
1632   int i = 0;
1633 
1634   while (slot_args->slot_name) {
1635     if (STREQLEN(identifier, slot_args->slot_name, MAX_SLOTNAME)) {
1636       return i;
1637     }
1638     slot_args++;
1639     i++;
1640   }
1641 
1642   return -1;
1643 }
1644 
bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS],const char * identifier)1645 static int bmo_name_to_slotcode_check(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
1646 {
1647   int i = bmo_name_to_slotcode(slot_args, identifier);
1648   if (i < 0) {
1649     fprintf(stderr,
1650             "%s: ! could not find bmesh slot for name %s! (bmesh internal error)\n",
1651             __func__,
1652             identifier);
1653   }
1654 
1655   return i;
1656 }
1657 
BMO_opcode_from_opname(const char * opname)1658 int BMO_opcode_from_opname(const char *opname)
1659 {
1660 
1661   const uint tot = bmo_opdefines_total;
1662   uint i;
1663   for (i = 0; i < tot; i++) {
1664     if (STREQ(bmo_opdefines[i]->opname, opname)) {
1665       return i;
1666     }
1667   }
1668   return -1;
1669 }
1670 
BMO_opcode_from_opname_check(const char * opname)1671 static int BMO_opcode_from_opname_check(const char *opname)
1672 {
1673   int i = BMO_opcode_from_opname(opname);
1674   if (i == -1) {
1675     fprintf(stderr,
1676             "%s: could not find bmesh slot for name %s! (bmesh internal error)\n",
1677             __func__,
1678             opname);
1679   }
1680   return i;
1681 }
1682 
1683 /**
1684  * \brief Format Strings for #BMOperator Initialization.
1685  *
1686  * This system is used to execute or initialize an operator,
1687  * using a formatted-string system.
1688  *
1689  * The basic format for the format string is:
1690  * `[operatorname] [slot_name]=%[code] [slot_name]=%[code]`
1691  *
1692  * Example:
1693  *
1694  * \code{.c}
1695  *     BMO_op_callf(bm, BMO_FLAG_DEFAULTS,
1696  *                  "delete context=%i geom=%hv",
1697  *                  DEL_ONLYFACES, BM_ELEM_SELECT);
1698  * \endcode
1699  * **Primitive Types**
1700  * - `b` - boolean (same as int but 1/0 only). #BMO_OP_SLOT_BOOL
1701  * - `i` - int. #BMO_OP_SLOT_INT
1702  * - `f` - float. #BMO_OP_SLOT_FLT
1703  * - `p` - pointer (normally to a Scene/Mesh/Object/BMesh). #BMO_OP_SLOT_PTR
1704  * - `m3` - 3x3 matrix of floats. #BMO_OP_SLOT_MAT
1705  * - `m4` - 4x4 matrix of floats. #BMO_OP_SLOT_MAT
1706  * - `v` - 3D vector of floats. #BMO_OP_SLOT_VEC
1707  * **Utility**
1708  *
1709  * Pass an existing slot which is copied to either an input or output slot.
1710  * Taking the operator and slot-name pair of args (BMOperator *, const char *).
1711  * - `s` - slot_in (lower case)
1712  * - `S` - slot_out (upper case)
1713  * **Element Buffer** (#BMO_OP_SLOT_ELEMENT_BUF)
1714  * - `e` - single element vert/edge/face (use with #BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE).
1715  * - `eb` - elem buffer, take an array and a length.
1716  * - `av` - all verts
1717  * - `ae` - all edges
1718  * - `af` - all faces
1719  * - `hv` - header flagged verts (hflag)
1720  * - `he` - header flagged edges (hflag)
1721  * - `hf` - header flagged faces (hflag)
1722  * - `Hv` - header flagged verts (hflag off)
1723  * - `He` - header flagged edges (hflag off)
1724  * - `Hf` - header flagged faces (hflag off)
1725  * - `fv` - flagged verts (oflag)
1726  * - `fe` - flagged edges (oflag)
1727  * - `ff` - flagged faces (oflag)
1728  * - `Fv` - flagged verts (oflag off)
1729  * - `Fe` - flagged edges (oflag off)
1730  * - `Ff` - flagged faces (oflag off)
1731  *
1732  * \note The common v/e/f suffix can be mixed,
1733  * so `avef` is can be used for all verts, edges and faces.
1734  * Order is not important so `Hfev` is also valid (all un-flagged verts, edges and faces).
1735  */
1736 
BMO_op_vinitf(BMesh * bm,BMOperator * op,const int flag,const char * _fmt,va_list vlist)1737 bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt, va_list vlist)
1738 {
1739   //  BMOpDefine *def;
1740   char *opname, *ofmt, *fmt;
1741   char slot_name[64] = {0};
1742   int i, type;
1743   bool noslot, state;
1744 
1745   /* basic useful info to help find where bmop formatting strings fail */
1746   const char *err_reason = "Unknown";
1747   int lineno = -1;
1748 
1749 #define GOTO_ERROR(reason) \
1750   { \
1751     err_reason = reason; \
1752     lineno = __LINE__; \
1753     goto error; \
1754   } \
1755   (void)0
1756 
1757   /* we muck around in here, so dup it */
1758   fmt = ofmt = BLI_strdup(_fmt);
1759 
1760   /* find operator name */
1761   i = strcspn(fmt, " ");
1762 
1763   opname = fmt;
1764   noslot = (opname[i] == '\0');
1765   opname[i] = '\0';
1766 
1767   fmt += i + (noslot ? 0 : 1);
1768 
1769   i = BMO_opcode_from_opname_check(opname);
1770 
1771   if (i == -1) {
1772     MEM_freeN(ofmt);
1773     BLI_assert(0);
1774     return false;
1775   }
1776 
1777   BMO_op_init(bm, op, flag, opname);
1778   //  def = bmo_opdefines[i];
1779 
1780   i = 0;
1781   state = true; /* false: not inside slot_code name, true: inside slot_code name */
1782 
1783   while (*fmt) {
1784     if (state) {
1785       /* jump past leading whitespace */
1786       i = strspn(fmt, " ");
1787       fmt += i;
1788 
1789       /* ignore trailing whitespace */
1790       if (!fmt[i]) {
1791         break;
1792       }
1793 
1794       /* find end of slot name, only "slot=%f", can be used */
1795       i = strcspn(fmt, "=");
1796       if (!fmt[i]) {
1797         GOTO_ERROR("could not match end of slot name");
1798       }
1799 
1800       fmt[i] = 0;
1801 
1802       if (bmo_name_to_slotcode_check(op->slots_in, fmt) < 0) {
1803         GOTO_ERROR("name to slot code check failed");
1804       }
1805 
1806       BLI_strncpy(slot_name, fmt, sizeof(slot_name));
1807 
1808       state = false;
1809       fmt += i;
1810     }
1811     else {
1812       switch (*fmt) {
1813         case ' ':
1814         case '=':
1815         case '%':
1816           break;
1817         case 'm': {
1818           int size;
1819           const char c = NEXT_CHAR(fmt);
1820           fmt++;
1821 
1822           if (c == '3') {
1823             size = 3;
1824           }
1825           else if (c == '4') {
1826             size = 4;
1827           }
1828           else {
1829             GOTO_ERROR("matrix size was not 3 or 4");
1830           }
1831 
1832           BMO_slot_mat_set(op, op->slots_in, slot_name, va_arg(vlist, void *), size);
1833           state = true;
1834           break;
1835         }
1836         case 'v': {
1837           BMO_slot_vec_set(op->slots_in, slot_name, va_arg(vlist, float *));
1838           state = true;
1839           break;
1840         }
1841         case 'e': {
1842           BMOpSlot *slot = BMO_slot_get(op->slots_in, slot_name);
1843 
1844           if (NEXT_CHAR(fmt) == 'b') {
1845             BMHeader **ele_buffer = va_arg(vlist, void *);
1846             int ele_buffer_len = va_arg(vlist, int);
1847 
1848             BMO_slot_buffer_from_array(op, slot, ele_buffer, ele_buffer_len);
1849             fmt++;
1850           }
1851           else {
1852             /* single vert/edge/face */
1853             BMHeader *ele = va_arg(vlist, void *);
1854 
1855             BMO_slot_buffer_from_single(op, slot, ele);
1856           }
1857 
1858           state = true;
1859           break;
1860         }
1861         case 's':
1862         case 'S': {
1863           BMOperator *op_other = va_arg(vlist, void *);
1864           const char *slot_name_other = va_arg(vlist, char *);
1865 
1866           if (*fmt == 's') {
1867             BLI_assert(bmo_name_to_slotcode_check(op_other->slots_in, slot_name_other) != -1);
1868             BMO_slot_copy(op_other, slots_in, slot_name_other, op, slots_in, slot_name);
1869           }
1870           else {
1871             BLI_assert(bmo_name_to_slotcode_check(op_other->slots_out, slot_name_other) != -1);
1872             BMO_slot_copy(op_other, slots_out, slot_name_other, op, slots_in, slot_name);
1873           }
1874           state = true;
1875           break;
1876         }
1877         case 'i':
1878           BMO_slot_int_set(op->slots_in, slot_name, va_arg(vlist, int));
1879           state = true;
1880           break;
1881         case 'b':
1882           BMO_slot_bool_set(op->slots_in, slot_name, va_arg(vlist, int));
1883           state = true;
1884           break;
1885         case 'p':
1886           BMO_slot_ptr_set(op->slots_in, slot_name, va_arg(vlist, void *));
1887           state = true;
1888           break;
1889         case 'f':
1890         case 'F':
1891         case 'h':
1892         case 'H':
1893         case 'a':
1894           type = *fmt;
1895 
1896           if (NEXT_CHAR(fmt) == ' ' || NEXT_CHAR(fmt) == '\0') {
1897             BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double));
1898           }
1899           else {
1900             char htype = 0;
1901 
1902             while (1) {
1903               char htype_set;
1904               const char c = NEXT_CHAR(fmt);
1905               if (c == 'f') {
1906                 htype_set = BM_FACE;
1907               }
1908               else if (c == 'e') {
1909                 htype_set = BM_EDGE;
1910               }
1911               else if (c == 'v') {
1912                 htype_set = BM_VERT;
1913               }
1914               else {
1915                 break;
1916               }
1917 
1918               if (UNLIKELY(htype & htype_set)) {
1919                 GOTO_ERROR("htype duplicated");
1920               }
1921 
1922               htype |= htype_set;
1923               fmt++;
1924             }
1925 
1926             if (type == 'h') {
1927               BMO_slot_buffer_from_enabled_hflag(
1928                   bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1929             }
1930             else if (type == 'H') {
1931               BMO_slot_buffer_from_disabled_hflag(
1932                   bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1933             }
1934             else if (type == 'a') {
1935               if ((op->flag & BMO_FLAG_RESPECT_HIDE) == 0) {
1936                 BMO_slot_buffer_from_all(bm, op, op->slots_in, slot_name, htype);
1937               }
1938               else {
1939                 BMO_slot_buffer_from_disabled_hflag(
1940                     bm, op, op->slots_in, slot_name, htype, BM_ELEM_HIDDEN);
1941               }
1942             }
1943             else if (type == 'f') {
1944               BMO_slot_buffer_from_enabled_flag(
1945                   bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1946             }
1947             else if (type == 'F') {
1948               BMO_slot_buffer_from_disabled_flag(
1949                   bm, op, op->slots_in, slot_name, htype, va_arg(vlist, int));
1950             }
1951           }
1952 
1953           state = true;
1954           break;
1955         default:
1956           fprintf(stderr,
1957                   "%s: unrecognized bmop format char: '%c', %d in '%s'\n",
1958                   __func__,
1959                   *fmt,
1960                   (int)(fmt - ofmt),
1961                   ofmt);
1962           break;
1963       }
1964     }
1965     fmt++;
1966   }
1967 
1968   MEM_freeN(ofmt);
1969   return true;
1970 error:
1971 
1972   /* non urgent todo - explain exactly what is failing */
1973   fprintf(stderr, "%s: error parsing formatting string\n", __func__);
1974 
1975   fprintf(stderr, "string: '%s', position %d\n", _fmt, (int)(fmt - ofmt));
1976   fprintf(stderr, "         ");
1977   {
1978     int pos = (int)(fmt - ofmt);
1979     for (i = 0; i < pos; i++) {
1980       fprintf(stderr, " ");
1981     }
1982     fprintf(stderr, "^\n");
1983   }
1984 
1985   fprintf(stderr, "source code:  %s:%d\n", __FILE__, lineno);
1986 
1987   fprintf(stderr, "reason: %s\n", err_reason);
1988 
1989   MEM_freeN(ofmt);
1990 
1991   BMO_op_finish(bm, op);
1992   return false;
1993 
1994 #undef GOTO_ERROR
1995 }
1996 
BMO_op_initf(BMesh * bm,BMOperator * op,const int flag,const char * fmt,...)1997 bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, ...)
1998 {
1999   va_list list;
2000 
2001   va_start(list, fmt);
2002   if (!BMO_op_vinitf(bm, op, flag, fmt, list)) {
2003     printf("%s: failed\n", __func__);
2004     va_end(list);
2005     return false;
2006   }
2007   va_end(list);
2008 
2009   return true;
2010 }
2011 
BMO_op_callf(BMesh * bm,const int flag,const char * fmt,...)2012 bool BMO_op_callf(BMesh *bm, const int flag, const char *fmt, ...)
2013 {
2014   va_list list;
2015   BMOperator op;
2016 
2017   va_start(list, fmt);
2018   if (!BMO_op_vinitf(bm, &op, flag, fmt, list)) {
2019     printf("%s: failed, format is:\n    \"%s\"\n", __func__, fmt);
2020     va_end(list);
2021     return false;
2022   }
2023 
2024   BMO_op_exec(bm, &op);
2025   BMO_op_finish(bm, &op);
2026 
2027   va_end(list);
2028   return true;
2029 }
2030