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