Blender  V3.3
bmesh_py_ops_call.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. All rights reserved. */
3 
12 #include <Python.h>
13 
14 #include "BLI_utildefines.h"
15 
16 #include "../mathutils/mathutils.h"
17 
18 #include "bmesh.h"
19 
20 #include "bmesh_py_ops_call.h" /* own include */
21 
22 #include "bmesh_py_types.h"
23 
24 #include "../generic/py_capi_utils.h"
25 #include "../generic/python_utildefines.h"
26 
27 BLI_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, NULL, NULL)) {
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 == NULL) {
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 NULL */
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 == NULL) {
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 NULL */
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 == NULL) {
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  }
188  else if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
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,
259  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
260  opname,
261  slot_name,
262  "single element") == -1) {
263  return -1; /* error is set in bpy_slot_from_py_elem_check() */
264  }
265 
266  BMO_slot_buffer_from_single(bmop, slot, &((BPy_BMElem *)value)->ele->head);
267  }
268  else {
269  /* there are many ways we could interpret arguments, for now...
270  * - verts/edges/faces from the mesh direct,
271  * this way the operator takes every item.
272  * - `TODO` a plain python sequence (list) of elements.
273  * - `TODO` an iterator. eg.
274  * face.verts
275  * - `TODO` (type, flag) pair, eg.
276  * ('VERT', {'TAG'})
277  */
278 
279  if (BPy_BMVertSeq_Check(value)) {
281  bm,
282  BM_VERT,
283  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
284  opname,
285  slot_name,
286  "element buffer") == -1) {
287  return -1; /* error is set in bpy_slot_from_py_elem_check() */
288  }
289 
290  BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_VERT);
291  }
292  else if (BPy_BMEdgeSeq_Check(value)) {
294  bm,
295  BM_EDGE,
296  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
297  opname,
298  slot_name,
299  "element buffer") == -1) {
300  return -1; /* error is set in bpy_slot_from_py_elem_check() */
301  }
302 
303  BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_EDGE);
304  }
305  else if (BPy_BMFaceSeq_Check(value)) {
307  bm,
308  BM_FACE,
309  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
310  opname,
311  slot_name,
312  "element buffer") == -1) {
313  return -1; /* error is set in bpy_slot_from_py_elem_check() */
314  }
315  BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_FACE);
316  }
317 
318  else if (BPy_BMElemSeq_Check(value)) {
319  BMIter iter;
320  BMHeader *ele;
321  int tot;
322  uint i;
323 
325  (BPy_BMGeneric *)value,
326  bm,
328  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
329  opname,
330  slot_name,
331  "element buffer") == -1) {
332  return -1; /* error is set in bpy_slot_from_py_elem_check() */
333  }
334 
335  /* this will loop over all elements which is a shame but
336  * we need to know this before alloc */
337  /* calls bpy_bmelemseq_length() */
338  tot = Py_TYPE(value)->tp_as_sequence->sq_length(value);
339 
340  BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, tot);
341 
342  i = 0;
343  BM_ITER_BPY_BM_SEQ (ele, &iter, ((BPy_BMElemSeq *)value)) {
344  slot->data.buf[i] = ele;
345  i++;
346  }
347  }
348  /* keep this last */
349  else if (PySequence_Check(value)) {
350  BMElem **elem_array = NULL;
351  Py_ssize_t elem_array_len;
352 
353  elem_array = BPy_BMElem_PySeq_As_Array(&bm,
354  value,
355  0,
356  PY_SSIZE_T_MAX,
357  &elem_array_len,
358  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
359  true,
360  true,
361  slot_name);
362 
363  /* error is set above */
364  if (elem_array == NULL) {
365  return -1;
366  }
367 
368  BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, elem_array_len);
369  memcpy(slot->data.buf, elem_array, sizeof(void *) * elem_array_len);
370  PyMem_FREE(elem_array);
371  }
372  else {
373  PyErr_Format(PyExc_TypeError,
374  "%.200s: keyword \"%.200s\" expected "
375  "a bmesh sequence, list, (htype, flag) pair, not %.200s",
376  opname,
377  slot_name,
378  Py_TYPE(value)->tp_name);
379  return -1;
380  }
381  }
382  break;
383  }
384  case BMO_OP_SLOT_MAPPING: {
385  /* first check types */
387  if (!PyDict_Check(value)) {
388  PyErr_Format(PyExc_TypeError,
389  "%.200s: keyword \"%.200s\" expected "
390  "a dict, not %.200s",
391  opname,
392  slot_name,
393  Py_TYPE(value)->tp_name);
394  return -1;
395  }
396  }
397  else {
398  if (!PySet_Check(value)) {
399  PyErr_Format(PyExc_TypeError,
400  "%.200s: keyword \"%.200s\" expected "
401  "a set, not %.200s",
402  opname,
403  slot_name,
404  Py_TYPE(value)->tp_name);
405  return -1;
406  }
407  }
408 
409  switch (slot->slot_subtype.map) {
411  if (PyDict_Size(value) > 0) {
412  PyObject *arg_key, *arg_value;
413  Py_ssize_t arg_pos = 0;
414  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
416  bm,
418  opname,
419  slot_name,
420  "invalid key in dict") == -1) {
421  return -1; /* error is set in bpy_slot_from_py_elem_check() */
422  }
423 
424  if (bpy_slot_from_py_elem_check((BPy_BMElem *)arg_value,
425  bm,
427  opname,
428  slot_name,
429  "invalid value in dict") == -1) {
430  return -1; /* error is set in bpy_slot_from_py_elem_check() */
431  }
432 
434  bmop, slot, ((BPy_BMElem *)arg_key)->ele, ((BPy_BMElem *)arg_value)->ele);
435  }
436  }
437  break;
438  }
440  if (PyDict_Size(value) > 0) {
441  PyObject *arg_key, *arg_value;
442  Py_ssize_t arg_pos = 0;
443  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
444  float value_f;
445 
447  bm,
449  opname,
450  slot_name,
451  "invalid key in dict") == -1) {
452  return -1; /* error is set in bpy_slot_from_py_elem_check() */
453  }
454 
455  value_f = PyFloat_AsDouble(arg_value);
456 
457  if (value_f == -1.0f && PyErr_Occurred()) {
458  PyErr_Format(PyExc_TypeError,
459  "%.200s: keyword \"%.200s\" expected "
460  "a dict with float values, not %.200s",
461  opname,
462  slot_name,
463  Py_TYPE(arg_value)->tp_name);
464  return -1;
465  }
466 
467  BMO_slot_map_float_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_f);
468  }
469  }
470  break;
471  }
473  if (PyDict_Size(value) > 0) {
474  PyObject *arg_key, *arg_value;
475  Py_ssize_t arg_pos = 0;
476  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
477  int value_i;
478 
480  bm,
482  opname,
483  slot_name,
484  "invalid key in dict") == -1) {
485  return -1; /* error is set in bpy_slot_from_py_elem_check() */
486  }
487 
488  value_i = PyC_Long_AsI32(arg_value);
489 
490  if (value_i == -1 && PyErr_Occurred()) {
491  PyErr_Format(PyExc_TypeError,
492  "%.200s: keyword \"%.200s\" expected "
493  "a dict with int values, not %.200s",
494  opname,
495  slot_name,
496  Py_TYPE(arg_value)->tp_name);
497  return -1;
498  }
499 
500  BMO_slot_map_int_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i);
501  }
502  }
503  break;
504  }
506  if (PyDict_Size(value) > 0) {
507  PyObject *arg_key, *arg_value;
508  Py_ssize_t arg_pos = 0;
509  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
510  int value_i;
511 
513  bm,
515  opname,
516  slot_name,
517  "invalid key in dict") == -1) {
518  return -1; /* error is set in bpy_slot_from_py_elem_check() */
519  }
520 
521  value_i = PyC_Long_AsI32(arg_value);
522 
523  if (value_i == -1 && PyErr_Occurred()) {
524  PyErr_Format(PyExc_TypeError,
525  "%.200s: keyword \"%.200s\" expected "
526  "a dict with bool values, not %.200s",
527  opname,
528  slot_name,
529  Py_TYPE(arg_value)->tp_name);
530  return -1;
531  }
532 
533  BMO_slot_map_bool_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i != 0);
534  }
535  }
536  break;
537  }
539  if (PySet_Size(value) > 0) {
540  PyObject *arg_key;
541  Py_ssize_t arg_pos = 0;
542  Py_ssize_t arg_hash = 0;
543  while (_PySet_NextEntry(value, &arg_pos, &arg_key, &arg_hash)) {
544 
546  bm,
548  opname,
549  slot_name,
550  "invalid key in set") == -1) {
551  return -1; /* error is set in bpy_slot_from_py_elem_check() */
552  }
553 
554  BMO_slot_map_empty_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele);
555  }
556  }
557  break;
558  }
560  /* can't convert from these */
561  PyErr_Format(PyExc_NotImplementedError,
562  "This arguments mapping subtype %d is not supported",
563  slot->slot_subtype.map);
564  return -1;
565  }
566  }
567  break;
568  }
569  default:
570  /* TODO: many others. */
571  PyErr_Format(PyExc_NotImplementedError,
572  "%.200s: keyword \"%.200s\" type %d not working yet!",
573  opname,
574  slot_name,
575  slot->slot_type);
576  return -1;
577  }
578 
579  /* all is well */
580  return 0;
581 }
582 
588 static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
589 {
590  PyObject *item = NULL;
591 
592  /* keep switch in same order as above */
593  switch (slot->slot_type) {
594  case BMO_OP_SLOT_BOOL:
595  item = PyBool_FromLong(BMO_SLOT_AS_BOOL(slot));
596  break;
597  case BMO_OP_SLOT_INT:
598  item = PyLong_FromLong(BMO_SLOT_AS_INT(slot));
599  break;
600  case BMO_OP_SLOT_FLT:
601  item = PyFloat_FromDouble((double)BMO_SLOT_AS_FLOAT(slot));
602  break;
603  case BMO_OP_SLOT_MAT:
604  item = Matrix_CreatePyObject((float *)BMO_SLOT_AS_MATRIX(slot), 4, 4, NULL);
605  break;
606  case BMO_OP_SLOT_VEC:
607  item = Vector_CreatePyObject(BMO_SLOT_AS_VECTOR(slot), slot->len, NULL);
608  break;
609  case BMO_OP_SLOT_PTR:
610  BLI_assert(0); /* currently we don't have any pointer return values in use */
611  item = Py_INCREF_RET(Py_None);
612  break;
616  item = ele ? BPy_BMElem_CreatePyObject(bm, ele) : Py_INCREF_RET(Py_None);
617  }
618  else {
619  const int size = slot->len;
620  void **buffer = BMO_SLOT_AS_BUFFER(slot);
621  int j;
622 
623  item = PyList_New(size);
624  for (j = 0; j < size; j++) {
625  BMHeader *ele = buffer[j];
626  PyList_SET_ITEM(item, j, BPy_BMElem_CreatePyObject(bm, ele));
627  }
628  }
629  break;
630  }
631  case BMO_OP_SLOT_MAPPING: {
632  GHash *slot_hash = BMO_SLOT_AS_GHASH(slot);
633  GHashIterator hash_iter;
634 
635  switch (slot->slot_subtype.map) {
637  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
638  if (slot_hash) {
639  GHASH_ITER (hash_iter, slot_hash) {
640  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
641  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
642 
643  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
644  PyObject *py_val = BPy_BMElem_CreatePyObject(bm, ele_val);
645 
646  PyDict_SetItem(item, py_key, py_val);
647  Py_DECREF(py_key);
648  Py_DECREF(py_val);
649  }
650  }
651  break;
652  }
654  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
655  if (slot_hash) {
656  GHASH_ITER (hash_iter, slot_hash) {
657  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
658  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
659 
660  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
661  PyObject *py_val = PyFloat_FromDouble(*(float *)&ele_val);
662 
663  PyDict_SetItem(item, py_key, py_val);
664  Py_DECREF(py_key);
665  Py_DECREF(py_val);
666  }
667  }
668  break;
669  }
671  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
672  if (slot_hash) {
673  GHASH_ITER (hash_iter, slot_hash) {
674  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
675  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
676 
677  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
678  PyObject *py_val = PyLong_FromLong(*(int *)&ele_val);
679 
680  PyDict_SetItem(item, py_key, py_val);
681  Py_DECREF(py_key);
682  Py_DECREF(py_val);
683  }
684  }
685  break;
686  }
688  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
689  if (slot_hash) {
690  GHASH_ITER (hash_iter, slot_hash) {
691  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
692  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
693 
694  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
695  PyObject *py_val = PyBool_FromLong(*(bool *)&ele_val);
696 
697  PyDict_SetItem(item, py_key, py_val);
698  Py_DECREF(py_key);
699  Py_DECREF(py_val);
700  }
701  }
702  break;
703  }
705  item = PySet_New(NULL);
706  if (slot_hash) {
707  GHASH_ITER (hash_iter, slot_hash) {
708  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
709 
710  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
711 
712  PySet_Add(item, py_key);
713 
714  Py_DECREF(py_key);
715  }
716  }
717  break;
718  }
720  /* can't convert from these */
721  item = Py_INCREF_RET(Py_None);
722  break;
723  }
724  break;
725  }
726  }
727  BLI_assert(item != NULL);
728 
729  return item;
730 }
731 
732 PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
733 {
734  PyObject *ret;
735  BPy_BMesh *py_bm;
736  BMesh *bm;
737 
738  BMOperator bmop;
739 
740  if ((PyTuple_GET_SIZE(args) == 1) && (py_bm = (BPy_BMesh *)PyTuple_GET_ITEM(args, 0)) &&
741  (BPy_BMesh_Check(py_bm))) {
742  BPY_BM_CHECK_OBJ(py_bm);
743  bm = py_bm->bm;
744 
745  if (bm->use_toolflags == false) {
746  PyErr_SetString(PyExc_ValueError, "bmesh created with 'use_operators=False'");
747  return NULL;
748  }
749 
750  /* could complain about entering with exceptions... */
752  }
753  else {
754  PyErr_SetString(PyExc_TypeError,
755  "bmesh operators expect a single BMesh positional argument, all other args "
756  "must be keywords");
757  return NULL;
758  }
759 
760  /* TODO: error check this!, though we do the error check on attribute access. */
761  /* TODO: make flags optional. */
762  BMO_op_init(bm, &bmop, BMO_FLAG_DEFAULTS, self->opname);
763 
764  if (kw && PyDict_Size(kw) > 0) {
765  /* setup properties, see bpy_rna.c: pyrna_py_to_prop()
766  * which shares this logic for parsing properties */
767 
768  PyObject *key, *value;
769  Py_ssize_t pos = 0;
770  while (PyDict_Next(kw, &pos, &key, &value)) {
771  const char *slot_name = PyUnicode_AsUTF8(key);
772  BMOpSlot *slot;
773 
774  if (!BMO_slot_exists(bmop.slots_in, slot_name)) {
775  PyErr_Format(PyExc_TypeError,
776  "%.200s: keyword \"%.200s\" is invalid for this operator",
777  self->opname,
778  slot_name);
779  BMO_op_finish(bm, &bmop);
780  return NULL;
781  }
782 
783  slot = BMO_slot_get(bmop.slots_in, slot_name);
784 
785  /* now assign the value */
786  if (bpy_slot_from_py(bm, &bmop, slot, value, self->opname, slot_name) == -1) {
787  BMO_op_finish(bm, &bmop);
788  return NULL;
789  }
790  }
791  }
792 
793  BMO_op_exec(bm, &bmop);
794 
795  /* from here until the end of the function, no returns, just set 'ret' */
796  if (UNLIKELY(bpy_bm_op_as_py_error(bm) == -1)) {
797  ret = NULL; /* exception raised above */
798  }
799  else if (bmop.slots_out[0].slot_name == NULL) {
800  ret = Py_INCREF_RET(Py_None);
801  }
802  else {
803  /* build return value */
804  int i;
805  ret = PyDict_New();
806 
807  for (i = 0; bmop.slots_out[i].slot_name; i++) {
808  // BMOpDefine *op_def = opdefines[bmop.type];
809  // BMOSlotType *slot_type = op_def->slot_types_out[i];
810  BMOpSlot *slot = &bmop.slots_out[i];
811  PyObject *item;
812 
813  /* this function doesn't throw exceptions */
814  item = bpy_slot_to_py(bm, slot);
815  if (item == NULL) {
816  item = Py_INCREF_RET(Py_None);
817  }
818 
819 #if 1
820  /* temp code, strip off '.out' while we keep this convention */
821  {
822  char slot_name_strip[MAX_SLOTNAME];
823  const char *ch = strchr(slot->slot_name, '.'); /* can't fail! */
824  const int tot = ch - slot->slot_name;
825  BLI_assert(ch != NULL);
826  memcpy(slot_name_strip, slot->slot_name, tot);
827  slot_name_strip[tot] = '\0';
828  PyDict_SetItemString(ret, slot_name_strip, item);
829  }
830 #else
831  PyDict_SetItemString(ret, slot->slot_name, item);
832 #endif
833  Py_DECREF(item);
834  }
835  }
836 
837  BMO_op_finish(bm, &bmop);
838  return ret;
839 }
#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:298
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:302
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:321
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:705
unsigned int uint
Definition: BLI_sys_types.h:67
unsigned short ushort
Definition: BLI_sys_types.h:68
#define UNLIKELY(x)
#define ELEM(...)
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
void BMO_error_clear(BMesh *bm)
@ BMO_ERROR_FATAL
Definition: bmesh_error.h:34
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
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, int len)
#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_get_single(BMOpSlot *slot)
void BMO_slot_buffer_from_single(BMOperator *op, BMOpSlot *slot, BMHeader *ele)
#define MAX_SLOTNAME
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.
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
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)
BLI_STATIC_ASSERT(sizeof(PyC_FlagSet)==sizeof(BMO_FlagSet), "size mismatch")
PyObject * BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
static PyObject * bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
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 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_ex(const char htype, char ret[32])
char * BPy_BMElem_StringFromHType(const char htype)
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
Definition: bpy_driver.c:165
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
uint pos
ccl_global float * buffer
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:98
int Matrix_ParseAny(PyObject *o, void *p)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort col_num, const ushort row_num, PyTypeObject *base_type)
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)
return ret
BMHeader head
Definition: bmesh_class.h:243
char htype
Definition: bmesh_class.h:64
eBMOpSlotSubType_Union slot_subtype
eBMOpSlotType slot_type
struct BMOpSlot::@145::@146 enum_data
union BMOpSlot::@145 data
const char * slot_name
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
struct BMOpSlot slots_in[BMO_OP_MAX_SLOTS]
uint use_toolflags
Definition: bmesh_class.h:333
struct BMElem * ele
PyObject_VAR_HEAD struct BMesh * bm
PyObject_VAR_HEAD struct BMesh * bm
PyObject_VAR_HEAD struct BMesh * bm
eBMOpSlotSubType_Int intg
eBMOpSlotSubType_Elem elem
eBMOpSlotSubType_Map map