Blender  V2.93
bmesh_py_ops_call.c
Go to the documentation of this file.
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  * The Original Code is Copyright (C) 2012 Blender Foundation.
17  * All rights reserved.
18  */
19 
28 #include <Python.h>
29 
30 #include "BLI_utildefines.h"
31 
32 #include "../mathutils/mathutils.h"
33 
34 #include "bmesh.h"
35 
36 #include "bmesh_py_ops_call.h" /* own include */
37 
38 #include "bmesh_py_types.h"
39 
40 #include "../generic/py_capi_utils.h"
41 #include "../generic/python_utildefines.h"
42 
43 BLI_STATIC_ASSERT(sizeof(PyC_FlagSet) == sizeof(BMO_FlagSet), "size mismatch");
44 
46 {
47  if (BMO_error_occurred(bm)) {
48  /* note: we could have multiple errors */
49  const char *errmsg;
50  if (BMO_error_get(bm, &errmsg, NULL)) {
51  PyErr_Format(PyExc_RuntimeError, "bmesh operator: %.200s", errmsg);
53  return -1;
54  }
55  }
56  return 0;
57 }
58 
68  BMesh *bm,
69  const char htype,
70  /* for error messages */
71  const char *opname,
72  const char *slot_name,
73  const char *descr)
74 {
75  if (!BPy_BMElem_Check(value) || !(value->ele->head.htype & htype)) {
76  PyErr_Format(PyExc_TypeError,
77  "%.200s: keyword \"%.200s\" %.200s, expected a %.200s not *.200s",
78  opname,
79  slot_name,
80  descr,
82  Py_TYPE(value)->tp_name);
83  return -1;
84  }
85  if (value->bm == NULL) {
86  PyErr_Format(PyExc_TypeError,
87  "%.200s: keyword \"%.200s\" %.200s invalidated element",
88  opname,
89  slot_name,
90  descr);
91  return -1;
92  }
93  if (value->bm != bm) { /* we may want to make this check optional by setting 'bm' to NULL */
94  PyErr_Format(PyExc_TypeError,
95  "%.200s: keyword \"%.200s\" %.200s invalidated element",
96  opname,
97  slot_name,
98  descr);
99  return -1;
100  }
101  return 0;
102 }
103 
114  BMesh *bm,
115  const char htype_py,
116  const char htype_bmo,
117  /* for error messages */
118  const char *opname,
119  const char *slot_name,
120  const char *descr)
121 {
122  if (value->bm == NULL) {
123  PyErr_Format(PyExc_TypeError,
124  "%.200s: keyword \"%.200s\" %.200s, invalidated sequence",
125  opname,
126  slot_name,
127  descr);
128  return -1;
129  }
130  if (value->bm != bm) { /* we may want to make this check optional by setting 'bm' to NULL */
131  PyErr_Format(PyExc_TypeError,
132  "%.200s: keyword \"%.200s\" %.200s, invalidated sequence",
133  opname,
134  slot_name,
135  descr);
136  return -1;
137  }
138  if ((htype_py & htype_bmo) == 0) {
139  char str_bmo[32];
140  char str_py[32];
141  PyErr_Format(PyExc_TypeError,
142  "%.200s: keyword \"%.200s\" %.200s, expected "
143  "a sequence of %.200s not %.200s",
144  opname,
145  slot_name,
146  descr,
147  BPy_BMElem_StringFromHType_ex(htype_bmo, str_bmo),
148  BPy_BMElem_StringFromHType_ex(htype_py, str_py));
149  return -1;
150  }
151 
152  return 0;
153 }
154 
159  BMOperator *bmop,
160  BMOpSlot *slot,
161  PyObject *value,
162  /* the are just for exception messages */
163  const char *opname,
164  const char *slot_name)
165 {
166  switch (slot->slot_type) {
167  case BMO_OP_SLOT_BOOL: {
168  const int param = PyC_Long_AsBool(value);
169 
170  if (param == -1) {
171  PyErr_Format(PyExc_TypeError,
172  "%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s",
173  opname,
174  slot_name,
175  Py_TYPE(value)->tp_name);
176  return -1;
177  }
178 
179  BMO_SLOT_AS_BOOL(slot) = param;
180 
181  break;
182  }
183  case BMO_OP_SLOT_INT: {
185  int enum_val = -1;
186  PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_data.flags;
187  const char *enum_str = PyUnicode_AsUTF8(value);
188 
189  if (enum_str == NULL) {
190  PyErr_Format(PyExc_TypeError,
191  "%.200s: keyword \"%.200s\" expected a string, not %.200s",
192  opname,
193  slot_name,
194  Py_TYPE(value)->tp_name);
195  return -1;
196  }
197 
198  if (PyC_FlagSet_ValueFromID(items, enum_str, &enum_val, slot_name) == -1) {
199  return -1;
200  }
201 
202  BMO_SLOT_AS_INT(slot) = enum_val;
203  }
204  else if (slot->slot_subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
205  int flag = 0;
206  PyC_FlagSet *items = (PyC_FlagSet *)slot->data.enum_data.flags;
207 
208  if (PyC_FlagSet_ToBitfield(items, value, &flag, slot_name) == -1) {
209  return -1;
210  }
211 
212  BMO_SLOT_AS_INT(slot) = flag;
213  }
214  else {
215  const int param = PyC_Long_AsI32(value);
216 
217  if (param == -1 && PyErr_Occurred()) {
218  PyErr_Format(PyExc_TypeError,
219  "%.200s: keyword \"%.200s\" expected an int, not %.200s",
220  opname,
221  slot_name,
222  Py_TYPE(value)->tp_name);
223  return -1;
224  }
225 
226  BMO_SLOT_AS_INT(slot) = param;
227  }
228  break;
229  }
230  case BMO_OP_SLOT_FLT: {
231  const float param = PyFloat_AsDouble(value);
232  if (param == -1 && PyErr_Occurred()) {
233  PyErr_Format(PyExc_TypeError,
234  "%.200s: keyword \"%.200s\" expected a float, not %.200s",
235  opname,
236  slot_name,
237  Py_TYPE(value)->tp_name);
238  return -1;
239  }
240 
241  BMO_SLOT_AS_FLOAT(slot) = param;
242 
243  break;
244  }
245  case BMO_OP_SLOT_MAT: {
246  /* XXX - BMesh operator design is crappy here, operator slot should define matrix size,
247  * not the caller! */
248  MatrixObject *pymat;
249  if (!Matrix_ParseAny(value, &pymat)) {
250  return -1;
251  }
252  const ushort size = pymat->num_col;
253  if ((size != pymat->num_row) || (!ELEM(size, 3, 4))) {
254  PyErr_Format(PyExc_TypeError,
255  "%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix Matrix",
256  opname,
257  slot_name);
258  return -1;
259  }
260 
261  BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size);
262  break;
263  }
264  case BMO_OP_SLOT_VEC: {
265  /* passing slot name here is a bit non-descriptive */
266  if (mathutils_array_parse(BMO_SLOT_AS_VECTOR(slot), 3, 3, value, slot_name) == -1) {
267  return -1;
268  }
269  break;
270  }
274  bm,
275  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
276  opname,
277  slot_name,
278  "single element") == -1) {
279  return -1; /* error is set in bpy_slot_from_py_elem_check() */
280  }
281 
282  BMO_slot_buffer_from_single(bmop, slot, &((BPy_BMElem *)value)->ele->head);
283  }
284  else {
285  /* there are many ways we could interpret arguments, for now...
286  * - verts/edges/faces from the mesh direct,
287  * this way the operator takes every item.
288  * - `TODO` a plain python sequence (list) of elements.
289  * - `TODO` an iterator. eg.
290  * face.verts
291  * - `TODO` (type, flag) pair, eg.
292  * ('VERT', {'TAG'})
293  */
294 
295  if (BPy_BMVertSeq_Check(value)) {
297  bm,
298  BM_VERT,
299  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
300  opname,
301  slot_name,
302  "element buffer") == -1) {
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_VERT);
307  }
308  else if (BPy_BMEdgeSeq_Check(value)) {
310  bm,
311  BM_EDGE,
312  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
313  opname,
314  slot_name,
315  "element buffer") == -1) {
316  return -1; /* error is set in bpy_slot_from_py_elem_check() */
317  }
318 
319  BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_EDGE);
320  }
321  else if (BPy_BMFaceSeq_Check(value)) {
323  bm,
324  BM_FACE,
325  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
326  opname,
327  slot_name,
328  "element buffer") == -1) {
329  return -1; /* error is set in bpy_slot_from_py_elem_check() */
330  }
331  BMO_slot_buffer_from_all(bm, bmop, bmop->slots_in, slot_name, BM_FACE);
332  }
333 
334  else if (BPy_BMElemSeq_Check(value)) {
335  BMIter iter;
336  BMHeader *ele;
337  int tot;
338  uint i;
339 
341  (BPy_BMGeneric *)value,
342  bm,
344  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
345  opname,
346  slot_name,
347  "element buffer") == -1) {
348  return -1; /* error is set in bpy_slot_from_py_elem_check() */
349  }
350 
351  /* this will loop over all elements which is a shame but
352  * we need to know this before alloc */
353  /* calls bpy_bmelemseq_length() */
354  tot = Py_TYPE(value)->tp_as_sequence->sq_length(value);
355 
356  BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, tot);
357 
358  i = 0;
359  BM_ITER_BPY_BM_SEQ (ele, &iter, ((BPy_BMElemSeq *)value)) {
360  slot->data.buf[i] = ele;
361  i++;
362  }
363  }
364  /* keep this last */
365  else if (PySequence_Check(value)) {
366  BMElem **elem_array = NULL;
367  Py_ssize_t elem_array_len;
368 
369  elem_array = BPy_BMElem_PySeq_As_Array(&bm,
370  value,
371  0,
372  PY_SSIZE_T_MAX,
373  &elem_array_len,
374  (slot->slot_subtype.elem & BM_ALL_NOLOOP),
375  true,
376  true,
377  slot_name);
378 
379  /* error is set above */
380  if (elem_array == NULL) {
381  return -1;
382  }
383 
384  BMO_slot_buffer_alloc(bmop, bmop->slots_in, slot_name, elem_array_len);
385  memcpy(slot->data.buf, elem_array, sizeof(void *) * elem_array_len);
386  PyMem_FREE(elem_array);
387  }
388  else {
389  PyErr_Format(PyExc_TypeError,
390  "%.200s: keyword \"%.200s\" expected "
391  "a bmesh sequence, list, (htype, flag) pair, not %.200s",
392  opname,
393  slot_name,
394  Py_TYPE(value)->tp_name);
395  return -1;
396  }
397  }
398  break;
399  }
400  case BMO_OP_SLOT_MAPPING: {
401  /* first check types */
403  if (!PyDict_Check(value)) {
404  PyErr_Format(PyExc_TypeError,
405  "%.200s: keyword \"%.200s\" expected "
406  "a dict, not %.200s",
407  opname,
408  slot_name,
409  Py_TYPE(value)->tp_name);
410  return -1;
411  }
412  }
413  else {
414  if (!PySet_Check(value)) {
415  PyErr_Format(PyExc_TypeError,
416  "%.200s: keyword \"%.200s\" expected "
417  "a set, not %.200s",
418  opname,
419  slot_name,
420  Py_TYPE(value)->tp_name);
421  return -1;
422  }
423  }
424 
425  switch (slot->slot_subtype.map) {
427  if (PyDict_Size(value) > 0) {
428  PyObject *arg_key, *arg_value;
429  Py_ssize_t arg_pos = 0;
430  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
432  bm,
434  opname,
435  slot_name,
436  "invalid key in dict") == -1) {
437  return -1; /* error is set in bpy_slot_from_py_elem_check() */
438  }
439 
440  if (bpy_slot_from_py_elem_check((BPy_BMElem *)arg_value,
441  bm,
443  opname,
444  slot_name,
445  "invalid value in dict") == -1) {
446  return -1; /* error is set in bpy_slot_from_py_elem_check() */
447  }
448 
450  bmop, slot, ((BPy_BMElem *)arg_key)->ele, ((BPy_BMElem *)arg_value)->ele);
451  }
452  }
453  break;
454  }
456  if (PyDict_Size(value) > 0) {
457  PyObject *arg_key, *arg_value;
458  Py_ssize_t arg_pos = 0;
459  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
460  float value_f;
461 
463  bm,
465  opname,
466  slot_name,
467  "invalid key in dict") == -1) {
468  return -1; /* error is set in bpy_slot_from_py_elem_check() */
469  }
470 
471  value_f = PyFloat_AsDouble(arg_value);
472 
473  if (value_f == -1.0f && PyErr_Occurred()) {
474  PyErr_Format(PyExc_TypeError,
475  "%.200s: keyword \"%.200s\" expected "
476  "a dict with float values, not %.200s",
477  opname,
478  slot_name,
479  Py_TYPE(arg_value)->tp_name);
480  return -1;
481  }
482 
483  BMO_slot_map_float_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_f);
484  }
485  }
486  break;
487  }
489  if (PyDict_Size(value) > 0) {
490  PyObject *arg_key, *arg_value;
491  Py_ssize_t arg_pos = 0;
492  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
493  int value_i;
494 
496  bm,
498  opname,
499  slot_name,
500  "invalid key in dict") == -1) {
501  return -1; /* error is set in bpy_slot_from_py_elem_check() */
502  }
503 
504  value_i = PyC_Long_AsI32(arg_value);
505 
506  if (value_i == -1 && PyErr_Occurred()) {
507  PyErr_Format(PyExc_TypeError,
508  "%.200s: keyword \"%.200s\" expected "
509  "a dict with int values, not %.200s",
510  opname,
511  slot_name,
512  Py_TYPE(arg_value)->tp_name);
513  return -1;
514  }
515 
516  BMO_slot_map_int_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i);
517  }
518  }
519  break;
520  }
522  if (PyDict_Size(value) > 0) {
523  PyObject *arg_key, *arg_value;
524  Py_ssize_t arg_pos = 0;
525  while (PyDict_Next(value, &arg_pos, &arg_key, &arg_value)) {
526  int value_i;
527 
529  bm,
531  opname,
532  slot_name,
533  "invalid key in dict") == -1) {
534  return -1; /* error is set in bpy_slot_from_py_elem_check() */
535  }
536 
537  value_i = PyC_Long_AsI32(arg_value);
538 
539  if (value_i == -1 && PyErr_Occurred()) {
540  PyErr_Format(PyExc_TypeError,
541  "%.200s: keyword \"%.200s\" expected "
542  "a dict with bool values, not %.200s",
543  opname,
544  slot_name,
545  Py_TYPE(arg_value)->tp_name);
546  return -1;
547  }
548 
549  BMO_slot_map_bool_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele, value_i != 0);
550  }
551  }
552  break;
553  }
555  if (PySet_Size(value) > 0) {
556  PyObject *arg_key;
557  Py_ssize_t arg_pos = 0;
558  Py_ssize_t arg_hash = 0;
559  while (_PySet_NextEntry(value, &arg_pos, &arg_key, &arg_hash)) {
560 
562  bm,
564  opname,
565  slot_name,
566  "invalid key in set") == -1) {
567  return -1; /* error is set in bpy_slot_from_py_elem_check() */
568  }
569 
570  BMO_slot_map_empty_insert(bmop, slot, ((BPy_BMElem *)arg_key)->ele);
571  }
572  }
573  break;
574  }
576  /* can't convert from these */
577  PyErr_Format(PyExc_NotImplementedError,
578  "This arguments mapping subtype %d is not supported",
579  slot->slot_subtype.map);
580  return -1;
581  }
582  }
583  break;
584  }
585  default:
586  /* TODO --- many others */
587  PyErr_Format(PyExc_NotImplementedError,
588  "%.200s: keyword \"%.200s\" type %d not working yet!",
589  opname,
590  slot_name,
591  slot->slot_type);
592  return -1;
593  }
594 
595  /* all is well */
596  return 0;
597 }
598 
604 static PyObject *bpy_slot_to_py(BMesh *bm, BMOpSlot *slot)
605 {
606  PyObject *item = NULL;
607 
608  /* keep switch in same order as above */
609  switch (slot->slot_type) {
610  case BMO_OP_SLOT_BOOL:
611  item = PyBool_FromLong((BMO_SLOT_AS_BOOL(slot)));
612  break;
613  case BMO_OP_SLOT_INT:
614  item = PyLong_FromLong(BMO_SLOT_AS_INT(slot));
615  break;
616  case BMO_OP_SLOT_FLT:
617  item = PyFloat_FromDouble((double)BMO_SLOT_AS_FLOAT(slot));
618  break;
619  case BMO_OP_SLOT_MAT:
620  item = Matrix_CreatePyObject((float *)BMO_SLOT_AS_MATRIX(slot), 4, 4, NULL);
621  break;
622  case BMO_OP_SLOT_VEC:
623  item = Vector_CreatePyObject(BMO_SLOT_AS_VECTOR(slot), slot->len, NULL);
624  break;
625  case BMO_OP_SLOT_PTR:
626  BLI_assert(0); /* currently we don't have any pointer return values in use */
627  item = Py_INCREF_RET(Py_None);
628  break;
632  item = ele ? BPy_BMElem_CreatePyObject(bm, ele) : Py_INCREF_RET(Py_None);
633  }
634  else {
635  const int size = slot->len;
636  void **buffer = BMO_SLOT_AS_BUFFER(slot);
637  int j;
638 
639  item = PyList_New(size);
640  for (j = 0; j < size; j++) {
641  BMHeader *ele = buffer[j];
642  PyList_SET_ITEM(item, j, BPy_BMElem_CreatePyObject(bm, ele));
643  }
644  }
645  break;
646  }
647  case BMO_OP_SLOT_MAPPING: {
648  GHash *slot_hash = BMO_SLOT_AS_GHASH(slot);
649  GHashIterator hash_iter;
650 
651  switch (slot->slot_subtype.map) {
653  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
654  if (slot_hash) {
655  GHASH_ITER (hash_iter, slot_hash) {
656  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
657  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
658 
659  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
660  PyObject *py_val = BPy_BMElem_CreatePyObject(bm, ele_val);
661 
662  PyDict_SetItem(item, py_key, py_val);
663  Py_DECREF(py_key);
664  Py_DECREF(py_val);
665  }
666  }
667  break;
668  }
670  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
671  if (slot_hash) {
672  GHASH_ITER (hash_iter, slot_hash) {
673  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
674  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
675 
676  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
677  PyObject *py_val = PyFloat_FromDouble(*(float *)&ele_val);
678 
679  PyDict_SetItem(item, py_key, py_val);
680  Py_DECREF(py_key);
681  Py_DECREF(py_val);
682  }
683  }
684  break;
685  }
687  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
688  if (slot_hash) {
689  GHASH_ITER (hash_iter, slot_hash) {
690  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
691  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
692 
693  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
694  PyObject *py_val = PyLong_FromLong(*(int *)&ele_val);
695 
696  PyDict_SetItem(item, py_key, py_val);
697  Py_DECREF(py_key);
698  Py_DECREF(py_val);
699  }
700  }
701  break;
702  }
704  item = _PyDict_NewPresized(slot_hash ? BLI_ghash_len(slot_hash) : 0);
705  if (slot_hash) {
706  GHASH_ITER (hash_iter, slot_hash) {
707  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
708  void *ele_val = BLI_ghashIterator_getValue(&hash_iter);
709 
710  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
711  PyObject *py_val = PyBool_FromLong(*(bool *)&ele_val);
712 
713  PyDict_SetItem(item, py_key, py_val);
714  Py_DECREF(py_key);
715  Py_DECREF(py_val);
716  }
717  }
718  break;
719  }
721  item = PySet_New(NULL);
722  if (slot_hash) {
723  GHASH_ITER (hash_iter, slot_hash) {
724  BMHeader *ele_key = BLI_ghashIterator_getKey(&hash_iter);
725 
726  PyObject *py_key = BPy_BMElem_CreatePyObject(bm, ele_key);
727 
728  PySet_Add(item, py_key);
729 
730  Py_DECREF(py_key);
731  }
732  }
733  break;
734  }
736  /* can't convert from these */
737  item = Py_INCREF_RET(Py_None);
738  break;
739  }
740  break;
741  }
742  }
743  BLI_assert(item != NULL);
744 
745  return item;
746 }
747 
751 PyObject *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  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 NULL;
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 NULL;
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.c: 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 NULL;
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 NULL;
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 = NULL; /* exception raised above */
817  }
818  else if (bmop.slots_out[0].slot_name == NULL) {
819  ret = Py_INCREF_RET(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 == NULL) {
835  item = Py_INCREF_RET(Py_None);
836  }
837 
838 #if 1
839  /* temp 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 != NULL);
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_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:150
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:744
unsigned int uint
Definition: BLI_sys_types.h:83
unsigned short ushort
Definition: BLI_sys_types.h:84
#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
bool BMO_error_occurred(BMesh *bm)
void BMO_error_clear(BMesh *bm)
int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
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_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype)
BMO_ALL_TO_SLOT.
#define BMO_SLOT_AS_VECTOR(slot)
void * BMO_slot_buffer_alloc(BMOperator *op, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const int len)
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)
#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.
#define BMO_FLAG_DEFAULTS
bool BMO_slot_exists(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK HAS SLOT.
void BMO_op_init(BMesh *bm, BMOperator *op, const int flag, const char *opname)
BMESH OPSTACK INIT OP.
#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:185
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
uint pos
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
Definition: mathutils.c:118
int Matrix_ParseAny(PyObject *o, void *p)
PyObject * Matrix_CreatePyObject(const float *mat, const ushort num_col, const ushort num_row, PyTypeObject *base_type)
PyObject * Vector_CreatePyObject(const float *vec, const int size, PyTypeObject *base_type)
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int *r_value, const char *error_prefix)
int PyC_Long_AsBool(PyObject *value)
return ret
BMHeader head
Definition: bmesh_class.h:255
char htype
Definition: bmesh_class.h:76
eBMOpSlotSubType_Union slot_subtype
eBMOpSlotType slot_type
union BMOpSlot::@139 data
struct BMOpSlot::@139::@140 enum_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