Blender V5.0
bmesh_py_ops_call.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include <Python.h>
14
15#include "BLI_utildefines.h"
16
18
19#include "bmesh.hh"
20
21#include "bmesh_py_ops_call.hh" /* own include */
22
23#include "bmesh_py_types.hh"
24
26
27BLI_STATIC_ASSERT(sizeof(PyC_FlagSet) == sizeof(BMO_FlagSet), "size mismatch");
28
30{
32 /* NOTE: we could have multiple errors. */
33 const char *errmsg;
34 if (BMO_error_get(bm, &errmsg, nullptr, nullptr)) {
35 PyErr_Format(PyExc_RuntimeError, "bmesh operator: %.200s", errmsg);
37 return -1;
38 }
39 }
40 return 0;
41}
42
52 BMesh *bm,
53 const char htype,
54 /* for error messages */
55 const char *opname,
56 const char *slot_name,
57 const char *descr)
58{
59 if (!BPy_BMElem_Check(value) || !(value->ele->head.htype & htype)) {
60 PyErr_Format(PyExc_TypeError,
61 "%.200s: keyword \"%.200s\" %.200s, expected a %.200s not *.200s",
62 opname,
63 slot_name,
64 descr,
66 Py_TYPE(value)->tp_name);
67 return -1;
68 }
69 if (value->bm == nullptr) {
70 PyErr_Format(PyExc_TypeError,
71 "%.200s: keyword \"%.200s\" %.200s invalidated element",
72 opname,
73 slot_name,
74 descr);
75 return -1;
76 }
77 if (value->bm != bm) { /* we may want to make this check optional by setting 'bm' to nullptr */
78 PyErr_Format(PyExc_TypeError,
79 "%.200s: keyword \"%.200s\" %.200s invalidated element",
80 opname,
81 slot_name,
82 descr);
83 return -1;
84 }
85 return 0;
86}
87
98 BMesh *bm,
99 const char htype_py,
100 const char htype_bmo,
101 /* for error messages */
102 const char *opname,
103 const char *slot_name,
104 const char *descr)
105{
106 if (value->bm == nullptr) {
107 PyErr_Format(PyExc_TypeError,
108 "%.200s: keyword \"%.200s\" %.200s, invalidated sequence",
109 opname,
110 slot_name,
111 descr);
112 return -1;
113 }
114 if (value->bm != bm) { /* we may want to make this check optional by setting 'bm' to nullptr */
115 PyErr_Format(PyExc_TypeError,
116 "%.200s: keyword \"%.200s\" %.200s, invalidated sequence",
117 opname,
118 slot_name,
119 descr);
120 return -1;
121 }
122 if ((htype_py & htype_bmo) == 0) {
123 char str_bmo[32];
124 char str_py[32];
125 PyErr_Format(PyExc_TypeError,
126 "%.200s: keyword \"%.200s\" %.200s, expected "
127 "a sequence of %.200s not %.200s",
128 opname,
129 slot_name,
130 descr,
131 BPy_BMElem_StringFromHType_ex(htype_bmo, str_bmo),
132 BPy_BMElem_StringFromHType_ex(htype_py, str_py));
133 return -1;
134 }
135
136 return 0;
137}
138
143 BMOperator *bmop,
144 BMOpSlot *slot,
145 PyObject *value,
146 /* the are just for exception messages */
147 const char *opname,
148 const char *slot_name)
149{
150 switch (slot->slot_type) {
151 case BMO_OP_SLOT_BOOL: {
152 const int param = PyC_Long_AsBool(value);
153
154 if (param == -1) {
155 PyErr_Format(PyExc_TypeError,
156 "%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s",
157 opname,
158 slot_name,
159 Py_TYPE(value)->tp_name);
160 return -1;
161 }
162
163 BMO_SLOT_AS_BOOL(slot) = param;
164
165 break;
166 }
167 case BMO_OP_SLOT_INT: {
169 int enum_val = -1;
170 PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_data.flags;
171 const char *enum_str = PyUnicode_AsUTF8(value);
172
173 if (enum_str == nullptr) {
174 PyErr_Format(PyExc_TypeError,
175 "%.200s: keyword \"%.200s\" expected a string, not %.200s",
176 opname,
177 slot_name,
178 Py_TYPE(value)->tp_name);
179 return -1;
180 }
181
182 if (PyC_FlagSet_ValueFromID(items, enum_str, &enum_val, slot_name) == -1) {
183 return -1;
184 }
185
186 BMO_SLOT_AS_INT(slot) = enum_val;
187 }
189 int flag = 0;
190 PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_data.flags;
191
192 if (PyC_FlagSet_ToBitfield(items, value, &flag, slot_name) == -1) {
193 return -1;
194 }
195
196 BMO_SLOT_AS_INT(slot) = flag;
197 }
198 else {
199 const int param = PyC_Long_AsI32(value);
200
201 if (param == -1 && PyErr_Occurred()) {
202 PyErr_Format(PyExc_TypeError,
203 "%.200s: keyword \"%.200s\" expected an int, not %.200s",
204 opname,
205 slot_name,
206 Py_TYPE(value)->tp_name);
207 return -1;
208 }
209
210 BMO_SLOT_AS_INT(slot) = param;
211 }
212 break;
213 }
214 case BMO_OP_SLOT_FLT: {
215 const float param = PyFloat_AsDouble(value);
216 if (param == -1 && PyErr_Occurred()) {
217 PyErr_Format(PyExc_TypeError,
218 "%.200s: keyword \"%.200s\" expected a float, not %.200s",
219 opname,
220 slot_name,
221 Py_TYPE(value)->tp_name);
222 return -1;
223 }
224
225 BMO_SLOT_AS_FLOAT(slot) = param;
226
227 break;
228 }
229 case BMO_OP_SLOT_MAT: {
230 /* XXX: BMesh operator design is crappy here, operator slot should define matrix size,
231 * not the caller! */
232 MatrixObject *pymat;
233 if (!Matrix_ParseAny(value, &pymat)) {
234 return -1;
235 }
236 const ushort size = pymat->col_num;
237 if ((size != pymat->row_num) || !ELEM(size, 3, 4)) {
238 PyErr_Format(PyExc_TypeError,
239 "%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix",
240 opname,
241 slot_name);
242 return -1;
243 }
244
245 BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size);
246 break;
247 }
248 case BMO_OP_SLOT_VEC: {
249 /* passing slot name here is a bit non-descriptive */
250 if (mathutils_array_parse(BMO_SLOT_AS_VECTOR(slot), 3, 3, value, slot_name) == -1) {
251 return -1;
252 }
253 break;
254 }
258 bm,
260 opname,
261 slot_name,
262 "single element") == -1)
263 {
264 return -1; /* error is set in bpy_slot_from_py_elem_check() */
265 }
266
267 BMO_slot_buffer_from_single(bmop, slot, &((BPy_BMElem *)value)->ele->head);
268 }
269 else {
270 /* there are many ways we could interpret arguments, for now...
271 * - verts/edges/faces from the mesh direct,
272 * this way the operator takes every item.
273 * - `TODO` a plain python sequence (list) of elements.
274 * - `TODO` an iterator. eg.
275 * face.verts
276 * - `TODO` (type, flag) pair, eg.
277 * ('VERT', {'TAG'})
278 */
279
280 if (BPy_BMVertSeq_Check(value)) {
282 bm,
283 BM_VERT,
285 opname,
286 slot_name,
287 "element buffer") == -1)
288 {
289 return -1; /* error is set in bpy_slot_from_py_elem_check() */
290 }
291
292 BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_VERT);
293 }
294 else if (BPy_BMEdgeSeq_Check(value)) {
296 bm,
297 BM_EDGE,
299 opname,
300 slot_name,
301 "element buffer") == -1)
302 {
303 return -1; /* error is set in bpy_slot_from_py_elem_check() */
304 }
305
306 BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_EDGE);
307 }
308 else if (BPy_BMFaceSeq_Check(value)) {
310 bm,
311 BM_FACE,
313 opname,
314 slot_name,
315 "element buffer") == -1)
316 {
317 return -1; /* error is set in bpy_slot_from_py_elem_check() */
318 }
319 BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_FACE);
320 }
321
322 else if (BPy_BMElemSeq_Check(value)) {
323 BMIter iter;
324 BMHeader *ele;
325 int tot;
326 uint i;
327
329 (BPy_BMGeneric *)value,
330 bm,
333 opname,
334 slot_name,
335 "element buffer") == -1)
336 {
337 return -1; /* error is set in bpy_slot_from_py_elem_check() */
338 }
339
340 /* this will loop over all elements which is a shame but
341 * we need to know this before alloc */
342 /* calls bpy_bmelemseq_length() */
343 tot = Py_TYPE(value)->tp_as_sequence->sq_length(value);
344
345 BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, tot);
346
347 i = 0;
348 BM_ITER_BPY_BM_SEQ (ele, &iter, ((BPy_BMElemSeq *)value)) {
349 slot->data.buf[i] = ele;
350 i++;
351 }
352 }
353 /* keep this last */
354 else if (PySequence_Check(value)) {
355 BMElem **elem_array = nullptr;
356 Py_ssize_t elem_array_len;
357
358 elem_array = static_cast<BMElem **>(
360 value,
361 0,
362 PY_SSIZE_T_MAX,
363 &elem_array_len,
365 true,
366 true,
367 slot_name));
368
369 /* error is set above */
370 if (elem_array == nullptr) {
371 return -1;
372 }
373
374 BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, elem_array_len);
375 memcpy(slot->data.buf, elem_array, sizeof(void *) * elem_array_len);
376 PyMem_FREE(elem_array);
377 }
378 else {
379 PyErr_Format(PyExc_TypeError,
380 "%.200s: keyword \"%.200s\" expected "
381 "a bmesh sequence, list, (htype, flag) pair, not %.200s",
382 opname,
383 slot_name,
384 Py_TYPE(value)->tp_name);
385 return -1;
386 }
387 }
388 break;
389 }
390 case BMO_OP_SLOT_MAPPING: {
391 /* first check types */
393 if (!PyDict_Check(value)) {
394 PyErr_Format(PyExc_TypeError,
395 "%.200s: keyword \"%.200s\" expected "
396 "a dict, not %.200s",
397 opname,
398 slot_name,
399 Py_TYPE(value)->tp_name);
400 return -1;
401 }
402 }
403 else {
404 if (!PySet_Check(value)) {
405 PyErr_Format(PyExc_TypeError,
406 "%.200s: keyword \"%.200s\" expected "
407 "a set, not %.200s",
408 opname,
409 slot_name,
410 Py_TYPE(value)->tp_name);
411 return -1;
412 }
413 }
414
415 switch (slot->slot_subtype.map) {
417 if (PyDict_Size(value) > 0) {
418 PyObject *arg_key, *arg_value;
419 Py_ssize_t arg_pos = 0;
420 while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
422 bm,
424 opname,
425 slot_name,
426 "invalid key in dict") == -1)
427 {
428 return -1; /* error is set in bpy_slot_from_py_elem_check() */
429 }
430
432 bm,
434 opname,
435 slot_name,
436 "invalid value in dict") == -1)
437 {
438 return -1; /* error is set in bpy_slot_from_py_elem_check() */
439 }
440
442 bmop, slot, ((BPy_BMElem *)arg_key)->ele, ((BPy_BMElem *)arg_value)->ele);
443 }
444 }
445 break;
446 }
448 if (PyDict_Size(value) > 0) {
449 PyObject *arg_key, *arg_value;
450 Py_ssize_t arg_pos = 0;
451 while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
452 float value_f;
453
455 bm,
457 opname,
458 slot_name,
459 "invalid key in dict") == -1)
460 {
461 return -1; /* error is set in bpy_slot_from_py_elem_check() */
462 }
463
464 value_f = PyFloat_AsDouble(arg_value);
465
466 if (value_f == -1.0f && PyErr_Occurred()) {
467 PyErr_Format(PyExc_TypeError,
468 "%.200s: keyword \"%.200s\" expected "
469 "a dict with float values, not %.200s",
470 opname,
471 slot_name,
472 Py_TYPE(arg_value)->tp_name);
473 return -1;
474 }
475
476 BMO_slot_map_float_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_f);
477 }
478 }
479 break;
480 }
482 if (PyDict_Size(value) > 0) {
483 PyObject *arg_key, *arg_value;
484 Py_ssize_t arg_pos = 0;
485 while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
486 int value_i;
487
489 bm,
491 opname,
492 slot_name,
493 "invalid key in dict") == -1)
494 {
495 return -1; /* error is set in bpy_slot_from_py_elem_check() */
496 }
497
498 value_i = PyC_Long_AsI32(arg_value);
499
500 if (value_i == -1 && PyErr_Occurred()) {
501 PyErr_Format(PyExc_TypeError,
502 "%.200s: keyword \"%.200s\" expected "
503 "a dict with int values, not %.200s",
504 opname,
505 slot_name,
506 Py_TYPE(arg_value)->tp_name);
507 return -1;
508 }
509
510 BMO_slot_map_int_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i);
511 }
512 }
513 break;
514 }
516 if (PyDict_Size(value) > 0) {
517 PyObject *arg_key, *arg_value;
518 Py_ssize_t arg_pos = 0;
519 while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
520 int value_i;
521
523 bm,
525 opname,
526 slot_name,
527 "invalid key in dict") == -1)
528 {
529 return -1; /* error is set in bpy_slot_from_py_elem_check() */
530 }
531
532 value_i = PyC_Long_AsI32(arg_value);
533
534 if (value_i == -1 && PyErr_Occurred()) {
535 PyErr_Format(PyExc_TypeError,
536 "%.200s: keyword \"%.200s\" expected "
537 "a dict with bool values, not %.200s",
538 opname,
539 slot_name,
540 Py_TYPE(arg_value)->tp_name);
541 return -1;
542 }
543
544 BMO_slot_map_bool_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i != 0);
545 }
546 }
547 break;
548 }
550 if (PySet_GET_SIZE(value) > 0) {
551 PyObject *it = PyObject_GetIter(value);
552 PyObject *arg_key;
553 while ((arg_key = PyIter_Next(it))) {
554 /* Borrow from the set. */
555 Py_DECREF(arg_key);
556
558 bm,
560 opname,
561 slot_name,
562 "invalid key in set") == -1)
563 {
564 /* Error is set in #bpy_slot_from_py_elem_check(). */
565 break;
566 }
567
568 BMO_slot_map_empty_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele);
569 }
570 Py_DECREF(it);
571 if (arg_key) {
572 return -1;
573 }
574 }
575 break;
576 }
578 /* can't convert from these */
579 PyErr_Format(PyExc_NotImplementedError,
580 "This arguments mapping subtype %d is not supported",
581 slot->slot_subtype.map);
582 return -1;
583 }
584 }
585 break;
586 }
587 default:
588 /* TODO: many others. */
589 PyErr_Format(PyExc_NotImplementedError,
590 "%.200s: keyword \"%.200s\" type %d not working yet!",
591 opname,
592 slot_name,
593 slot->slot_type);
594 return -1;
595 }
596
597 /* all is well */
598 return 0;
599}
600
606static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
607{
608 PyObject *item = nullptr;
609
610 /* keep switch in same order as above */
611 switch (slot->slot_type) {
612 case BMO_OP_SLOT_BOOL:
613 item = PyBool_FromLong(BMO_SLOT_AS_BOOL(slot));
614 break;
615 case BMO_OP_SLOT_INT:
616 item = PyLong_FromLong(BMO_SLOT_AS_INT(slot));
617 break;
618 case BMO_OP_SLOT_FLT:
619 item = PyFloat_FromDouble(double(BMO_SLOT_AS_FLOAT(slot)));
620 break;
621 case BMO_OP_SLOT_MAT:
622 item = Matrix_CreatePyObject((float *)BMO_SLOT_AS_MATRIX(slot), 4, 4, nullptr);
623 break;
624 case BMO_OP_SLOT_VEC:
625 item = Vector_CreatePyObject(BMO_SLOT_AS_VECTOR(slot), slot->len, nullptr);
626 break;
627 case BMO_OP_SLOT_PTR:
628 BLI_assert(0); /* currently we don't have any pointer return values in use */
629 item = Py_NewRef(Py_None);
630 break;
633 BMHeader *ele = static_cast<BMHeader *>(BMO_slot_buffer_get_single(slot));
634 item = ele ? BPy_BMElem_CreatePyObject(bm, ele) : Py_NewRef(Py_None);
635 }
636 else {
637 const int size = slot->len;
638 void **buffer = BMO_SLOT_AS_BUFFER(slot);
639 int j;
640
641 item = PyList_New(size);
642 for (j = 0; j < size; j++) {
643 BMHeader *ele = static_cast<BMHeader *>(buffer[j]);
644 PyList_SET_ITEM(item, j, BPy_BMElem_CreatePyObject(bm, ele));
645 }
646 }
647 break;
648 }
649 case BMO_OP_SLOT_MAPPING: {
650 GHash *slot_hash = BMO_SLOT_AS_GHASH(slot);
651 GHashIterator hash_iter;
652
653 switch (slot->slot_subtype.map) {
655 item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
656 if (slot_hash) {
657 GHASH_ITER (hash_iter, slot_hash) {
658 BMHeader *ele_key = static_cast<BMHeader *>(BLI_ghashIterator_getKey(&hash_iter));
659 void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
660
661 PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
662 PyObject *py_val = BPy_BMElem_CreatePyObject(bm, static_cast<BMHeader *>(ele_val));
663
664 PyDict_SetItem(item, py_key, py_val);
665 Py_DECREF(py_key);
666 Py_DECREF(py_val);
667 }
668 }
669 break;
670 }
672 item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
673 if (slot_hash) {
674 GHASH_ITER (hash_iter, slot_hash) {
675 BMHeader *ele_key = static_cast<BMHeader *>(BLI_ghashIterator_getKey(&hash_iter));
676 void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
677
678 PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
679 PyObject *py_val = PyFloat_FromDouble(*(float *)&ele_val);
680
681 PyDict_SetItem(item, py_key, py_val);
682 Py_DECREF(py_key);
683 Py_DECREF(py_val);
684 }
685 }
686 break;
687 }
689 item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
690 if (slot_hash) {
691 GHASH_ITER (hash_iter, slot_hash) {
692 BMHeader *ele_key = static_cast<BMHeader *>(BLI_ghashIterator_getKey(&hash_iter));
693 void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
694
695 PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
696 PyObject *py_val = PyLong_FromLong(*(int *)&ele_val);
697
698 PyDict_SetItem(item, py_key, py_val);
699 Py_DECREF(py_key);
700 Py_DECREF(py_val);
701 }
702 }
703 break;
704 }
706 item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
707 if (slot_hash) {
708 GHASH_ITER (hash_iter, slot_hash) {
709 BMHeader *ele_key = static_cast<BMHeader *>(BLI_ghashIterator_getKey(&hash_iter));
710 void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
711
712 PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
713 PyObject *py_val = PyBool_FromLong(*(bool *)&ele_val);
714
715 PyDict_SetItem(item, py_key, py_val);
716 Py_DECREF(py_key);
717 Py_DECREF(py_val);
718 }
719 }
720 break;
721 }
723 item = PySet_New(nullptr);
724 if (slot_hash) {
725 GHASH_ITER (hash_iter, slot_hash) {
726 BMHeader *ele_key = static_cast<BMHeader *>(BLI_ghashIterator_getKey(&hash_iter));
727
728 PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
729
730 PySet_Add(item, py_key);
731
732 Py_DECREF(py_key);
733 }
734 }
735 break;
736 }
738 /* can't convert from these */
739 item = Py_NewRef(Py_None);
740 break;
741 }
742 break;
743 }
744 }
745 BLI_assert(item != nullptr);
746
747 return item;
748}
749
750PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
751{
752 PyObject *ret;
753 BPy_BMesh *py_bm;
754 BMesh *bm;
755
756 BMOperator bmop;
757
758 if ((PyTuple_GET_SIZE(args) == 1) && (py_bm = (BPy_BMesh *)PyTuple_GET_ITEM(args, 0)) &&
759 BPy_BMesh_Check(py_bm))
760 {
761 BPY_BM_CHECK_OBJ(py_bm);
762 bm = py_bm->bm;
763
764 if (bm->use_toolflags == false) {
765 PyErr_SetString(PyExc_ValueError, "bmesh created with 'use_operators=False'");
766 return nullptr;
767 }
768
769 /* could complain about entering with exceptions... */
771 }
772 else {
773 PyErr_SetString(PyExc_TypeError,
774 "bmesh operators expect a single BMesh positional argument, all other args "
775 "must be keywords");
776 return nullptr;
777 }
778
779 /* TODO: error check this!, though we do the error check on attribute access. */
780 /* TODO: make flags optional. */
781 BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, self->opname);
782
783 if (kw && PyDict_Size(kw) > 0) {
784 /* Setup properties, see `bpy_rna.cc`: #pyrna_py_to_prop()
785 * which shares this logic for parsing properties. */
786
787 PyObject *key, *value;
788 Py_ssize_t pos = 0;
789 while (PyDict_Next(kw, &pos, &key, &value)) {
790 const char *slot_name = PyUnicode_AsUTF8(key);
791 BMOpSlot *slot;
792
793 if (!BMO_slot_exists(bmop.slots_in, slot_name)) {
794 PyErr_Format(PyExc_TypeError,
795 "%.200s: keyword \"%.200s\" is invalid for this operator",
796 self->opname,
797 slot_name);
798 BMO_op_finish(bm, &bmop);
799 return nullptr;
800 }
801
802 slot = BMO_slot_get(bmop.slots_in, slot_name);
803
804 /* now assign the value */
805 if (bpy_slot_from_py(bm, &bmop, slot, value, self->opname, slot_name) == -1) {
806 BMO_op_finish(bm, &bmop);
807 return nullptr;
808 }
809 }
810 }
811
812 BMO_op_exec(bm, &bmop);
813
814 /* from here until the end of the function, no returns, just set 'ret' */
815 if (UNLIKELY(bpy_bm_op_as_py_error(bm) == -1)) {
816 ret = nullptr; /* exception raised above */
817 }
818 else if (bmop.slots_out[0].slot_name == nullptr) {
819 ret = Py_NewRef(Py_None);
820 }
821 else {
822 /* build return value */
823 int i;
824 ret = PyDict_New();
825
826 for (i = 0; bmop.slots_out[i].slot_name; i++) {
827 // BMOpDefine *op_def = opdefines[bmop.type];
828 // BMOSlotType *slot_type = op_def->slot_types_out[i];
829 BMOpSlot *slot = &bmop.slots_out[i];
830 PyObject *item;
831
832 /* this function doesn't throw exceptions */
833 item = bpy_slot_to_py(bm, slot);
834 if (item == nullptr) {
835 item = Py_NewRef(Py_None);
836 }
837
838#if 1
839 /* Temporary code, strip off `.out` while we keep this convention. */
840 {
841 char slot_name_strip[MAX_SLOTNAME];
842 const char *ch = strchr(slot->slot_name, '.'); /* can't fail! */
843 const int tot = ch - slot->slot_name;
844 BLI_assert(ch != nullptr);
845 memcpy(slot_name_strip, slot->slot_name, tot);
846 slot_name_strip[tot] = '\0';
847 PyDict_SetItemString(ret, slot_name_strip, item);
848 }
849#else
850 PyDict_SetItemString(ret, slot->slot_name, item);
851#endif
852 Py_DECREF(item);
853 }
854 }
855
856 BMO_op_finish(bm, &bmop);
857 return ret;
858}
#define BLI_STATIC_ASSERT(a, msg)
Definition BLI_assert.h:83
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:295
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:318
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:702
unsigned int uint
unsigned short ushort
#define UNLIKELY(x)
#define ELEM(...)
#define BM_ALL_NOLOOP
void BMO_error_clear(BMesh *bm)
@ BMO_ERROR_FATAL
bool BMO_error_occurred_at_level(BMesh *bm, eBMOpErrorLevel level)
void bool BMO_error_get(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
const char bm_iter_itype_htype_map[BM_ITYPE_MAX]
BMesh * bm
BMesh const char itype
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int len)
void * BMO_slot_buffer_get_single(BMOpSlot *slot)
#define BMO_SLOT_AS_VECTOR(slot)
void BMO_slot_mat_set(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const float *mat, int size)
#define BMO_SLOT_AS_FLOAT(slot)
@ BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE
@ BMO_OP_SLOT_ELEMENT_BUF
@ BMO_OP_SLOT_PTR
@ BMO_OP_SLOT_BOOL
@ BMO_OP_SLOT_FLT
@ BMO_OP_SLOT_INT
@ BMO_OP_SLOT_VEC
@ BMO_OP_SLOT_MAPPING
@ BMO_OP_SLOT_MAT
void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
#define MAX_SLOTNAME
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
#define BMO_SLOT_AS_BUFFER(slot)
@ BMO_OP_SLOT_SUBTYPE_MAP_ELEM
@ BMO_OP_SLOT_SUBTYPE_MAP_BOOL
@ BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL
@ BMO_OP_SLOT_SUBTYPE_MAP_INT
@ BMO_OP_SLOT_SUBTYPE_MAP_EMPTY
@ BMO_OP_SLOT_SUBTYPE_MAP_FLT
@ BMO_OP_SLOT_SUBTYPE_INT_FLAG
@ BMO_OP_SLOT_SUBTYPE_INT_ENUM
#define BMO_SLOT_AS_GHASH(slot)
void BMO_op_init(BMesh *bm, BMOperator *op, int flag, const char *opname)
BMESH OPSTACK INIT OP.
#define BMO_SLOT_AS_BOOL(slot)
#define BMO_SLOT_AS_MATRIX(slot)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype)
BMO_ALL_TO_SLOT.
#define BMO_FLAG_DEFAULTS
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK HAS SLOT.
#define BMO_SLOT_AS_INT(slot)
BLI_INLINE void BMO_slot_map_int_insert(BMOperator *op, BMOpSlot *slot, void *element, const int val)
BLI_INLINE void BMO_slot_map_elem_insert(BMOperator *op, BMOpSlot *slot, const void *element, void *val)
BLI_INLINE void BMO_slot_map_float_insert(BMOperator *op, BMOpSlot *slot, void *element, const float val)
BLI_INLINE void BMO_slot_map_empty_insert(BMOperator *op, BMOpSlot *slot, const void *element)
BLI_INLINE void BMO_slot_map_bool_insert(BMOperator *op, BMOpSlot *slot, void *element, const bool val)
PyObject * BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
static int bpy_bm_op_as_py_error(BMesh *bm)
static int bpy_slot_from_py_elemseq_check(BPy_BMGeneric *value, BMesh *bm, const char htype_py, const char htype_bmo, const char *opname, const char *slot_name, const char *descr)
Utility function to check BMVertSeq/BMEdgeSeq/BMFaceSeq's.
static int bpy_slot_from_py_elem_check(BPy_BMElem *value, BMesh *bm, const char htype, const char *opname, const char *slot_name, const char *descr)
Utility function to check BMVert/BMEdge/BMFace's.
static PyObject * bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
static int bpy_slot_from_py(BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObject *value, const char *opname, const char *slot_name)
PyObject * BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
void * BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, const char htype, const bool do_unique_check, const bool do_bm_check, const char *error_prefix)
char * BPy_BMElem_StringFromHType(const char htype)
char * BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
#define BPY_BM_CHECK_OBJ(obj)
#define BPy_BMVertSeq_Check(v)
#define BPy_BMFaceSeq_Check(v)
#define BPy_BMElemSeq_Check(v)
#define BPy_BMElem_Check(v)
#define BPy_BMesh_Check(v)
#define BPy_BMEdgeSeq_Check(v)
#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq)
PyObject * self
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
uint pos
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:96
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
int Matrix_ParseAny(PyObject *o, void *p)
PyObject * Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
int PyC_FlagSet_ValueFromID(const PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix)
int PyC_Long_AsBool(PyObject *value)
int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
Py_DECREF(oname)
return ret
BMHeader head
union BMOpSlot::@313121210037300127305053354046356312170117023254 data
eBMOpSlotSubType_Union slot_subtype
eBMOpSlotType slot_type
BMO_FlagSet * flags
struct BMOpSlot::@313121210037300127305053354046356312170117023254::@263061076130337244124145337307265057223360175210 enum_data
const char * slot_name
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
i
Definition text_draw.cc:230
eBMOpSlotSubType_Int intg
eBMOpSlotSubType_Elem elem
eBMOpSlotSubType_Map map
uint8_t flag
Definition wm_window.cc:145