Blender  V2.93
bmesh_py_ops.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 
27 #include <Python.h>
28 
29 #include "BLI_dynstr.h"
30 #include "BLI_utildefines.h"
31 
32 #include "MEM_guardedalloc.h"
33 
34 #include "bmesh.h"
35 
36 #include "bmesh_py_ops.h" /* own include */
37 #include "bmesh_py_ops_call.h"
38 
39 /* bmesh operator 'bmesh.ops.*' callable types
40  * ******************************************* */
41 static PyTypeObject bmesh_op_Type;
42 
43 static PyObject *bpy_bmesh_op_CreatePyObject(const char *opname)
44 {
45  BPy_BMeshOpFunc *self = PyObject_New(BPy_BMeshOpFunc, &bmesh_op_Type);
46 
47  self->opname = opname;
48 
49  return (PyObject *)self;
50 }
51 
52 static PyObject *bpy_bmesh_op_repr(BPy_BMeshOpFunc *self)
53 {
54  return PyUnicode_FromFormat("<%.200s bmesh.ops.%.200s()>", Py_TYPE(self)->tp_name, self->opname);
55 }
56 
57 /* methods
58  * ======= */
59 
60 /* __doc__
61  * ------- */
62 
63 static char *bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], const bool is_out)
64 {
65  DynStr *dyn_str = BLI_dynstr_new();
66  char *ret;
67  bool quoted;
68  bool set;
69 
70  int i = 0;
71 
72  while (*slot_types[i].name) {
73  quoted = false;
74  set = false;
75  /* cut off '.out' by using a string size arg */
76  const int name_len = is_out ? (strchr(slot_types[i].name, '.') - slot_types[i].name) :
77  sizeof(slot_types[i].name);
78  const char *value = "<Unknown>";
79  switch (slot_types[i].type) {
80  case BMO_OP_SLOT_BOOL:
81  value = "False";
82  break;
83  case BMO_OP_SLOT_INT:
84  if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_ENUM) {
85  value = slot_types[i].enum_flags[0].identifier;
86  quoted = true;
87  }
88  else if (slot_types[i].subtype.intg == BMO_OP_SLOT_SUBTYPE_INT_FLAG) {
89  value = "";
90  set = true;
91  }
92  else {
93  value = "0";
94  }
95  break;
96  case BMO_OP_SLOT_FLT:
97  value = "0.0";
98  break;
99  case BMO_OP_SLOT_PTR:
100  value = "None";
101  break;
102  case BMO_OP_SLOT_MAT:
103  value = "Matrix()";
104  break;
105  case BMO_OP_SLOT_VEC:
106  value = "Vector()";
107  break;
109  value = (slot_types[i].subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) ? "None" : "[]";
110  break;
111  case BMO_OP_SLOT_MAPPING:
112  value = "{}";
113  break;
114  }
115  BLI_dynstr_appendf(dyn_str,
116  i ? ", %.*s=%s%s%s%s%s" : "%.*s=%s%s%s%s%s",
117  name_len,
118  slot_types[i].name,
119  set ? "{" : "",
120  quoted ? "'" : "",
121  value,
122  quoted ? "'" : "",
123  set ? "}" : "");
124  i++;
125  }
126 
127  ret = BLI_dynstr_get_cstring(dyn_str);
128  BLI_dynstr_free(dyn_str);
129  return ret;
130 }
131 
132 static PyObject *bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void *UNUSED(closure))
133 {
134  PyObject *ret;
135  char *slot_in;
136  char *slot_out;
137  int i;
138 
139  i = BMO_opcode_from_opname(self->opname);
140 
141  slot_in = bmp_slots_as_args(bmo_opdefines[i]->slot_types_in, false);
142  slot_out = bmp_slots_as_args(bmo_opdefines[i]->slot_types_out, true);
143 
144  ret = PyUnicode_FromFormat("%.200s bmesh.ops.%.200s(bmesh, %s)\n -> dict(%s)",
145  Py_TYPE(self)->tp_name,
146  self->opname,
147  slot_in,
148  slot_out);
149 
150  MEM_freeN(slot_in);
151  MEM_freeN(slot_out);
152 
153  return ret;
154 }
155 
156 static PyGetSetDef bpy_bmesh_op_getseters[] = {
157  {"__doc__", (getter)bpy_bmesh_op_doc_get, (setter)NULL, NULL, NULL},
158  {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
159 };
160 
161 /* Types
162  * ===== */
163 
164 static PyTypeObject bmesh_op_Type = {
165  PyVarObject_HEAD_INIT(NULL, 0) "BMeshOpFunc", /* tp_name */
166  sizeof(BPy_BMeshOpFunc), /* tp_basicsize */
167  0, /* tp_itemsize */
168  /* methods */
169  NULL, /* tp_dealloc */
170  0, /* tp_vectorcall_offset */
171  NULL, /* getattrfunc tp_getattr; */
172  NULL, /* setattrfunc tp_setattr; */
173  NULL,
174  /* tp_compare */ /* DEPRECATED in python 3.0! */
175  (reprfunc)bpy_bmesh_op_repr, /* tp_repr */
176 
177  /* Method suites for standard classes */
178 
179  NULL, /* PyNumberMethods *tp_as_number; */
180  NULL, /* PySequenceMethods *tp_as_sequence; */
181  NULL, /* PyMappingMethods *tp_as_mapping; */
182 
183  /* More standard operations (here for binary compatibility) */
184 
185  NULL, /* hashfunc tp_hash; */
186  (ternaryfunc)BPy_BMO_call, /* ternaryfunc tp_call; */
187  NULL, /* reprfunc tp_str; */
188 
189  /* will only use these if this is a subtype of a py class */
190  NULL, /* getattrofunc tp_getattro; */
191  NULL, /* setattrofunc tp_setattro; */
192 
193  /* Functions to access object as input/output buffer */
194  NULL, /* PyBufferProcs *tp_as_buffer; */
195 
196  /*** Flags to define presence of optional/expanded features ***/
197  Py_TPFLAGS_DEFAULT, /* long tp_flags; */
198 
199  NULL, /* char *tp_doc; Documentation string */
200  /*** Assigned meaning in release 2.0 ***/
201  /* call function for all accessible objects */
202  NULL, /* traverseproc tp_traverse; */
203 
204  /* delete references to contained objects */
205  NULL, /* inquiry tp_clear; */
206 
207  /*** Assigned meaning in release 2.1 ***/
208  /*** rich comparisons ***/
209  NULL, /* richcmpfunc tp_richcompare; */
210 
211  /*** weak reference enabler ***/
212  0,
213  /*** Added in release 2.2 ***/
214  /* Iterators */
215  NULL, /* getiterfunc tp_iter; */
216  NULL, /* iternextfunc tp_iternext; */
217 
218  /*** Attribute descriptor and subclassing stuff ***/
219  NULL, /* struct PyMethodDef *tp_methods; */
220  NULL, /* struct PyMemberDef *tp_members; */
221  bpy_bmesh_op_getseters, /* struct PyGetSetDef *tp_getset; */
222  NULL, /* struct _typeobject *tp_base; */
223  NULL, /* PyObject *tp_dict; */
224  NULL, /* descrgetfunc tp_descr_get; */
225  NULL, /* descrsetfunc tp_descr_set; */
226  0, /* long tp_dictoffset; */
227  NULL, /* initproc tp_init; */
228  NULL, /* allocfunc tp_alloc; */
229  NULL, /* newfunc tp_new; */
230  /* Low-level free-memory routine */
231  NULL, /* freefunc tp_free; */
232  /* For PyObject_IS_GC */
233  NULL, /* inquiry tp_is_gc; */
234  NULL, /* PyObject *tp_bases; */
235  /* method resolution order */
236  NULL, /* PyObject *tp_mro; */
237  NULL, /* PyObject *tp_cache; */
238  NULL, /* PyObject *tp_subclasses; */
239  NULL, /* PyObject *tp_weaklist; */
240  NULL,
241 };
242 
243 /* bmesh module 'bmesh.ops'
244  * ************************ */
245 
246 static PyObject *bpy_bmesh_ops_module_getattro(PyObject *UNUSED(self), PyObject *pyname)
247 {
248  const char *opname = PyUnicode_AsUTF8(pyname);
249 
250  if (BMO_opcode_from_opname(opname) != -1) {
251  return bpy_bmesh_op_CreatePyObject(opname);
252  }
253 
254  PyErr_Format(PyExc_AttributeError, "BMeshOpsModule: operator \"%.200s\" doesn't exist", opname);
255  return NULL;
256 }
257 
258 static PyObject *bpy_bmesh_ops_module_dir(PyObject *UNUSED(self))
259 {
260  const uint tot = bmo_opdefines_total;
261  uint i;
262  PyObject *ret;
263 
264  ret = PyList_New(bmo_opdefines_total);
265 
266  for (i = 0; i < tot; i++) {
267  PyList_SET_ITEM(ret, i, PyUnicode_FromString(bmo_opdefines[i]->opname));
268  }
269 
270  return ret;
271 }
272 
273 static struct PyMethodDef BPy_BM_ops_methods[] = {
274  {"__getattr__", (PyCFunction)bpy_bmesh_ops_module_getattro, METH_O, NULL},
275  {"__dir__", (PyCFunction)bpy_bmesh_ops_module_dir, METH_NOARGS, NULL},
276  {NULL, NULL, 0, NULL},
277 };
278 
279 PyDoc_STRVAR(BPy_BM_ops_doc, "Access to BMesh operators");
280 static struct PyModuleDef BPy_BM_ops_module_def = {
281  PyModuleDef_HEAD_INIT,
282  "bmesh.ops", /* m_name */
283  BPy_BM_ops_doc, /* m_doc */
284  0, /* m_size */
285  BPy_BM_ops_methods, /* m_methods */
286  NULL, /* m_reload */
287  NULL, /* m_traverse */
288  NULL, /* m_clear */
289  NULL, /* m_free */
290 };
291 
292 PyObject *BPyInit_bmesh_ops(void)
293 {
294  PyObject *submodule = PyModule_Create(&BPy_BM_ops_module_def);
295 
296  if (PyType_Ready(&bmesh_op_Type) < 0) {
297  return NULL;
298  }
299 
300  return submodule;
301 }
A dynamically sized string ADT.
DynStr * BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_dynstr.c:71
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL()
Definition: BLI_dynstr.c:358
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format,...) ATTR_PRINTF_FORMAT(2
char * BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_dynstr.c:323
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
const int bmo_opdefines_total
const BMOpDefine * bmo_opdefines[]
@ 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
int BMO_opcode_from_opname(const char *opname)
@ BMO_OP_SLOT_SUBTYPE_INT_FLAG
@ BMO_OP_SLOT_SUBTYPE_INT_ENUM
#define BMO_OP_MAX_SLOTS
static PyObject * bpy_bmesh_ops_module_dir(PyObject *UNUSED(self))
Definition: bmesh_py_ops.c:258
static struct PyMethodDef BPy_BM_ops_methods[]
Definition: bmesh_py_ops.c:273
static PyObject * bpy_bmesh_op_repr(BPy_BMeshOpFunc *self)
Definition: bmesh_py_ops.c:52
static PyObject * bpy_bmesh_op_doc_get(BPy_BMeshOpFunc *self, void *UNUSED(closure))
Definition: bmesh_py_ops.c:132
static PyObject * bpy_bmesh_op_CreatePyObject(const char *opname)
Definition: bmesh_py_ops.c:43
static PyGetSetDef bpy_bmesh_op_getseters[]
Definition: bmesh_py_ops.c:156
PyDoc_STRVAR(BPy_BM_ops_doc, "Access to BMesh operators")
PyObject * BPyInit_bmesh_ops(void)
Definition: bmesh_py_ops.c:292
static PyTypeObject bmesh_op_Type
Definition: bmesh_py_ops.c:41
static PyObject * bpy_bmesh_ops_module_getattro(PyObject *UNUSED(self), PyObject *pyname)
Definition: bmesh_py_ops.c:246
static struct PyModuleDef BPy_BM_ops_module_def
Definition: bmesh_py_ops.c:280
static char * bmp_slots_as_args(const BMOSlotType slot_types[BMO_OP_MAX_SLOTS], const bool is_out)
Definition: bmesh_py_ops.c:63
PyObject * BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw)
PyObject * self
Definition: bpy_driver.c:185
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
return ret