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