diff options
author | Campbell Barton <ideasman42@gmail.com> | 2017-10-09 12:49:27 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2017-10-09 12:49:27 +0300 |
commit | a5b4b0f21c1ae8c96e4fea9abdcfac2fab1cf300 (patch) | |
tree | 0658d8bdfb8ec03652aa04f82ee8a4d243ec6370 /source/blender/python | |
parent | d68f698cf0321477c0734474150eb4bc43c4e85f (diff) | |
parent | abcda06934aba054de8540b66b13c2bbc5f8f515 (diff) |
Merge branch '28' into custom-manipulatorscustom-manipulators
Diffstat (limited to 'source/blender/python')
53 files changed, 3300 insertions, 915 deletions
diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt index e855f3a3756..8d26fee0abd 100644 --- a/source/blender/python/CMakeLists.txt +++ b/source/blender/python/CMakeLists.txt @@ -17,6 +17,7 @@ # ***** END GPL LICENSE BLOCK ***** add_subdirectory(intern) +add_subdirectory(gawain) add_subdirectory(generic) add_subdirectory(mathutils) add_subdirectory(bmesh) diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 8f287918a4a..6598d402f72 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -44,6 +44,7 @@ #include "bmesh_py_types.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" static int bpy_bm_op_as_py_error(BMesh *bm) { @@ -152,11 +153,9 @@ static int bpy_slot_from_py( switch (slot->slot_type) { case BMO_OP_SLOT_BOOL: { - int param; + const int param = PyC_Long_AsBool(value); - param = PyLong_AsLong(value); - - if (param < 0) { + if (param == -1) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected True/False or 0/1, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); @@ -170,23 +169,16 @@ static int bpy_slot_from_py( } case BMO_OP_SLOT_INT: { - int overflow; - long param = PyLong_AsLongAndOverflow(value, &overflow); - if (overflow || (param > INT_MAX) || (param < INT_MIN)) { - PyErr_Format(PyExc_ValueError, - "%.200s: keyword \"%.200s\" value not in 'int' range " - "(" STRINGIFY(INT_MIN) ", " STRINGIFY(INT_MAX) ")", - opname, slot_name, Py_TYPE(value)->tp_name); - return -1; - } - else if (param == -1 && PyErr_Occurred()) { + const int param = PyC_Long_AsI32(value); + + if (param == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected an int, not %.200s", opname, slot_name, Py_TYPE(value)->tp_name); return -1; } else { - BMO_SLOT_AS_INT(slot) = (int)param; + BMO_SLOT_AS_INT(slot) = param; } break; } @@ -208,26 +200,19 @@ static int bpy_slot_from_py( { /* XXX - BMesh operator design is crappy here, operator slot should define matrix size, * not the caller! */ - unsigned short size; - if (!MatrixObject_Check(value)) { - PyErr_Format(PyExc_TypeError, - "%.200s: keyword \"%.200s\" expected a Matrix, not %.200s", - opname, slot_name, Py_TYPE(value)->tp_name); + MatrixObject *pymat; + if (!Matrix_ParseAny(value, &pymat)) { return -1; } - else if (BaseMath_ReadCallback((MatrixObject *)value) == -1) { - return -1; - } - else if (((size = ((MatrixObject *)value)->num_col) != ((MatrixObject *)value)->num_row) || - (ELEM(size, 3, 4) == false)) - { + const ushort size = pymat->num_col; + if ((size != pymat->num_row) || (!ELEM(size, 3, 4))) { PyErr_Format(PyExc_TypeError, "%.200s: keyword \"%.200s\" expected a 3x3 or 4x4 matrix Matrix", opname, slot_name); return -1; } - BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, ((MatrixObject *)value)->matrix, size); + BMO_slot_mat_set(bmop, bmop->slots_in, slot_name, pymat->matrix, size); break; } case BMO_OP_SLOT_VEC: @@ -436,7 +421,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, @@ -466,7 +451,7 @@ static int bpy_slot_from_py( return -1; /* error is set in bpy_slot_from_py_elem_check() */ } - value_i = PyLong_AsLong(arg_value); + value_i = PyC_Long_AsI32(arg_value); if (value_i == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 88445cfd62b..caf836fa5b8 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -125,25 +125,19 @@ static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if ((unsigned int)param <= 1) { - if (hflag == BM_ELEM_SELECT) - BM_elem_select_set(self->bm, self->ele, param); - else - BM_elem_flag_set(self->ele, hflag, param); + if ((param = PyC_Long_AsBool(value)) == -1) { + return -1; + } - return 0; + if (hflag == BM_ELEM_SELECT) { + BM_elem_select_set(self->bm, self->ele, param); } else { - PyErr_Format(PyExc_TypeError, - "expected True/False or 0/1, not %.200s", - Py_TYPE(value)->tp_name); - return -1; + BM_elem_flag_set(self->ele, hflag, param); } + return 0; } - PyDoc_STRVAR(bpy_bm_elem_index_doc, "Index of this element.\n" "\n" @@ -170,21 +164,17 @@ static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *UNUSED BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else { - BM_elem_index_set(self->ele, param); /* set_dirty! */ - /* when setting the index assume its set invalid */ - self->bm->elem_index_dirty |= self->ele->head.htype; + BM_elem_index_set(self->ele, param); /* set_dirty! */ - return 0; - } + /* when setting the index assume its set invalid */ + self->bm->elem_index_dirty |= self->ele->head.htype; + + return 0; } /* type specific get/sets @@ -507,14 +497,12 @@ static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value) BPY_BM_CHECK_INT(self); - param = PyLong_AsLong(value); - - if (param == -1 && PyErr_Occurred()) { - PyErr_SetString(PyExc_TypeError, - "expected an int type"); + if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) { + /* error is set */ return -1; } - else if ((param < 0) || (param > MAXMAT)) { + + if ((param < 0) || (param > MAXMAT)) { /* normally we clamp but in this case raise an error */ PyErr_SetString(PyExc_ValueError, "material index outside of usable range (0 - 32766)"); @@ -941,6 +929,8 @@ PyDoc_STRVAR(bpy_bmesh_from_object_doc, ); static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw) { + /* TODO: This doesn't work currently because of eval_ctx. */ +#if 0 static const char *kwlist[] = {"object", "scene", "deform", "render", "cage", "face_normals", NULL}; PyObject *py_object; PyObject *py_scene; @@ -1033,6 +1023,10 @@ static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject dm->release(dm); Py_RETURN_NONE; +#else + UNUSED_VARS(self, args, kw); +#endif + return NULL; } @@ -1047,6 +1041,13 @@ PyDoc_STRVAR(bpy_bmesh_from_mesh_doc, " :type use_shape_key: boolean\n" " :arg shape_key_index: The shape key index to use.\n" " :type shape_key_index: int\n" +"\n" +" .. note::\n" +"\n" +" Multiple calls can be used to join multiple meshes.\n" +"\n" +" Custom-data layers are only copied from ``mesh`` on initialization.\n" +" Further calls will copy custom-data to matching layers, layers missing on the target mesh wont be added.\n" ); static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw) { @@ -1111,15 +1112,16 @@ static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } - if (param) BM_mesh_select_flush(self->bm); - else BM_mesh_deselect_flush(self->bm); + if (param) { + BM_mesh_select_flush(self->bm); + } + else { + BM_mesh_deselect_flush(self->bm); + } Py_RETURN_NONE; } @@ -1299,10 +1301,7 @@ static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } @@ -1327,10 +1326,7 @@ static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value) BPY_BM_CHECK_OBJ(self); - param = PyLong_AsLong(value); - if (param != false && param != true) { - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + if ((param = PyC_Long_AsBool(value)) == -1) { return NULL; } diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 47dead028a4..e2241ade7f0 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -43,6 +43,7 @@ #include "../mathutils/mathutils.h" #include "../generic/python_utildefines.h" +#include "../generic/py_capi_utils.h" #include "BKE_customdata.h" @@ -116,6 +117,9 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc, PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc, "Accessor for paint mask layer.\n\ntype: :class:`BMLayerCollection`" ); +PyDoc_STRVAR(bpy_bmlayeraccess_collection__face_map_doc, +"FaceMap custom-data layer.\n\ntype: :class:`BMLayerCollection`" +); #ifdef WITH_FREESTYLE PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_edge_doc, "Accessor for Freestyle edge layer.\n\ntype: :class:`BMLayerCollection`" @@ -218,6 +222,7 @@ static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = { {(char *)"float", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT}, {(char *)"int", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT}, {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR}, + {(char *)"face_map", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__face_map_doc, (void *)CD_FACEMAP}, #ifdef WITH_FREESTYLE {(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_face_doc, (void *)CD_FREESTYLE_FACE}, @@ -983,6 +988,7 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) break; } case CD_PROP_INT: + case CD_FACEMAP: { ret = PyLong_FromLong(*(int *)value); break; @@ -1063,10 +1069,11 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj break; } case CD_PROP_INT: + case CD_FACEMAP: { - int tmp_val = PyLong_AsLong(py_value); + int tmp_val = PyC_Long_AsI32(py_value); if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { - PyErr_Format(PyExc_TypeError, "expected an int, not a %.200s", Py_TYPE(py_value)->tp_name); + /* error is set */ ret = -1; } else { diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index f6926e8437d..574aef3d54f 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -45,6 +45,7 @@ #include "bmesh_py_types_meshdata.h" +#include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" /* Mesh Loop UV @@ -98,7 +99,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -106,8 +107,7 @@ static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } @@ -207,7 +207,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * { const int flag = GET_INT_FROM_POINTER(flag_p); - switch (PyLong_AsLong(value)) { + switch (PyC_Long_AsBool(value)) { case true: self->data->flag |= flag; return 0; @@ -215,8 +215,7 @@ static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void * self->data->flag &= ~flag; return 0; default: - PyErr_SetString(PyExc_TypeError, - "expected a boolean type 0/1"); + /* error is set */ return -1; } } diff --git a/source/blender/python/gawain/CMakeLists.txt b/source/blender/python/gawain/CMakeLists.txt new file mode 100644 index 00000000000..6b6c902f48a --- /dev/null +++ b/source/blender/python/gawain/CMakeLists.txt @@ -0,0 +1,47 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Campbell Barton +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../../blenkernel + ../../blenlib + ../../gpu + ../../makesdna + ../../../../intern/gawain + ../../../../intern/guardedalloc + ../../../../intern/glew-mx +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} + ${PYTHON_INCLUDE_DIRS} +) + +set(SRC + gwn_py_api.c + gwn_py_types.c + + gwn_py_api.h + gwn_py_types.h +) + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_python_gawain "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/python/gawain/gwn_py_api.c b/source/blender/python/gawain/gwn_py_api.c new file mode 100644 index 00000000000..d79ef070649 --- /dev/null +++ b/source/blender/python/gawain/gwn_py_api.c @@ -0,0 +1,63 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gawain/gwn_py_api.c + * \ingroup pygawain + * + * Experimental Python API, not considered public yet (called '_gawain'), + * we may re-expose as public later. + */ + +#include <Python.h> + +#include "gawain/gwn_batch.h" +#include "gawain/gwn_vertex_format.h" + +#include "gwn_py_api.h" +#include "gwn_py_types.h" + +#include "BLI_utildefines.h" + +#include "../generic/python_utildefines.h" + +PyDoc_STRVAR(GWN_doc, +"This module provides access to gawain drawing functions." +); +static struct PyModuleDef GWN_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "_gawain", /* m_name */ + .m_doc = GWN_doc, /* m_doc */ +}; + +PyObject *BPyInit_gawain(void) +{ + PyObject *sys_modules = PyThreadState_GET()->interp->modules; + PyObject *submodule; + PyObject *mod; + + mod = PyModule_Create(&GWN_module_def); + + /* _gawain.types */ + PyModule_AddObject(mod, "types", (submodule = BPyInit_gawain_types())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + Py_INCREF(submodule); + + return mod; +} diff --git a/source/blender/python/gawain/gwn_py_api.h b/source/blender/python/gawain/gwn_py_api.h new file mode 100644 index 00000000000..3ef85e8ae0f --- /dev/null +++ b/source/blender/python/gawain/gwn_py_api.h @@ -0,0 +1,30 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __GWN_PY_API_H__ +#define __GWN_PY_API_H__ + +/** \file blender/python/gawain/gwn_py_api.h + * \ingroup pygawain + */ + +PyObject *BPyInit_gawain(void); + +#endif /* __GWN_PY_API_H__ */ diff --git a/source/blender/python/gawain/gwn_py_types.c b/source/blender/python/gawain/gwn_py_types.c new file mode 100644 index 00000000000..cc448d9ed90 --- /dev/null +++ b/source/blender/python/gawain/gwn_py_types.c @@ -0,0 +1,823 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gawain/gwn_py_types.c + * \ingroup pygawain + * + * - Use ``bpygwn_`` for local API. + * - Use ``BPyGwn_`` for public API. + */ + +#include <Python.h> + +#include "gawain/gwn_batch.h" +#include "gawain/gwn_vertex_format.h" + +#include "BLI_math.h" + +#include "GPU_batch.h" + +#include "MEM_guardedalloc.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "gwn_py_types.h" /* own include */ + +#ifdef __BIG_ENDIAN__ + /* big endian */ +# define MAKE_ID2(c, d) ((c) << 8 | (d)) +# define MAKE_ID3(a, b, c) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 ) +# define MAKE_ID4(a, b, c, d) ( (int)(a) << 24 | (int)(b) << 16 | (c) << 8 | (d) ) +#else + /* little endian */ +# define MAKE_ID2(c, d) ((d) << 8 | (c)) +# define MAKE_ID3(a, b, c) ( (int)(c) << 16 | (b) << 8 | (a) ) +# define MAKE_ID4(a, b, c, d) ( (int)(d) << 24 | (int)(c) << 16 | (b) << 8 | (a) ) +#endif + +/* -------------------------------------------------------------------- */ + +/** \name Enum Conversion + * + * Use with PyArg_ParseTuple's "O&" formatting. + * \{ */ + +static int bpygwn_ParseVertCompType(PyObject *o, void *p) +{ + Py_ssize_t comp_type_id_len; + const char *comp_type_id = _PyUnicode_AsStringAndSize(o, &comp_type_id_len); + if (comp_type_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } + + Gwn_VertCompType comp_type; + if (comp_type_id_len == 2) { + switch (*((ushort *)comp_type_id)) { + case MAKE_ID2('I', '8'): { comp_type = GWN_COMP_I8; goto success; } + case MAKE_ID2('U', '8'): { comp_type = GWN_COMP_U8; goto success; } + } + } + else if (comp_type_id_len == 3) { + switch (*((uint *)comp_type_id)) { + case MAKE_ID3('I', '1', '6'): { comp_type = GWN_COMP_I16; goto success; } + case MAKE_ID3('U', '1', '6'): { comp_type = GWN_COMP_U16; goto success; } + case MAKE_ID3('I', '3', '2'): { comp_type = GWN_COMP_I32; goto success; } + case MAKE_ID3('U', '3', '2'): { comp_type = GWN_COMP_U32; goto success; } + case MAKE_ID3('F', '3', '2'): { comp_type = GWN_COMP_F32; goto success; } + case MAKE_ID3('I', '1', '0'): { comp_type = GWN_COMP_I10; goto success; } + } + } + + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + comp_type_id); + return 0; + +success: + *((Gwn_VertCompType *)p) = comp_type; + return 1; +} + +static int bpygwn_ParseVertFetchMode(PyObject *o, void *p) +{ + Py_ssize_t mode_id_len; + const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len); + if (mode_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } +#define MATCH_ID(id) \ + if (mode_id_len == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GWN_FETCH_##id; \ + goto success; \ + } \ + } ((void)0) + + Gwn_VertCompType mode; + MATCH_ID(FLOAT); + MATCH_ID(INT); + MATCH_ID(INT_TO_FLOAT_UNIT); + MATCH_ID(INT_TO_FLOAT); +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(Gwn_VertFetchMode *)p) = mode; + return 1; +} + +static int bpygwn_ParsePrimType(PyObject *o, void *p) +{ + Py_ssize_t mode_id_len; + const char *mode_id = _PyUnicode_AsStringAndSize(o, &mode_id_len); + if (mode_id == NULL) { + PyErr_Format(PyExc_ValueError, + "expected a string, got %s", + Py_TYPE(o)->tp_name); + return 0; + } +#define MATCH_ID(id) \ + if (mode_id_len == strlen(STRINGIFY(id))) { \ + if (STREQ(mode_id, STRINGIFY(id))) { \ + mode = GWN_PRIM_##id; \ + goto success; \ + } \ + } ((void)0) + + Gwn_PrimType mode; + MATCH_ID(POINTS); + MATCH_ID(LINES); + MATCH_ID(TRIS); + MATCH_ID(LINE_STRIP); + MATCH_ID(LINE_LOOP); + MATCH_ID(TRI_STRIP); + MATCH_ID(TRI_FAN); + MATCH_ID(LINE_STRIP_ADJ); + +#undef MATCH_ID + PyErr_Format(PyExc_ValueError, + "unknown type literal: '%s'", + mode_id); + return 0; + +success: + (*(Gwn_VertFetchMode *)p) = mode; + return 1; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Utility Functions + * \{ */ + +#define PY_AS_NATIVE_SWITCH(attr) \ + switch (attr->comp_type) { \ + case GWN_COMP_I8: { PY_AS_NATIVE(int8_t, PyC_Long_AsI8); break; } \ + case GWN_COMP_U8: { PY_AS_NATIVE(uint8_t, PyC_Long_AsU8); break; } \ + case GWN_COMP_I16: { PY_AS_NATIVE(int16_t, PyC_Long_AsI16); break; } \ + case GWN_COMP_U16: { PY_AS_NATIVE(uint16_t, PyC_Long_AsU16); break; } \ + case GWN_COMP_I32: { PY_AS_NATIVE(int32_t, PyC_Long_AsI32); break; } \ + case GWN_COMP_U32: { PY_AS_NATIVE(uint32_t, PyC_Long_AsU32); break; } \ + case GWN_COMP_F32: { PY_AS_NATIVE(float, PyFloat_AsDouble); break; } \ + default: \ + BLI_assert(0); \ + } ((void)0) + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_elem(void *data_dst_void, PyObject *py_src, const Gwn_VertAttr *attr) +{ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ +{ \ + ty_dst *data_dst = data_dst_void; \ + *data_dst = py_as_native(py_src); \ +} ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +/* No error checking, callers must run PyErr_Occurred */ +static void fill_format_tuple(void *data_dst_void, PyObject *py_src, const Gwn_VertAttr *attr) +{ + const uint len = attr->comp_ct; + +/** + * Args are constants, so range checks will be optimized out if they're nop's. + */ +#define PY_AS_NATIVE(ty_dst, py_as_native) \ + ty_dst *data_dst = data_dst_void; \ + for (uint i = 0; i < len; i++) { \ + data_dst[i] = py_as_native(PyTuple_GET_ITEM(py_src, i)); \ + } ((void)0) + + PY_AS_NATIVE_SWITCH(attr); + +#undef PY_AS_NATIVE +} + +#undef PY_AS_NATIVE_SWITCH +#undef WARN_TYPE_LIMIT_PUSH +#undef WARN_TYPE_LIMIT_POP + +static bool bpygwn_vertbuf_fill_impl( + Gwn_VertBuf *vbo, + uint data_id, PyObject *seq) +{ + bool ok = true; + const Gwn_VertAttr *attr = &vbo->format.attribs[data_id]; + + Gwn_VertBufRaw data_step; + GWN_vertbuf_attr_get_raw_data(vbo, data_id, &data_step); + + PyObject *seq_fast = PySequence_Fast(seq, "Vertex buffer fill"); + if (seq_fast == NULL) { + goto finally; + } + + const uint seq_len = PySequence_Fast_GET_SIZE(seq_fast); + + if (seq_len != vbo->vertex_ct) { + PyErr_Format(PyExc_ValueError, + "Expected a sequence of size %d, got %d", + vbo->vertex_ct, seq_len); + } + + PyObject **seq_items = PySequence_Fast_ITEMS(seq_fast); + + if (attr->comp_ct == 1) { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GWN_vertbuf_raw_step(&data_step); + PyObject *item = seq_items[i]; + fill_format_elem(data, item, attr); + } + } + else { + for (uint i = 0; i < seq_len; i++) { + uchar *data = (uchar *)GWN_vertbuf_raw_step(&data_step); + PyObject *item = seq_items[i]; + if (!PyTuple_CheckExact(item)) { + PyErr_Format(PyExc_ValueError, + "expected a tuple, got %s", + Py_TYPE(item)->tp_name); + ok = false; + goto finally; + } + if (PyTuple_GET_SIZE(item) != attr->comp_ct) { + PyErr_Format(PyExc_ValueError, + "expected a tuple of size %d, got %d", + attr->comp_ct, PyTuple_GET_SIZE(item)); + ok = false; + goto finally; + } + + /* May trigger error, check below */ + fill_format_tuple(data, item, attr); + } + } + + if (PyErr_Occurred()) { + ok = false; + } + +finally: + + Py_DECREF(seq_fast); + return ok; +} + +/* handy, but not used just now */ +#if 0 +static int bpygwn_find_id(const Gwn_VertFormat *fmt, const char *id) +{ + for (int i = 0; i < fmt->attrib_ct; i++) { + for (uint j = 0; j < fmt->name_ct; j++) { + if (STREQ(fmt->attribs[i].name[j], id)) { + return i; + } + } + } + return -1; +} +#endif + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertFormat Type + * \{ */ + +static PyObject *bpygwn_VertFormat_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + if (PyTuple_GET_SIZE(args) || (kwds && PyDict_Size(kwds))) { + PyErr_SetString(PyExc_TypeError, + "VertFormat(): takes no arguments"); + return NULL; + } + + BPyGwn_VertFormat *ret = (BPyGwn_VertFormat *)BPyGwn_VertFormat_CreatePyObject(NULL); + + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygwn_VertFormat_attr_add_doc, +"TODO" +); +static PyObject *bpygwn_VertFormat_attr_add(BPyGwn_VertFormat *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", "comp_type", "len", "fetch_mode", NULL}; + + struct { + const char *id; + Gwn_VertCompType comp_type; + uint len; + Gwn_VertFetchMode fetch_mode; + } params; + + if (self->fmt.attrib_ct == GWN_VERT_ATTR_MAX_LEN) { + PyErr_SetString(PyExc_ValueError, "Maxumum attr reached " STRINGIFY(GWN_VERT_ATTR_MAX_LEN)); + return NULL; + } + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "$sO&IO&:attr_add", (char **)kwlist, + ¶ms.id, + bpygwn_ParseVertCompType, ¶ms.comp_type, + ¶ms.len, + bpygwn_ParseVertFetchMode, ¶ms.fetch_mode)) + { + return NULL; + } + + uint attr_id = GWN_vertformat_attr_add(&self->fmt, params.id, params.comp_type, params.len, params.fetch_mode); + return PyLong_FromLong(attr_id); +} + +static struct PyMethodDef bpygwn_VertFormat_methods[] = { + {"attr_add", (PyCFunction)bpygwn_VertFormat_attr_add, + METH_VARARGS | METH_KEYWORDS, bpygwn_VertFormat_attr_add_doc}, + {NULL, NULL, 0, NULL} +}; + + +static void bpygwn_VertFormat_dealloc(BPyGwn_VertFormat *self) +{ + Py_TYPE(self)->tp_free(self); +} + +PyTypeObject BPyGwn_VertFormat_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "Gwn_VertFormat", + .tp_basicsize = sizeof(BPyGwn_VertFormat), + .tp_dealloc = (destructor)bpygwn_VertFormat_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = bpygwn_VertFormat_methods, + .tp_new = bpygwn_VertFormat_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertBuf Type + * \{ */ + +static PyObject *bpygwn_VertBuf_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + const char * const keywords[] = {"len", "format", NULL}; + + struct { + BPyGwn_VertFormat *py_fmt; + uint len; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "$IO!:Gwn_VertBuf.__new__", (char **)keywords, + ¶ms.len, + &BPyGwn_VertFormat_Type, ¶ms.py_fmt)) + { + return NULL; + } + + struct Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(¶ms.py_fmt->fmt); + + GWN_vertbuf_data_alloc(vbo, params.len); + + return BPyGwn_VertBuf_CreatePyObject(vbo); +} + +PyDoc_STRVAR(bpygwn_VertBuf_fill_doc, +"TODO" +); +static PyObject *bpygwn_VertBuf_fill(BPyGwn_VertBuf *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", "data", NULL}; + + struct { + uint id; + PyObject *py_seq_data; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "$IO:fill", (char **)kwlist, + ¶ms.id, + ¶ms.py_seq_data)) + { + return NULL; + } + + if (params.id >= self->buf->format.attrib_ct) { + PyErr_Format(PyExc_ValueError, + "Format id %d out of range", + params.id); + return NULL; + } + + if (self->buf->vbo_id != 0) { + PyErr_SetString(PyExc_ValueError, + "Can't fill, buffer already in use"); + return NULL; + } + + if (!bpygwn_vertbuf_fill_impl(self->buf, params.id, params.py_seq_data)) { + return NULL; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef bpygwn_VertBuf_methods[] = { + {"fill", (PyCFunction) bpygwn_VertBuf_fill, + METH_VARARGS | METH_KEYWORDS, bpygwn_VertBuf_fill_doc}, + {NULL, NULL, 0, NULL} +}; + +static void bpygwn_VertBuf_dealloc(BPyGwn_VertBuf *self) +{ + GWN_vertbuf_discard(self->buf); + Py_TYPE(self)->tp_free(self); +} + +PyTypeObject BPyGwn_VertBuf_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "Gwn_VertBuf", + .tp_basicsize = sizeof(BPyGwn_VertBuf), + .tp_dealloc = (destructor)bpygwn_VertBuf_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = bpygwn_VertBuf_methods, + .tp_new = bpygwn_VertBuf_new, +}; + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name VertBatch Type + * \{ */ + +static PyObject *bpygwn_Batch_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) +{ + const char * const keywords[] = {"type", "buf", NULL}; + + struct { + Gwn_PrimType type_id; + BPyGwn_VertBuf *py_buf; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, + "$O&O!:Gwn_Batch.__new__", (char **)keywords, + bpygwn_ParsePrimType, ¶ms.type_id, + &BPyGwn_VertBuf_Type, ¶ms.py_buf)) + { + return NULL; + } + + Gwn_Batch *batch = GWN_batch_create(params.type_id, params.py_buf->buf, NULL); + BPyGwn_Batch *ret = (BPyGwn_Batch *)BPyGwn_Batch_CreatePyObject(batch); + +#ifdef USE_GWN_PY_REFERENCES + ret->references = PyList_New(1); + PyList_SET_ITEM(ret->references, 0, (PyObject *)params.py_buf); + Py_INCREF(params.py_buf); + PyObject_GC_Track(ret); +#endif + + return (PyObject *)ret; +} + +PyDoc_STRVAR(bpygwn_VertBatch_vertbuf_add_doc, +"TODO" +); +static PyObject *bpygwn_VertBatch_vertbuf_add(BPyGwn_Batch *self, BPyGwn_VertBuf *py_buf) +{ + if (!BPyGwn_VertBuf_Check(py_buf)) { + PyErr_Format(PyExc_TypeError, + "Expected a Gwn_VertBuf, got %s", + Py_TYPE(py_buf)->tp_name); + return NULL; + } + + if (self->batch->verts[0]->vertex_ct != py_buf->buf->vertex_ct) { + PyErr_Format(PyExc_TypeError, + "Expected %d length, got %d", + self->batch->verts[0]->vertex_ct, py_buf->buf->vertex_ct); + return NULL; + } + +#ifdef USE_GWN_PY_REFERENCES + /* Hold user */ + PyList_Append(self->references, (PyObject *)py_buf); +#endif + + GWN_batch_vertbuf_add(self->batch, py_buf->buf); + Py_RETURN_NONE; +} + +/* Currently magic number from Py perspective. */ +PyDoc_STRVAR(bpygwn_VertBatch_program_set_builtin_doc, +"TODO" +); +static PyObject *bpygwn_VertBatch_program_set_builtin(BPyGwn_Batch *self, PyObject *args, PyObject *kwds) +{ + static const char *kwlist[] = {"id", NULL}; + + struct { + const char *shader; + } params; + + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "s:program_set_builtin", (char **)kwlist, + ¶ms.shader)) + { + return NULL; + } + + GPUBuiltinShader shader; + +#define MATCH_ID(id) \ + if (STREQ(params.shader, STRINGIFY(id))) { \ + shader = GPU_SHADER_##id; \ + goto success; \ + } ((void)0) + + MATCH_ID(2D_FLAT_COLOR); + MATCH_ID(2D_SMOOTH_COLOR); + MATCH_ID(2D_UNIFORM_COLOR); + + MATCH_ID(3D_FLAT_COLOR); + MATCH_ID(3D_SMOOTH_COLOR); + MATCH_ID(3D_UNIFORM_COLOR); + +#undef MATCH_ID + + PyErr_SetString(PyExc_ValueError, + "shader name not known"); + return NULL; + +success: + GWN_batch_program_set_builtin(self->batch, shader); + Py_RETURN_NONE; +} + +static PyObject *bpygwn_VertBatch_uniform_bool(BPyGwn_Batch *self, PyObject *args) +{ + struct { + const char *id; + bool values[1]; + } params; + + if (!PyArg_ParseTuple( + args, "sO&:uniform_bool", + ¶ms.id, + PyC_ParseBool, ¶ms.values[0])) + { + return NULL; + } + + GWN_batch_uniform_1b(self->batch, params.id, params.values[0]); + Py_RETURN_NONE; +} + +static PyObject *bpygwn_VertBatch_uniform_i32(BPyGwn_Batch *self, PyObject *args) +{ + struct { + const char *id; + int values[1]; + } params; + + if (!PyArg_ParseTuple( + args, "si:uniform_i32", + ¶ms.id, + ¶ms.values[0])) + { + return NULL; + } + + GWN_batch_uniform_1i(self->batch, params.id, params.values[0]); + Py_RETURN_NONE; +} + +static PyObject *bpygwn_VertBatch_uniform_f32(BPyGwn_Batch *self, PyObject *args) +{ + static struct { + const char *id; + float values[4]; + } params; + + if (!PyArg_ParseTuple( + args, "sf|fff:uniform_f32", + ¶ms.id, + ¶ms.values[0], ¶ms.values[1], ¶ms.values[2], ¶ms.values[3])) + { + return NULL; + } + + switch (PyTuple_GET_SIZE(args)) { + case 2: GWN_batch_uniform_1f(self->batch, params.id, params.values[0]); break; + case 3: GWN_batch_uniform_2fv(self->batch, params.id, params.values); break; + case 4: GWN_batch_uniform_3fv(self->batch, params.id, params.values); break; + case 5: GWN_batch_uniform_4fv(self->batch, params.id, params.values); break; + default: + BLI_assert(0); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(bpygwn_VertBatch_draw_doc, +"TODO" +); +static PyObject *bpygwn_VertBatch_draw(BPyGwn_Batch *self) +{ + if (!glIsProgram(self->batch->program)) { + PyErr_SetString(PyExc_ValueError, + "batch program has not not set"); + } + GWN_batch_draw(self->batch); + Py_RETURN_NONE; +} + +static struct PyMethodDef bpygwn_VertBatch_methods[] = { + {"vertbuf_add", (PyCFunction)bpygwn_VertBatch_vertbuf_add, + METH_O, bpygwn_VertBatch_vertbuf_add_doc}, + {"program_set_builtin", (PyCFunction)bpygwn_VertBatch_program_set_builtin, + METH_VARARGS | METH_KEYWORDS, bpygwn_VertBatch_program_set_builtin_doc}, + {"uniform_bool", (PyCFunction)bpygwn_VertBatch_uniform_bool, + METH_VARARGS, NULL}, + {"uniform_i32", (PyCFunction)bpygwn_VertBatch_uniform_i32, + METH_VARARGS, NULL}, + {"uniform_f32", (PyCFunction)bpygwn_VertBatch_uniform_f32, + METH_VARARGS, NULL}, + {"draw", (PyCFunction) bpygwn_VertBatch_draw, + METH_NOARGS, bpygwn_VertBatch_draw_doc}, + {NULL, NULL, 0, NULL} +}; + +#ifdef USE_GWN_PY_REFERENCES + +static int bpygwn_Batch_traverse(BPyGwn_Batch *self, visitproc visit, void *arg) +{ + Py_VISIT(self->references); + return 0; +} + +static int bpygwn_Batch_clear(BPyGwn_Batch *self) +{ + Py_CLEAR(self->references); + return 0; +} + +#endif + +static void bpygwn_Batch_dealloc(BPyGwn_Batch *self) +{ + GWN_batch_discard(self->batch); + +#ifdef USE_GWN_PY_REFERENCES + if (self->references) { + PyObject_GC_UnTrack(self); + bpygwn_Batch_clear(self); + Py_XDECREF(self->references); + } +#endif + + Py_TYPE(self)->tp_free(self); +} + +PyTypeObject BPyGwn_Batch_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "Gwn_Batch", + .tp_basicsize = sizeof(BPyGwn_Batch), + .tp_dealloc = (destructor)bpygwn_Batch_dealloc, +#ifdef USE_GWN_PY_REFERENCES + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)bpygwn_Batch_traverse, + .tp_clear = (inquiry)bpygwn_Batch_clear, +#else + .tp_flags = Py_TPFLAGS_DEFAULT, +#endif + .tp_methods = bpygwn_VertBatch_methods, + .tp_new = bpygwn_Batch_new, +}; + +/* -------------------------------------------------------------------- */ + + +/** \name Gawain Types Module + * \{ */ + +static struct PyModuleDef BPy_BM_types_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "_gawain.types", +}; + +PyObject *BPyInit_gawain_types(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPy_BM_types_module_def); + + if (PyType_Ready(&BPyGwn_VertFormat_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGwn_VertBuf_Type) < 0) + return NULL; + if (PyType_Ready(&BPyGwn_Batch_Type) < 0) + return NULL; + +#define MODULE_TYPE_ADD(s, t) \ + PyModule_AddObject(s, t.tp_name, (PyObject *)&t); Py_INCREF((PyObject *)&t) + + MODULE_TYPE_ADD(submodule, BPyGwn_VertFormat_Type); + MODULE_TYPE_ADD(submodule, BPyGwn_VertBuf_Type); + MODULE_TYPE_ADD(submodule, BPyGwn_Batch_Type); + +#undef MODULE_TYPE_ADD + + return submodule; +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Public API + * \{ */ + +PyObject *BPyGwn_VertFormat_CreatePyObject(Gwn_VertFormat *fmt) +{ + BPyGwn_VertFormat *self; + + self = PyObject_New(BPyGwn_VertFormat, &BPyGwn_VertFormat_Type); + if (fmt) { + self->fmt = *fmt; + } + else { + memset(&self->fmt, 0, sizeof(self->fmt)); + } + + return (PyObject *)self; +} + +PyObject *BPyGwn_VertBuf_CreatePyObject(Gwn_VertBuf *buf) +{ + BPyGwn_VertBuf *self; + + self = PyObject_New(BPyGwn_VertBuf, &BPyGwn_VertBuf_Type); + self->buf = buf; + + return (PyObject *)self; +} + + +PyObject *BPyGwn_Batch_CreatePyObject(Gwn_Batch *batch) +{ + BPyGwn_Batch *self; + +#ifdef USE_GWN_PY_REFERENCES + self = (BPyGwn_Batch *)_PyObject_GC_New(&BPyGwn_Batch_Type); + self->references = NULL; +#else + self = PyObject_New(BPyGwn_Batch, &BPyGwn_Batch_Type); +#endif + + self->batch = batch; + + return (PyObject *)self; +} + +/** \} */ diff --git a/source/blender/python/gawain/gwn_py_types.h b/source/blender/python/gawain/gwn_py_types.h new file mode 100644 index 00000000000..dde6cf98827 --- /dev/null +++ b/source/blender/python/gawain/gwn_py_types.h @@ -0,0 +1,67 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/gawain/gwn_py_types.h + * \ingroup pygawain + */ + +#ifndef __GWN_PY_TYPES_H__ +#define __GWN_PY_TYPES_H__ + +#include "BLI_compiler_attrs.h" + +#define USE_GWN_PY_REFERENCES + +extern PyTypeObject BPyGwn_VertFormat_Type; +extern PyTypeObject BPyGwn_VertBuf_Type; +extern PyTypeObject BPyGwn_Batch_Type; + +#define BPyGwn_VertFormat_Check(v) (Py_TYPE(v) == &BPyGwn_VertFormat_Type) +#define BPyGwn_VertBuf_Check(v) (Py_TYPE(v) == &BPyGwn_VertBuf_Type) +#define BPyGwn_Batch_Check(v) (Py_TYPE(v) == &BPyGwn_Batch_Type) + +typedef struct BPyGwn_VertFormat { + PyObject_VAR_HEAD + struct Gwn_VertFormat fmt; +} BPyGwn_VertFormat; + +typedef struct BPyGwn_VertBuf { + PyObject_VAR_HEAD + /* The buf is owned, we may support thin wrapped batches later. */ + struct Gwn_VertBuf *buf; +} BPyGwn_VertBuf; + +typedef struct BPyGwn_Batch { + PyObject_VAR_HEAD + /* The batch is owned, we may support thin wrapped batches later. */ + struct Gwn_Batch *batch; +#ifdef USE_GWN_PY_REFERENCES + /* Just to keep a user to prevent freeing buf's we're using */ + PyObject *references; +#endif +} BPyGwn_Batch; + +PyObject *BPyInit_gawain_types(void); + +PyObject *BPyGwn_VertFormat_CreatePyObject(struct Gwn_VertFormat *fmt); +PyObject *BPyGwn_VertBuf_CreatePyObject(struct Gwn_VertBuf *vbo) ATTR_NONNULL(1); +PyObject *BPyGwn_Batch_CreatePyObject(struct Gwn_Batch *batch) ATTR_NONNULL(1); + +#endif /* __GWN_PY_TYPES_H__ */ diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index ed4726e2ab7..5c938ef2ee3 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -476,6 +476,49 @@ int BGL_typeSize(int type) return -1; } +static int gl_buffer_type_from_py_format_char(char *typestr) +{ + if (ELEM(typestr[0], '<', '>', '|')) { + typestr += 1; + } + char format = typestr[0]; + char byte_num = typestr[1]; + + switch (format) { + case 't': + case 'b': + case 'h': + if (!byte_num) return GL_BYTE; + ATTR_FALLTHROUGH; + case 'i': + if (!byte_num) return GL_SHORT; + ATTR_FALLTHROUGH; + case 'l': + if (!byte_num || byte_num == '4') return GL_INT; + if (byte_num == '1') return GL_BYTE; + if (byte_num == '2') return GL_SHORT; + break; + case 'f': + if (!byte_num) return GL_FLOAT; + ATTR_FALLTHROUGH; + case 'd': + if (!byte_num || byte_num == '8') return GL_DOUBLE; + if (byte_num == '4') return GL_FLOAT; + break; + } + return -1; /* UNKNOWN */ +} + +static bool compare_dimensions(int ndim, int *dim1, Py_ssize_t *dim2) +{ + for (int i = 0; i < ndim; i++) { + if (dim1[i] != dim2[i]) { + return false; + } + } + return true; +} + /** \} */ @@ -634,6 +677,22 @@ PyTypeObject BGL_bufferType = { NULL /*tp_del*/ }; + +static Buffer *BGL_MakeBuffer_FromData(PyObject *parent, int type, int ndimensions, int *dimensions, void *buf) +{ + Buffer *buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); + + Py_XINCREF(parent); + buffer->parent = parent; + buffer->ndimensions = ndimensions; + buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); + memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); + buffer->type = type; + buffer->buf.asvoid = buf; + + return buffer; +} + /** * Create a buffer object * @@ -645,30 +704,21 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf { Buffer *buffer; void *buf = NULL; - int i, size, length; + int i, size = BGL_typeSize(type); - length = 1; for (i = 0; i < ndimensions; i++) { - length *= dimensions[i]; + size *= dimensions[i]; } - size = BGL_typeSize(type); + buf = MEM_mallocN(size, "Buffer buffer"); - buf = MEM_mallocN(length * size, "Buffer buffer"); - - buffer = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - buffer->parent = NULL; - buffer->ndimensions = ndimensions; - buffer->dimensions = MEM_mallocN(ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(buffer->dimensions, dimensions, ndimensions * sizeof(int)); - buffer->type = type; - buffer->buf.asvoid = buf; + buffer = BGL_MakeBuffer_FromData(NULL, type, ndimensions, dimensions, buf); if (initbuffer) { - memcpy(buffer->buf.asvoid, initbuffer, length * size); + memcpy(buffer->buf.asvoid, initbuffer, size); } else { - memset(buffer->buf.asvoid, 0, length * size); + memset(buffer->buf.asvoid, 0, size); } return buffer; } @@ -678,7 +728,7 @@ Buffer *BGL_MakeBuffer(int type, int ndimensions, int *dimensions, void *initbuf static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *length_ob = NULL, *init = NULL; - Buffer *buffer; + Buffer *buffer = NULL; int dimensions[MAX_DIMENSIONS]; int type; @@ -743,9 +793,32 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject return NULL; } - buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); - if (init && ndimensions) { - if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) { + if (init && PyObject_CheckBuffer(init)) { + Py_buffer pybuffer; + + if (PyObject_GetBuffer(init, &pybuffer, PyBUF_ND | PyBUF_FORMAT) == -1) { + /* PyObject_GetBuffer raise a PyExc_BufferError */ + return NULL; + } + + if (type != gl_buffer_type_from_py_format_char(pybuffer.format)) { + PyErr_Format(PyExc_TypeError, + "`GL_TYPE` and `typestr` of object with buffer interface do not match. '%s'", pybuffer.format); + } + else if (ndimensions != pybuffer.ndim || + !compare_dimensions(ndimensions, dimensions, pybuffer.shape)) + { + PyErr_Format(PyExc_TypeError, "array size does not match"); + } + else { + buffer = BGL_MakeBuffer_FromData(init, type, pybuffer.ndim, dimensions, pybuffer.buf); + } + + PyBuffer_Release(&pybuffer); + } + else { + buffer = BGL_MakeBuffer(type, ndimensions, dimensions, NULL); + if (init && Buffer_ass_slice(buffer, 0, dimensions[0], init)) { Py_DECREF(buffer); return NULL; } @@ -778,27 +851,17 @@ static PyObject *Buffer_item(Buffer *self, int i) } } else { - Buffer *newbuf; - int j, length, size; + int j, offset = i * BGL_typeSize(self->type); - length = 1; for (j = 1; j < self->ndimensions; j++) { - length *= self->dimensions[j]; + offset *= self->dimensions[j]; } - size = BGL_typeSize(self->type); - - newbuf = (Buffer *)PyObject_NEW(Buffer, &BGL_bufferType); - - Py_INCREF(self); - newbuf->parent = (PyObject *)self; - - newbuf->ndimensions = self->ndimensions - 1; - newbuf->type = self->type; - newbuf->buf.asvoid = self->buf.asbyte + i * length * size; - newbuf->dimensions = MEM_mallocN(newbuf->ndimensions * sizeof(int), "Buffer dimensions"); - memcpy(newbuf->dimensions, self->dimensions + 1, newbuf->ndimensions * sizeof(int)); - return (PyObject *)newbuf; + return (PyObject *)BGL_MakeBuffer_FromData( + (PyObject *)self, self->type, + self->ndimensions - 1, + self->dimensions + 1, + self->buf.asbyte + offset); } return NULL; diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c index ed2752d8372..ffac09efdde 100644 --- a/source/blender/python/generic/bpy_internal_import.c +++ b/source/blender/python/generic/bpy_internal_import.c @@ -248,8 +248,17 @@ PyObject *bpy_text_reimport(PyObject *module, int *found) if ((name = PyModule_GetName(module)) == NULL) return NULL; - if ((filepath = (char *)PyModule_GetFilename(module)) == NULL) - return NULL; + { + PyObject *module_file = PyModule_GetFilenameObject(module); + if (module_file == NULL) { + return NULL; + } + filepath = _PyUnicode_AsString(module_file); + Py_DECREF(module_file); + if (filepath == NULL) { + return NULL; + } + } /* look up the text object */ text = BLI_findstring(&maggie->text, BLI_path_basename(filepath), offsetof(ID, name) + 2); @@ -276,13 +285,13 @@ static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject int found = 0; PyObject *globals = NULL, *locals = NULL, *fromlist = NULL; int level = 0; /* relative imports */ - PyObject *newmodule; - //PyObject_Print(args, stderr, 0); - static const char *kwlist[] = {"name", "globals", "locals", "fromlist", "level", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|OOOi:bpy_import_meth", (char **)kwlist, - &name, &globals, &locals, &fromlist, &level)) + + static const char *_keywords[] = {"name", "globals", "locals", "fromlist", "level", NULL}; + static _PyArg_Parser _parser = {"s|OOOi:bpy_import_meth", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &name, &globals, &locals, &fromlist, &level)) { return NULL; } diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index 5d6a7c578a2..1153e0176df 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -386,7 +386,7 @@ static IDProperty *idp_from_PyFloat(const char *name, PyObject *ob) static IDProperty *idp_from_PyLong(const char *name, PyObject *ob) { IDPropertyTemplate val = {0}; - val.i = _PyLong_AsInt(ob); + val.i = PyC_Long_AsI32(ob); if (val.i == -1 && PyErr_Occurred()) { return NULL; } @@ -499,7 +499,7 @@ static IDProperty *idp_from_PySequence_Fast(const char *name, PyObject *ob) prop_data = IDP_Array(prop); for (i = 0; i < val.array.len; i++) { item = ob_seq_fast_items[i]; - if (((prop_data[i] = _PyLong_AsInt(item)) == -1) && PyErr_Occurred()) { + if (((prop_data[i] = PyC_Long_AsI32(item)) == -1) && PyErr_Occurred()) { return NULL; } } @@ -1337,7 +1337,7 @@ static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value) } case IDP_INT: { - const int i = _PyLong_AsInt(value); + const int i = PyC_Long_AsI32(value); if (i == -1 && PyErr_Occurred()) { return -1; } diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 2e789d6d4b3..d49f9514b8c 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -85,7 +85,7 @@ int PyC_AsArray_FAST( /* could use is_double for 'long int' but no use now */ int *array_int = array; for (i = 0; i < length; i++) { - array_int[i] = PyLong_AsLong(value_fast_items[i]); + array_int[i] = PyC_Long_AsI32(value_fast_items[i]); } } else if (type == &PyBool_Type) { @@ -127,54 +127,52 @@ int PyC_AsArray( return ret; } +/* -------------------------------------------------------------------- */ +/** \name Typed Tuple Packing + * + * \note See #PyC_Tuple_Pack_* macros that take multiple arguments. + * + * \{ */ + /* array utility function */ -PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix) +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len) { - PyObject *tuple; - int i; - - tuple = PyTuple_New(length); - - /* for each type */ - if (type == &PyFloat_Type) { - if (is_double) { - const double *array_double = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_double[i])); - } - } - else { - const float *array_float = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array_float[i])); - } - } - } - else if (type == &PyLong_Type) { - /* could use is_double for 'long int' but no use now */ - const int *array_int = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array_int[i])); - } + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyFloat_FromDouble(array[i])); } - else if (type == &PyBool_Type) { - const int *array_bool = array; - for (i = 0; i < length; ++i) { - PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array_bool[i])); - } + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyLong_FromLong(array[i])); } - else { - Py_DECREF(tuple); - PyErr_Format(PyExc_TypeError, - "%s: internal error %s is invalid", - error_prefix, type->tp_name); - return NULL; + return tuple; +} + +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); } + return tuple; +} +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len) +{ + PyObject *tuple = PyTuple_New(len); + for (uint i = 0; i < len; i++) { + PyTuple_SET_ITEM(tuple, i, PyBool_FromLong(array[i])); + } return tuple; } +/** \} */ + /** * Caller needs to ensure tuple is uninitialized. * Handy for filling a tuple with None for eg. @@ -203,6 +201,8 @@ void PyC_List_Fill(PyObject *list, PyObject *value) /** * Use with PyArg_ParseTuple's "O&" formatting. + * + * \see #PyC_Long_AsBool for a similar function to use outside of argument parsing. */ int PyC_ParseBool(PyObject *o, void *p) { @@ -300,7 +300,14 @@ void PyC_FileAndNum(const char **filename, int *lineno) if (mod_name) { PyObject *mod = PyDict_GetItem(PyImport_GetModuleDict(), mod_name); if (mod) { - *filename = PyModule_GetFilename(mod); + PyObject *mod_file = PyModule_GetFilenameObject(mod); + if (mod_file) { + *filename = _PyUnicode_AsString(mod_name); + Py_DECREF(mod_file); + } + else { + PyErr_Clear(); + } } /* unlikely, fallback */ @@ -1108,3 +1115,101 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val } #endif /* #ifndef MATH_STANDALONE */ + +/* -------------------------------------------------------------------- */ + +/** \name Int Conversion + * + * \note Python doesn't provide overflow checks for specific bit-widths. + * + * \{ */ + +/* Compiler optimizes out redundant checks. */ +#ifdef __GNUC__ +# pragma warning(push) +# pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * Don't use `bool` return type, so -1 can be used as an error value. + */ +int PyC_Long_AsBool(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY((uint)test > 1)) { + PyErr_SetString(PyExc_TypeError, + "Python number not a bool (0/1)"); + return -1; + } + return test; +} + +int8_t PyC_Long_AsI8(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT8_MIN || test > INT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int8"); + return -1; + } + return (int8_t)test; +} + +int16_t PyC_Long_AsI16(PyObject *value) +{ + int test = _PyLong_AsInt(value); + if (UNLIKELY(test < INT16_MIN || test > INT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C int16"); + return -1; + } + return (int16_t)test; +} + +/* Inlined in header: + * PyC_Long_AsI32 + * PyC_Long_AsI64 + */ + +uint8_t PyC_Long_AsU8(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT8_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint8"); + return (uint8_t)-1; + } + return (uint8_t)test; +} + +uint16_t PyC_Long_AsU16(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT16_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint16"); + return (uint16_t)-1; + } + return (uint16_t)test; +} + +uint32_t PyC_Long_AsU32(PyObject *value) +{ + ulong test = PyLong_AsUnsignedLong(value); + if (UNLIKELY(test > UINT32_MAX)) { + PyErr_SetString(PyExc_OverflowError, + "Python int too large to convert to C uint32"); + return (uint32_t)-1; + } + return (uint32_t)test; +} + +/* Inlined in header: + * PyC_Long_AsU64 + */ + +#ifdef __GNUC__ +# pragma warning(pop) +#endif + +/** \} */ diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h index 3f89e1d82a0..327d4e60954 100644 --- a/source/blender/python/generic/py_capi_utils.h +++ b/source/blender/python/generic/py_capi_utils.h @@ -24,10 +24,12 @@ * \ingroup pygen */ - #ifndef __PY_CAPI_UTILS_H__ #define __PY_CAPI_UTILS_H__ +#include "BLI_sys_types.h" +#include "BLI_utildefines_variadic.h" + void PyC_ObSpit(const char *name, PyObject *var); void PyC_LineSpit(void); void PyC_StackSpit(void); @@ -44,8 +46,21 @@ int PyC_AsArray_FAST( int PyC_AsArray( void *array, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const bool is_double, const char *error_prefix); -PyObject * PyC_FromArray(const void *array, int length, const PyTypeObject *type, - const bool is_double, const char *error_prefix); + +PyObject *PyC_Tuple_PackArray_F32(const float *array, uint len); +PyObject *PyC_Tuple_PackArray_I32(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len); +PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len); + +#define PyC_Tuple_Pack_F32(...) \ + PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32(...) \ + PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_I32FromBool(...) \ + PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) +#define PyC_Tuple_Pack_Bool(...) \ + PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) + void PyC_Tuple_Fill(PyObject *tuple, PyObject *value); void PyC_List_Fill(PyObject *list, PyObject *value); @@ -85,4 +100,26 @@ bool PyC_RunString_AsString(const char *expr, const char *filename, char **r_val int PyC_ParseBool(PyObject *o, void *p); + +/* Integer parsing (with overflow checks), -1 on error. */ +int PyC_Long_AsBool(PyObject *value); +int8_t PyC_Long_AsI8(PyObject *value); +int16_t PyC_Long_AsI16(PyObject *value); +#if 0 /* inline */ +int32_t PyC_Long_AsI32(PyObject *value); +int64_t PyC_Long_AsI64(PyObject *value); +#endif + +uint8_t PyC_Long_AsU8(PyObject *value); +uint16_t PyC_Long_AsU16(PyObject *value); +uint32_t PyC_Long_AsU32(PyObject *value); +#if 0 /* inline */ +uint64_t PyC_Long_AsU64(PyObject *value); +#endif + +/* inline so type signatures match as expected */ +Py_LOCAL_INLINE(int32_t) PyC_Long_AsI32(PyObject *value) { return (int32_t)_PyLong_AsInt(value); } +Py_LOCAL_INLINE(int64_t) PyC_Long_AsI64(PyObject *value) { return (int64_t)PyLong_AsLongLong(value); } +Py_LOCAL_INLINE(uint64_t) PyC_Long_AsU64(PyObject *value) { return (uint64_t)PyLong_AsUnsignedLongLong(value); } + #endif /* __PY_CAPI_UTILS_H__ */ diff --git a/source/blender/python/generic/python_utildefines.h b/source/blender/python/generic/python_utildefines.h index f7d3e7a8b4a..2d2d19c05f5 100644 --- a/source/blender/python/generic/python_utildefines.h +++ b/source/blender/python/generic/python_utildefines.h @@ -36,16 +36,16 @@ extern "C" { PyTupleObject *op = (PyTupleObject *)op_arg; \ PyObject **ob_items = op->ob_item; \ CHECK_TYPE_ANY(op_arg, PyObject *, PyTupleObject *); \ - BLI_assert(_VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ + BLI_assert(VA_NARGS_COUNT(__VA_ARGS__) == PyTuple_GET_SIZE(op)); \ ARRAY_SET_ITEMS(ob_items, __VA_ARGS__); \ } (void)0 /* wrap Py_INCREF & return the result, * use sparingly to avoid comma operator or temp var assignment */ -BLI_INLINE PyObject *Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } +Py_LOCAL_INLINE(PyObject *)Py_INCREF_RET(PyObject *op) { Py_INCREF(op); return op; } /* append & transfer ownership to the list, avoids inline Py_DECREF all over (which is quite a large macro) */ -BLI_INLINE int PyList_APPEND(PyObject *op, PyObject *v) +Py_LOCAL_INLINE(int) PyList_APPEND(PyObject *op, PyObject *v) { int ret = PyList_Append(op, v); Py_DecRef(v); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 967e90d22cb..26fbc5d9eb2 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -47,6 +47,8 @@ set(INC_SYS set(SRC gpu.c gpu_offscreen.c + gpu_py_matrix.c + gpu_py_select.c bpy.c bpy_app.c bpy_app_alembic.c @@ -151,10 +153,6 @@ if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) endif() -if(WITH_CODEC_QUICKTIME) - add_definitions(-DWITH_QUICKTIME) -endif() - if(WITH_CODEC_SNDFILE) add_definitions(-DWITH_SNDFILE) endif() diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 4a29d4f8da1..c576786a54c 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -119,10 +119,11 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec bool absolute = false; bool packed = false; bool local = false; - static const char *kwlist[] = {"absolute", "packed", "local", NULL}; - if (!PyArg_ParseTupleAndKeywords( - args, kw, "|O&O&O&:blend_paths", (char **)kwlist, + static const char *_keywords[] = {"absolute", "packed", "local", NULL}; + static _PyArg_Parser _parser = {"|O&O&O&:blend_paths", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, PyC_ParseBool, &absolute, PyC_ParseBool, &packed, PyC_ParseBool, &local)) @@ -148,13 +149,18 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj const char *type; const char *subdir = NULL; int folder_id; - static const char *kwlist[] = {"type", "subdir", NULL}; const char *path; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|s:user_resource", (char **)kwlist, &type, &subdir)) + static const char *_keywords[] = {"type", "subdir", NULL}; + static _PyArg_Parser _parser = {"s|s:user_resource", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &type, &subdir)) + { return NULL; - + } + /* stupid string compare */ if (STREQ(type, "DATAFILES")) folder_id = BLENDER_USER_DATAFILES; else if (STREQ(type, "CONFIG")) folder_id = BLENDER_USER_CONFIG; @@ -192,12 +198,17 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj { const char *type; int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100; - static const char *kwlist[] = {"type", "major", "minor", NULL}; int folder_id; const char *path; - if (!PyArg_ParseTupleAndKeywords(args, kw, "s|ii:resource_path", (char **)kwlist, &type, &major, &minor)) + static const char *_keywords[] = {"type", "major", "minor", NULL}; + static _PyArg_Parser _parser = {"s|ii:resource_path", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &type, &major, &minor)) + { return NULL; + } /* stupid string compare */ if (STREQ(type, "USER")) folder_id = BLENDER_RESOURCE_PATH_USER; diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 8b3464173d2..f44401afd7d 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -89,6 +89,7 @@ static PyStructSequence_Field app_info_fields[] = { {(char *)"version_cycle", (char *)"The release status of this build alpha/beta/rc/release"}, {(char *)"binary_path", (char *)"The location of blenders executable, useful for utilities that spawn new instances"}, {(char *)"background", (char *)"Boolean, True when blender is running without a user interface (started with -b)"}, + {(char *)"factory_startup", (char *)"Boolean, True when blender is running with --factory-startup)"}, /* buildinfo */ {(char *)"build_date", (char *)"The date this blender instance was built"}, @@ -156,8 +157,7 @@ static PyObject *make_app_info(void) #define SetObjItem(obj) \ PyStructSequence_SET_ITEM(app_info, pos++, obj) - SetObjItem(Py_BuildValue("(iii)", - BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); + SetObjItem(PyC_Tuple_Pack_I32(BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); SetObjItem(PyUnicode_FromFormat("%d.%02d (sub %d)", BLENDER_VERSION / 100, BLENDER_VERSION % 100, BLENDER_SUBVERSION)); @@ -165,6 +165,7 @@ static PyObject *make_app_info(void) SetStrItem(STRINGIFY(BLENDER_VERSION_CYCLE)); SetStrItem(BKE_appdir_program_path()); SetObjItem(PyBool_FromLong(G.background)); + SetObjItem(PyBool_FromLong(G.factory_startup)); /* build info, use bytes since we can't assume _any_ encoding: * see patch [#30154] for issue */ @@ -290,7 +291,7 @@ static PyObject *bpy_app_debug_value_get(PyObject *UNUSED(self), void *UNUSED(cl static int bpy_app_debug_value_set(PyObject *UNUSED(self), PyObject *value, void *UNUSED(closure)) { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "bpy.app.debug_value can only be set to a whole number"); diff --git a/source/blender/python/intern/bpy_app_alembic.c b/source/blender/python/intern/bpy_app_alembic.c index 90e6a02b418..2a1a031a629 100644 --- a/source/blender/python/intern/bpy_app_alembic.c +++ b/source/blender/python/intern/bpy_app_alembic.c @@ -34,6 +34,8 @@ #include "bpy_app_alembic.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_ALEMBIC # include "ABC_alembic.h" #endif @@ -79,11 +81,11 @@ static PyObject *make_alembic_info(void) const int patch = curversion - ((curversion / 100 ) * 100); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", major, minor, patch)); + SetObjItem(PyC_Tuple_Pack_I32(major, minor, patch)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", major, minor, patch)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index a6b98567a9a..501e09dd6ad 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -37,7 +37,6 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"bullet", NULL}, {(char *)"codec_avi", NULL}, {(char *)"codec_ffmpeg", NULL}, - {(char *)"codec_quicktime", NULL}, {(char *)"codec_sndfile", NULL}, {(char *)"compositor", NULL}, {(char *)"cycles", NULL}, @@ -112,12 +111,6 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif -#ifdef WITH_QUICKTIME - SetObjIncref(Py_True); -#else - SetObjIncref(Py_False); -#endif - #ifdef WITH_SNDFILE SetObjIncref(Py_True); #else diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c index fd516e4547f..9f8355db72b 100644 --- a/source/blender/python/intern/bpy_app_ffmpeg.c +++ b/source/blender/python/intern/bpy_app_ffmpeg.c @@ -29,6 +29,8 @@ #include "bpy_app_ffmpeg.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_FFMPEG #include <libavcodec/avcodec.h> #include <libavdevice/avdevice.h> @@ -91,8 +93,7 @@ static PyObject *make_ffmpeg_info(void) #ifdef WITH_FFMPEG # define FFMPEG_LIB_VERSION(lib) { \ curversion = lib ## _version(); \ - SetObjItem(Py_BuildValue("(iii)", \ - curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", \ curversion >> 16, (curversion >> 8) % 256, curversion % 256)); \ } (void)0 diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c index 02e4044219a..9997e6b87f1 100644 --- a/source/blender/python/intern/bpy_app_ocio.c +++ b/source/blender/python/intern/bpy_app_ocio.c @@ -29,6 +29,8 @@ #include "bpy_app_ocio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OCIO # include "ocio_capi.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_ocio_info(void) #ifdef WITH_OCIO curversion = OCIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c index 60daf3ddd8b..e14b48ff7cf 100644 --- a/source/blender/python/intern/bpy_app_oiio.c +++ b/source/blender/python/intern/bpy_app_oiio.c @@ -29,6 +29,8 @@ #include "bpy_app_oiio.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENIMAGEIO # include "openimageio_api.h" #endif @@ -74,13 +76,12 @@ static PyObject *make_oiio_info(void) #ifdef WITH_OPENIMAGEIO curversion = OIIO_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_opensubdiv.c b/source/blender/python/intern/bpy_app_opensubdiv.c index 7f269baf2b0..096374794c9 100644 --- a/source/blender/python/intern/bpy_app_opensubdiv.c +++ b/source/blender/python/intern/bpy_app_opensubdiv.c @@ -29,6 +29,8 @@ #include "bpy_app_opensubdiv.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" #endif @@ -70,13 +72,12 @@ static PyObject *make_opensubdiv_info(void) #ifdef WITH_OPENSUBDIV int curversion = openSubdiv_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion / 10000, (curversion / 100) % 100, curversion % 100)); + SetObjItem(PyC_Tuple_Pack_I32(curversion / 10000, (curversion / 100) % 100, curversion % 100)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_openvdb.c b/source/blender/python/intern/bpy_app_openvdb.c index 8a24aaf0555..0b385206d7b 100644 --- a/source/blender/python/intern/bpy_app_openvdb.c +++ b/source/blender/python/intern/bpy_app_openvdb.c @@ -34,6 +34,8 @@ #include "bpy_app_openvdb.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_OPENVDB # include "openvdb_capi.h" #endif @@ -79,13 +81,12 @@ static PyObject *make_openvdb_info(void) #ifdef WITH_OPENVDB curversion = OpenVDB_getVersionHex(); SetObjItem(PyBool_FromLong(1)); - SetObjItem(Py_BuildValue("(iii)", - curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); + SetObjItem(PyC_Tuple_Pack_I32(curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); SetObjItem(PyUnicode_FromFormat("%2d, %2d, %2d", curversion >> 24, (curversion >> 16) % 256, (curversion >> 8) % 256)); #else SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); #endif diff --git a/source/blender/python/intern/bpy_app_sdl.c b/source/blender/python/intern/bpy_app_sdl.c index 76dab775953..816ad2833cc 100644 --- a/source/blender/python/intern/bpy_app_sdl.c +++ b/source/blender/python/intern/bpy_app_sdl.c @@ -29,6 +29,8 @@ #include "bpy_app_sdl.h" +#include "../generic/py_capi_utils.h" + #ifdef WITH_SDL /* SDL force defines __SSE__ and __SSE2__ flags, which generates warnings * because we pass those defines via command line as well. For until there's @@ -103,7 +105,7 @@ static PyObject *make_sdl_info(void) # endif # endif - SetObjItem(Py_BuildValue("(iii)", version.major, version.minor, version.patch)); + SetObjItem(PyC_Tuple_Pack_I32(version.major, version.minor, version.patch)); if (sdl_available) { SetObjItem(PyUnicode_FromFormat("%d.%d.%d", version.major, version.minor, version.patch)); } @@ -114,7 +116,7 @@ static PyObject *make_sdl_info(void) #else // WITH_SDL=OFF SetObjItem(PyBool_FromLong(0)); - SetObjItem(Py_BuildValue("(iii)", 0, 0, 0)); + SetObjItem(PyC_Tuple_Pack_I32(0, 0, 0)); SetStrItem("Unknown"); SetObjItem(PyBool_FromLong(0)); #endif diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index cd4d2f7a1c2..7ddb41c3b0d 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -72,6 +72,7 @@ #include "../generic/bgl.h" #include "../generic/blf_py_api.h" #include "../generic/idprop_py_api.h" +#include "../gawain/gwn_py_api.h" #include "../bmesh/bmesh_py_api.h" #include "../mathutils/mathutils.h" @@ -212,6 +213,7 @@ static struct _inittab bpy_internal_modules[] = { {"mathutils.kdtree", PyInit_mathutils_kdtree}, #endif {"_bpy_path", BPyInit__bpy_path}, + {"_gawain", BPyInit_gawain}, {"bgl", BPyInit_bgl}, {"blf", BPyInit_blf}, {"bmesh", BPyInit_bmesh}, @@ -870,6 +872,7 @@ static void bpy_module_delay_init(PyObject *bpy_proxy) BLI_strncpy(filename_abs, filename_rel, sizeof(filename_abs)); BLI_path_cwd(filename_abs, sizeof(filename_abs)); + Py_DECREF(filename_obj); argv[0] = filename_abs; argv[1] = NULL; diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 73265d28a93..79081e47e27 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -73,7 +73,7 @@ typedef struct { } BPy_Library; static PyObject *bpy_lib_load(PyObject *self, PyObject *args, PyObject *kwds); -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *args); +static PyObject *bpy_lib_enter(BPy_Library *self); static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *args); static PyObject *bpy_lib_dir(BPy_Library *self); @@ -183,17 +183,17 @@ PyDoc_STRVAR(bpy_lib_load_doc, " :arg relative: When True the path is stored relative to the open blend file.\n" " :type relative: bool\n" ); -static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"filepath", "link", "relative", NULL}; Main *bmain = CTX_data_main(BPy_GetContext()); BPy_Library *ret; const char *filename = NULL; bool is_rel = false, is_link = false; - if (!PyArg_ParseTupleAndKeywords( - args, kwds, - "s|O&O&:load", (char **)kwlist, + static const char *_keywords[] = {"filepath", "link", "relative", NULL}; + static _PyArg_Parser _parser = {"s|O&O&:load", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &filename, PyC_ParseBool, &is_link, PyC_ParseBool, &is_rel)) @@ -237,7 +237,7 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) return list; } -static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) +static PyObject *bpy_lib_enter(BPy_Library *self) { PyObject *ret; BPy_Library *self_from; diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c index bf91253141a..c054183034a 100644 --- a/source/blender/python/intern/bpy_library_write.c +++ b/source/blender/python/intern/bpy_library_write.c @@ -69,24 +69,23 @@ PyDoc_STRVAR(bpy_lib_write_doc, " :arg compress: When True, write a compressed blend file.\n" " :type compress: bool\n" ); -static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +static PyObject *bpy_lib_write(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static const char *kwlist[] = { - "filepath", "datablocks", - /* optional */ - "relative_remap", "fake_user", "compress", - NULL, - }; - /* args */ const char *filepath; char filepath_abs[FILE_MAX]; PyObject *datablocks = NULL; bool use_relative_remap = false, use_fake_user = false, use_compress = false; - if (!PyArg_ParseTupleAndKeywords( - args, kwds, - "sO!|$O&O&O&:write", (char **)kwlist, + static const char *_keywords[] = { + "filepath", "datablocks", + /* optional */ + "relative_remap", "fake_user", "compress", + NULL, + }; + static _PyArg_Parser _parser = {"sO!|$O&O&O&:write", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &filepath, &PySet_Type, &datablocks, PyC_ParseBool, &use_relative_remap, diff --git a/source/blender/python/intern/bpy_manipulator_wrap.c b/source/blender/python/intern/bpy_manipulator_wrap.c index 53b6285e880..9df4e81ec55 100644 --- a/source/blender/python/intern/bpy_manipulator_wrap.c +++ b/source/blender/python/intern/bpy_manipulator_wrap.c @@ -58,8 +58,6 @@ static bool bpy_manipulatortype_target_property_def( { /* Note: names based on 'rna_rna.c' */ PyObject *empty_tuple = PyTuple_New(0); - static const char * const _keywords[] = {"id", "type", "array_length", NULL}; - static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0}; struct { char *id; @@ -72,6 +70,8 @@ static bool bpy_manipulatortype_target_property_def( .array_length = 1, }; + static const char * const _keywords[] = {"id", "type", "array_length", NULL}; + static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0}; if (!_PyArg_ParseTupleAndKeywordsFast( empty_tuple, item, &_parser, @@ -119,7 +119,7 @@ static void manipulator_properties_init(wmManipulatorType *wt) /* only call this so pyrna_deferred_register_class gives a useful error * WM_operatortype_append_ptr will call RNA_def_struct_identifier * later */ - RNA_def_struct_identifier(wt->srna, wt->idname); + RNA_def_struct_identifier_no_struct_map(wt->srna, wt->idname); if (pyrna_deferred_register_class(wt->srna, py_class) != 0) { PyErr_Print(); /* failed to register operator props */ @@ -132,27 +132,32 @@ static void manipulator_properties_init(wmManipulatorType *wt) * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal) - campbell */ PyObject *py_class_dict = py_class->tp_dict; PyObject *bl_target_properties = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_target_properties); - PyObject *bl_target_properties_fast; - - if (!(bl_target_properties_fast = PySequence_Fast(bl_target_properties, "bl_target_properties sequence"))) { - /* PySequence_Fast sets the error */ - PyErr_Print(); - PyErr_Clear(); - return; - } - const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast); - PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast); - - for (uint i = 0; i < items_len; i++) { - if (!bpy_manipulatortype_target_property_def(wt, items[i])) { + /* Some widgets may only exist to activate operators. */ + if (bl_target_properties != NULL) { + PyObject *bl_target_properties_fast; + if (!(bl_target_properties_fast = PySequence_Fast( + bl_target_properties, "bl_target_properties sequence"))) + { + /* PySequence_Fast sets the error */ PyErr_Print(); PyErr_Clear(); - break; + return; } - } - Py_DECREF(bl_target_properties_fast); + const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast); + PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast); + + for (uint i = 0; i < items_len; i++) { + if (!bpy_manipulatortype_target_property_def(wt, items[i])) { + PyErr_Print(); + PyErr_Clear(); + break; + } + } + + Py_DECREF(bl_target_properties_fast); + } } } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index bd3e5736c6c..c1fcb0792af 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -450,7 +450,7 @@ static PyObject *pyop_getinstance(PyObject *UNUSED(self), PyObject *value) op = PyMem_MALLOC(sizeof(wmOperator)); memset(op, 0, sizeof(wmOperator)); #endif - BLI_strncpy(op->idname, op->idname, sizeof(op->idname)); /* in case its needed */ + BLI_strncpy(op->idname, ot->idname, sizeof(op->idname)); /* in case its needed */ op->type = ot; RNA_pointer_create(NULL, &RNA_Operator, op, &ptr); diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index 90719905a79..9d57adca946 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -48,10 +48,12 @@ static void operator_properties_init(wmOperatorType *ot) PyTypeObject *py_class = ot->ext.data; RNA_struct_blender_type_set(ot->ext.srna, ot); - /* only call this so pyrna_deferred_register_class gives a useful error - * WM_operatortype_append_ptr will call RNA_def_struct_identifier - * later */ - RNA_def_struct_identifier(ot->srna, ot->idname); + /* Only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier later. + * + * Note the 'no_struct_map' function is used since the actual struct name is already used by the operator. + */ + RNA_def_struct_identifier_no_struct_map(ot->srna, ot->idname); if (pyrna_deferred_register_class(ot->srna, py_class) != 0) { PyErr_Print(); /* failed to register operator props */ diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index c7787ba9682..a46fda7ea63 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -320,7 +320,7 @@ static int bpy_prop_boolean_get_cb(struct PointerRNA *ptr, struct PropertyRNA *p value = false; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -530,12 +530,8 @@ static void bpy_prop_boolean_array_set_cb(struct PointerRNA *ptr, struct Propert self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyBool_Type, false, "BoolVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32FromBool(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -599,7 +595,7 @@ static int bpy_prop_int_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop) value = 0.0f; } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -764,12 +760,8 @@ static void bpy_prop_int_array_set_cb(struct PointerRNA *ptr, struct PropertyRNA self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyLong_Type, false, "IntVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_I32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -998,12 +990,8 @@ static void bpy_prop_float_array_set_cb(struct PointerRNA *ptr, struct PropertyR self = pyrna_struct_as_instance(ptr); PyTuple_SET_ITEM(args, 0, self); - py_values = PyC_FromArray(values, len, &PyFloat_Type, false, "FloatVectorProperty set"); - if (!py_values) { - printf_func_error(py_func); - } - else - PyTuple_SET_ITEM(args, 1, py_values); + py_values = PyC_Tuple_PackArray_F32(values, len); + PyTuple_SET_ITEM(args, 1, py_values); ret = PyObject_CallObject(py_func, args); @@ -1249,7 +1237,7 @@ static int bpy_prop_enum_get_cb(struct PointerRNA *ptr, struct PropertyRNA *prop value = RNA_property_enum_get_default(ptr, prop); } else { - value = PyLong_AsLong(ret); + value = PyC_Long_AsI32(ret); if (value == -1 && PyErr_Occurred()) { printf_func_error(py_func); @@ -2007,8 +1995,6 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(BoolProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "options", "subtype", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; bool def = false; @@ -2021,12 +2007,17 @@ static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssO&O!sOOO:BoolProperty", - (char **)kwlist, &id, &id_len, - &name, &description, PyC_ParseBool, &def, - &PySet_Type, &pyopts, &pysubtype, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "options", "subtype", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssO&O!sOOO:BoolProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, PyC_ParseBool, &def, + &PySet_Type, &pyopts, &pysubtype, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2089,8 +2080,6 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject BPY_PROPDEF_HEAD(BoolVectorProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "options", "subtype", "size", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; int def[PYRNA_STACK_ARRAY] = {0}; @@ -2105,12 +2094,17 @@ static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssOO!siOOO:BoolVectorProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &pydef, - &PySet_Type, &pyopts, &pysubtype, &size, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "options", "subtype", "size", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssOO!siOOO:BoolVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &pydef, + &PySet_Type, &pyopts, &pysubtype, &size, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2193,9 +2187,6 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(IntProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "min", "max", "soft_min", "soft_max", - "step", "options", "subtype", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1, def = 0; @@ -2208,13 +2199,19 @@ static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssiiiiiiO!sOOO:IntProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &def, - &min, &max, &soft_min, &soft_max, - &step, &PySet_Type, &pyopts, &pysubtype, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "min", "max", "soft_min", "soft_max", + "step", "options", "subtype", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssiiiiiiO!sOOO:IntProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &def, + &min, &max, &soft_min, &soft_max, + &step, &PySet_Type, &pyopts, &pysubtype, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2290,9 +2287,6 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject BPY_PROPDEF_HEAD(IntVectorProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "min", "max", "soft_min", "soft_max", - "step", "options", "subtype", "size", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; int min = INT_MIN, max = INT_MAX, soft_min = INT_MIN, soft_max = INT_MAX, step = 1; @@ -2308,14 +2302,20 @@ static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssOiiiiiO!siOOO:IntVectorProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &pydef, - &min, &max, &soft_min, &soft_max, - &step, &PySet_Type, &pyopts, - &pysubtype, &size, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "min", "max", "soft_min", "soft_max", + "step", "options", "subtype", "size", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssOiiiiiO!siOOO:IntVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &pydef, + &min, &max, &soft_min, &soft_max, + &step, &PySet_Type, &pyopts, + &pysubtype, &size, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2403,10 +2403,6 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(FloatProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "min", "max", "soft_min", "soft_max", - "step", "precision", "options", "subtype", - "unit", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3, def = 0.0f; @@ -2422,14 +2418,21 @@ static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssffffffiO!ssOOO:FloatProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &def, - &min, &max, &soft_min, &soft_max, - &step, &precision, &PySet_Type, - &pyopts, &pysubtype, &pyunit, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "min", "max", "soft_min", "soft_max", + "step", "precision", "options", "subtype", + "unit", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssffffffiO!ssOOO:FloatProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &def, + &min, &max, &soft_min, &soft_max, + &step, &precision, &PySet_Type, + &pyopts, &pysubtype, &pyunit, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2514,10 +2517,6 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec BPY_PROPDEF_HEAD(FloatVectorProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "min", "max", "soft_min", "soft_max", - "step", "precision", "options", "subtype", - "unit", "size", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; float min = -FLT_MAX, max = FLT_MAX, soft_min = -FLT_MAX, soft_max = FLT_MAX, step = 3; @@ -2535,14 +2534,21 @@ static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObjec PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|ssOfffffiO!ssiOOO:FloatVectorProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &pydef, - &min, &max, &soft_min, &soft_max, - &step, &precision, &PySet_Type, - &pyopts, &pysubtype, &pyunit, &size, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "min", "max", "soft_min", "soft_max", + "step", "precision", "options", "subtype", + "unit", "size", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|ssOfffffiO!ssiOOO:FloatVectorProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &pydef, + &min, &max, &soft_min, &soft_max, + &step, &precision, &PySet_Type, + &pyopts, &pysubtype, &pyunit, &size, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2623,8 +2629,6 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw BPY_PROPDEF_HEAD(StringProperty); if (srna) { - static const char *kwlist[] = {"attr", "name", "description", "default", - "maxlen", "options", "subtype", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = "", *def = ""; int id_len; int maxlen = 0; @@ -2637,12 +2641,17 @@ static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#|sssiO!sOOO:StringProperty", - (char **)kwlist, &id, &id_len, - &name, &description, &def, - &maxlen, &PySet_Type, &pyopts, &pysubtype, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "name", "description", "default", + "maxlen", "options", "subtype", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#|sssiO!sOOO:StringProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &name, &description, &def, + &maxlen, &PySet_Type, &pyopts, &pysubtype, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2697,7 +2706,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc, " :icon: An icon string identifier or integer icon value\n" " (e.g. returned by :class:`bpy.types.UILayout.icon`)\n" " :number: Unique value used as the identifier for this item (stored in file data).\n" -" Use when the identifier may need to change.\n" +" Use when the identifier may need to change. If the *ENUM_FLAG* option is used,\n" +" the values are bitmasks and should be powers of two.\n" "\n" " When an item only contains 4 items they define ``(identifier, name, description, number)``.\n" "\n" @@ -2731,8 +2741,6 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(EnumProperty); if (srna) { - static const char *kwlist[] = {"attr", "items", "name", "description", "default", - "options", "update", "get", "set", NULL}; const char *id = NULL, *name = NULL, *description = ""; PyObject *def = NULL; int id_len; @@ -2747,12 +2755,17 @@ static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw) PyObject *get_cb = NULL; PyObject *set_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssOO!OOO:EnumProperty", - (char **)kwlist, &id, &id_len, - &items, &name, &description, - &def, &PySet_Type, &pyopts, - &update_cb, &get_cb, &set_cb)) + static const char *_keywords[] = { + "attr", "items", "name", "description", "default", + "options", "update", "get", "set", NULL, + }; + static _PyArg_Parser _parser = {"s#O|ssOO!OOO:EnumProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &items, &name, &description, + &def, &PySet_Type, &pyopts, + &update_cb, &get_cb, &set_cb)) { return NULL; } @@ -2880,7 +2893,6 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(PointerProperty); if (srna) { - static const char *kwlist[] = {"attr", "type", "name", "description", "options", "poll", "update", NULL}; const char *id = NULL, *name = NULL, *description = ""; int id_len; PropertyRNA *prop; @@ -2890,12 +2902,16 @@ PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *kw) int opts = 0; PyObject *update_cb = NULL, *poll_cb = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssO!OOO:PointerProperty", - (char **)kwlist, &id, &id_len, - &type, &name, &description, - &PySet_Type, &pyopts, - &poll_cb, &update_cb)) + static const char *_keywords[] = { + "attr", "type", "name", "description", "options", "poll", "update", NULL, + }; + static _PyArg_Parser _parser = {"s#O|ssO!OO:PointerProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &type, &name, &description, + &PySet_Type, &pyopts, + &poll_cb, &update_cb)) { return NULL; } @@ -2954,20 +2970,23 @@ PyObject *BPy_CollectionProperty(PyObject *self, PyObject *args, PyObject *kw) BPY_PROPDEF_HEAD(CollectionProperty); if (srna) { - static const char *kwlist[] = {"attr", "type", "name", "description", "options", NULL}; - const char *id = NULL, *name = NULL, *description = ""; int id_len; + const char *id = NULL, *name = NULL, *description = ""; PropertyRNA *prop; StructRNA *ptype; PyObject *type = Py_None; PyObject *pyopts = NULL; int opts = 0; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s#O|ssO!:CollectionProperty", - (char **)kwlist, &id, &id_len, - &type, &name, &description, - &PySet_Type, &pyopts)) + static const char *_keywords[] = { + "attr", "type", "name", "description", "options", NULL, + }; + static _PyArg_Parser _parser = {"s#O|ssO!:CollectionProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id, &id_len, + &type, &name, &description, + &PySet_Type, &pyopts)) { return NULL; } @@ -3039,13 +3058,15 @@ static PyObject *BPy_RemoveProperty(PyObject *self, PyObject *args, PyObject *kw return NULL; } else { - static const char *kwlist[] = {"attr", NULL}; - const char *id = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kw, - "s:RemoveProperty", - (char **)kwlist, &id)) + static const char *_keywords[] = { + "attr", NULL, + }; + static _PyArg_Parser _parser = {"s:RemoveProperty", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &id)) { return NULL; } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 51e179fb317..02cb5233166 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -70,6 +70,8 @@ #include "BKE_report.h" #include "BKE_idprop.h" +/* only for types */ +#include "BKE_node.h" #include "../generic/idprop_py_api.h" /* for IDprop lookups */ #include "../generic/py_capi_utils.h" @@ -1395,7 +1397,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) } else { EnumPropertyItem *enum_item; - bool free = false; + bool free; /* don't throw error here, can't trust blender 100% to give the * right values, python code should not generate error for that */ @@ -1404,6 +1406,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val) ret = PyUnicode_FromString(enum_item->identifier); } else { + if (free) { + MEM_freeN(enum_item); + } RNA_property_enum_items(NULL, ptr, prop, &enum_item, NULL, &free); /* Do not print warning in case of DummyRNA_NULL_items, this one will never match any value... */ @@ -1640,7 +1645,7 @@ static int pyrna_py_to_prop( param = PyObject_IsTrue(value); } else { - param = PyLong_AsLong(value); + param = PyC_Long_AsI32(value); if (UNLIKELY(param & ~1)) { /* only accept 0/1 */ param = -1; /* error out below */ @@ -2085,10 +2090,10 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P switch (RNA_property_type(prop)) { case PROP_BOOLEAN: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsBool(value); - if (param < 0 || param > 1) { - PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1"); + if (param == -1) { + /* error is set */ ret = -1; } else { @@ -2098,7 +2103,7 @@ static int pyrna_py_to_prop_array_index(BPy_PropertyArrayRNA *self, int index, P } case PROP_INT: { - int param = PyLong_AsLong(value); + int param = PyC_Long_AsI32(value); if (param == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_TypeError, "expected an int type"); ret = -1; @@ -2718,7 +2723,7 @@ static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; - return pyrna_prop_array_subscript_int(self, PyLong_AsLong(key)); + return pyrna_prop_array_subscript_int(self, i); } else if (PySlice_Check(key)) { Py_ssize_t step = 1; @@ -3713,6 +3718,110 @@ static PyObject *pyrna_struct_type_recast(BPy_StructRNA *self) return pyrna_struct_CreatePyObject(&r_ptr); } +/** + * \note Return value is borrowed, caller must incref. + */ +static PyObject *pyrna_struct_bl_rna_find_subclass_recursive(PyObject *cls, const char *id) +{ + PyObject *ret_test = NULL; + PyObject *subclasses = ((PyTypeObject *)cls)->tp_subclasses; + if (subclasses) { + /* Unfortunately we can't use the dict key because Python class names + * don't match the bl_idname used internally. */ + BLI_assert(PyDict_CheckExact(subclasses)); + PyObject *key = NULL; + Py_ssize_t pos = 0; + PyObject *value = NULL; + while (PyDict_Next(subclasses, &pos, &key, &value)) { + BLI_assert(PyWeakref_CheckRef(value)); + PyObject *subcls = PyWeakref_GET_OBJECT(value); + if (subcls != Py_None) { + BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem( + ((PyTypeObject *)subcls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna) { + StructRNA *srna = py_srna->ptr.data; + if (STREQ(id, RNA_struct_identifier(srna))) { + ret_test = subcls; + break; + } + } + ret_test = pyrna_struct_bl_rna_find_subclass_recursive(subcls, id); + if (ret_test) { + break; + } + } + } + } + return ret_test; +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_py_doc, +".. classmethod:: bl_rna_get_subclass_py(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The class or default when not found.\n" +" :rtype: type\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass_py(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass_py", &id, &ret_default)) { + return NULL; + } + PyObject *ret = pyrna_struct_bl_rna_find_subclass_recursive(cls, id); + if (ret == NULL) { + ret = ret_default; + } + return Py_INCREF_RET(ret); +} + +PyDoc_STRVAR(pyrna_struct_bl_rna_get_subclass_doc, +".. classmethod:: bl_rna_get_subclass(id, default=None)\n" +"\n" +" :arg id: The RNA type identifier.\n" +" :type id: string\n" +" :return: The RNA type or default when not found.\n" +" :rtype: :class:`bpy.types.Struct` subclass\n" +); +static PyObject *pyrna_struct_bl_rna_get_subclass(PyObject *cls, PyObject *args) +{ + char *id; + PyObject *ret_default = Py_None; + + if (!PyArg_ParseTuple(args, "s|O:bl_rna_get_subclass", &id, &ret_default)) { + return NULL; + } + + + const BPy_StructRNA *py_srna = (BPy_StructRNA *)PyDict_GetItem(((PyTypeObject *)cls)->tp_dict, bpy_intern_str_bl_rna); + if (py_srna == NULL) { + PyErr_SetString(PyExc_ValueError, "Not a registered class"); + return NULL; + + } + const StructRNA *srna_base = py_srna->ptr.data; + + PointerRNA ptr; + if (srna_base == &RNA_Node) { + bNodeType *nt = nodeTypeFind(id); + if (nt) { + RNA_pointer_create(NULL, &RNA_Struct, nt->ext.srna, &ptr); + return pyrna_struct_CreatePyObject(&ptr); + } + } + else { + /* TODO, panels, menus etc. */ + PyErr_Format(PyExc_ValueError, "Class type \"%.200s\" not supported", + RNA_struct_identifier(srna_base)); + return NULL; + } + + return Py_INCREF_RET(ret_default); +} + static void pyrna_dir_members_py__add_keys(PyObject *list, PyObject *dict) { PyObject *list_tmp; @@ -5011,6 +5120,8 @@ static struct PyMethodDef pyrna_struct_methods[] = { {"path_resolve", (PyCFunction)pyrna_struct_path_resolve, METH_VARARGS, pyrna_struct_path_resolve_doc}, {"path_from_id", (PyCFunction)pyrna_struct_path_from_id, METH_VARARGS, pyrna_struct_path_from_id_doc}, {"type_recast", (PyCFunction)pyrna_struct_type_recast, METH_NOARGS, pyrna_struct_type_recast_doc}, + {"bl_rna_get_subclass_py", (PyCFunction) pyrna_struct_bl_rna_get_subclass_py, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_py_doc}, + {"bl_rna_get_subclass", (PyCFunction) pyrna_struct_bl_rna_get_subclass, METH_VARARGS | METH_CLASS, pyrna_struct_bl_rna_get_subclass_doc}, {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, /* experimental */ @@ -6657,7 +6768,30 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) if (ptr->data == NULL && ptr->type == NULL) { /* Operator RNA has NULL data */ Py_RETURN_NONE; } - else { + + /* New in 2.8x, since not many types support instancing + * we may want to use a flag to avoid looping over all classes. - campbell */ + void **instance = ptr->data ? RNA_struct_instance(ptr) : NULL; + if (instance && *instance) { + pyrna = *instance; + + /* Refine may have changed types after the first instance was created. */ + if (ptr->type == pyrna->ptr.type) { + Py_INCREF(pyrna); + return (PyObject *)pyrna; + } + else { + /* Existing users will need to use 'type_recast' method. */ + Py_DECREF(pyrna); + *instance = NULL; + /* Continue as if no instance was made */ +#if 0 /* no need to assign, will be written to next... */ + pyrna = NULL; +#endif + } + } + + { PyTypeObject *tp = (PyTypeObject *)pyrna_struct_Subtype(ptr); if (tp) { @@ -6678,6 +6812,12 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) return NULL; } + /* Blender's instance owns a reference (to avoid Python freeing it). */ + if (instance) { + *instance = pyrna; + Py_INCREF(pyrna); + } + pyrna->ptr = *ptr; #ifdef PYRNA_FREE_SUPPORT pyrna->freeptr = false; @@ -6933,15 +7073,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) RNA_PROP_BEGIN (&self->ptr, itemptr, self->prop) { StructRNA *srna = itemptr.data; - StructRNA *srna_base = RNA_struct_base(itemptr.data); - /* skip own operators, these double up [#29666] */ - if (ELEM(srna_base, &RNA_Operator, &RNA_Manipulator)) { - /* do nothing */ - } - else { - /* add to python list */ - PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); - } + PyList_APPEND(ret, PyUnicode_FromString(RNA_struct_identifier(srna))); } RNA_PROP_END; @@ -7450,7 +7582,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PyObject *args; PyObject *ret = NULL, *py_srna = NULL, *py_class_instance = NULL, *parmitem; PyTypeObject *py_class; - void **py_class_instance_store = NULL; PropertyRNA *parm; ParameterIterator iter; PointerRNA funcptr; @@ -7501,10 +7632,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param py_class_instance = *instance; Py_INCREF(py_class_instance); } - else { - /* store the instance here once its created */ - py_class_instance_store = instance; - } } } /* end exception */ @@ -7575,10 +7702,6 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (py_class_instance == NULL) { err = -1; /* so the error is not overridden below */ } - else if (py_class_instance_store) { - *py_class_instance_store = py_class_instance; - Py_INCREF(py_class_instance); - } } } diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index 38931cd85de..3e147d29c90 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -38,6 +38,8 @@ #include "RNA_access.h" +#include "../generic/py_capi_utils.h" + #define USE_MATHUTILS #ifdef USE_MATHUTILS @@ -550,7 +552,7 @@ static void py_to_float(const struct ItemConvertArgData *arg, PyObject *py, char static void py_to_int(const struct ItemConvertArgData *arg, PyObject *py, char *data) { const int *range = arg->int_data.range; - int value = (int)PyLong_AsLong(py); + int value = PyC_Long_AsI32(py); CLAMP(value, range[0], range[1]); *(int *)data = value; } diff --git a/source/blender/python/intern/bpy_rna_driver.c b/source/blender/python/intern/bpy_rna_driver.c index b4c0de51c04..1135ba121e3 100644 --- a/source/blender/python/intern/bpy_rna_driver.c +++ b/source/blender/python/intern/bpy_rna_driver.c @@ -63,7 +63,15 @@ PyObject *pyrna_driver_get_variable_value( } else { /* object & property */ - driver_arg = pyrna_prop_to_py(&ptr, prop); + PropertyType type = RNA_property_type(prop); + if (type == PROP_ENUM) { + /* Note that enum's are converted to strings by default, + * we want to avoid that, see: T52213 */ + driver_arg = PyLong_FromLong(RNA_property_enum_get(&ptr, prop)); + } + else { + driver_arg = pyrna_prop_to_py(&ptr, prop); + } } } else { diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 72705ffb3fb..8def52dc8fb 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -163,7 +163,6 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject * Main *bmain = G.main; /* XXX Ugly, but should work! */ #endif - static const char *kwlist[] = {"subset", "key_types", "value_types", NULL}; PyObject *subset = NULL; PyObject *key_types = NULL; @@ -173,9 +172,10 @@ static PyObject *bpy_user_map(PyObject *UNUSED(self), PyObject *args, PyObject * PyObject *ret = NULL; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "|O$O!O!:user_map", (char **)kwlist, + static const char *_keywords[] = {"subset", "key_types", "value_types", NULL}; + static _PyArg_Parser _parser = {"|O$O!O!:user_map", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, &subset, &PySet_Type, &key_types, &PySet_Type, &val_types)) diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c index 245735f679e..4a326ae657b 100644 --- a/source/blender/python/intern/bpy_rna_manipulator.c +++ b/source/blender/python/intern/bpy_rna_manipulator.c @@ -30,6 +30,7 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_alloca.h" #include "BKE_main.h" @@ -48,6 +49,11 @@ #include "bpy_rna.h" + +/* -------------------------------------------------------------------- */ +/** \name Manipulator Target Property Define API + * \{ */ + enum { BPY_MANIPULATOR_FN_SLOT_GET = 0, BPY_MANIPULATOR_FN_SLOT_SET, @@ -75,7 +81,7 @@ static void py_rna_manipulator_handler_get_cb( if (mpr_prop->type->data_type == PROP_FLOAT) { float *value = value_p; if (mpr_prop->type->array_length == 1) { - if (((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) == 0) { + if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) { goto fail; } } @@ -121,8 +127,7 @@ static void py_rna_manipulator_handler_set_cb( py_value = PyFloat_FromDouble(*value); } else { - py_value = PyC_FromArray((void *)value, mpr_prop->type->array_length, &PyFloat_Type, false, - "Manipulator set callback: "); + py_value = PyC_Tuple_PackArray_F32(value, mpr_prop->type->array_length); } if (py_value == NULL) { goto fail; @@ -236,14 +241,8 @@ PyDoc_STRVAR(bpy_manipulator_target_set_handler_doc, " :arg range: Function that returns a (min, max) tuple for manipulators that use a range.\n" " :type range: callable\n" ); -static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - /* Note: this is a counter-part to functions: - * 'Manipulator.target_set_prop & target_set_operator' - * (see: rna_wm_manipulator_api.c). conventions should match. */ - static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL}; - static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0}; - PyGILState_STATE gilstate = PyGILState_Ensure(); struct { @@ -256,9 +255,13 @@ static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyOb .py_fn_slots = {NULL}, }; + /* Note: this is a counter-part to functions: + * 'Manipulator.target_set_prop & target_set_operator' + * (see: rna_wm_manipulator_api.c). conventions should match. */ + static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL}; + static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0}; if (!_PyArg_ParseTupleAndKeywordsFast( - args, kwds, - &_parser, + args, kw, &_parser, ¶ms.self, ¶ms.target, ¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET], @@ -322,20 +325,241 @@ fail: return NULL; } -int BPY_rna_manipulator_module(PyObject *mod_par) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manipulator Target Property Access API + * \{ */ + +PyDoc_STRVAR(bpy_manipulator_target_get_value_doc, +".. method:: target_get_value(target):\n" +"\n" +" Get the value of this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :type target: string\n" +" :return: The value of the target property.\n" +" :rtype: Single value or array based on the target type\n" +); +static PyObject *bpy_manipulator_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static PyMethodDef method_def = { - "target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, METH_VARARGS | METH_KEYWORDS, - bpy_manipulator_target_set_handler_doc}; + struct { + PyObject *self; + char *target; + } params = { + .self = NULL, + .target = NULL, + }; - PyObject *func = PyCFunction_New(&method_def, NULL); - PyObject *func_inst = PyInstanceMethod_New(func); + static const char * const _keywords[] = {"self", "target", NULL}; + static _PyArg_Parser _parser = {"Os:target_get_value", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target)) + { + goto fail; + } + + wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data; + wmManipulatorProperty *mpr_prop = + WM_manipulator_target_property_find(mpr, params.target); + if (mpr_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Manipulator target property '%s.%s' not found", + mpr->type->idname, params.target); + goto fail; + } - /* TODO, return a type that binds nearly to a method. */ - PyModule_AddObject(mod_par, "_rna_manipulator_target_set_handler", func_inst); + const int array_len = WM_manipulator_target_property_array_length(mpr, mpr_prop); + switch (mpr_prop->type->data_type) { + case PROP_FLOAT: + { + if (array_len != 0) { + float *value = BLI_array_alloca(value, array_len); + WM_manipulator_target_property_value_get_array(mpr, mpr_prop, value); + return PyC_Tuple_PackArray_F32(value, array_len); + } + else { + float value = WM_manipulator_target_property_value_get(mpr, mpr_prop); + return PyFloat_FromDouble(value); + } + break; + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } - return 0; +fail: + return NULL; } +PyDoc_STRVAR(bpy_manipulator_target_set_value_doc, +".. method:: target_set_value(target):\n" +"\n" +" Set the value of this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :type target: string\n" +); +static PyObject *bpy_manipulator_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + struct { + PyObject *self; + char *target; + PyObject *value; + } params = { + .self = NULL, + .target = NULL, + .value = NULL, + }; + + static const char * const _keywords[] = {"self", "target", "value", NULL}; + static _PyArg_Parser _parser = {"OsO:target_set_value", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target, + ¶ms.value)) + { + goto fail; + } + + wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data; + wmManipulatorProperty *mpr_prop = + WM_manipulator_target_property_find(mpr, params.target); + if (mpr_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Manipulator target property '%s.%s' not found", + mpr->type->idname, params.target); + goto fail; + } + + const int array_len = WM_manipulator_target_property_array_length(mpr, mpr_prop); + switch (mpr_prop->type->data_type) { + case PROP_FLOAT: + { + if (array_len != 0) { + float *value = BLI_array_alloca(value, array_len); + if (PyC_AsArray(value, params.value, mpr_prop->type->array_length, &PyFloat_Type, false, + "Manipulator target property array") == -1) + { + goto fail; + } + WM_manipulator_target_property_value_set_array(BPy_GetContext(), mpr, mpr_prop, value); + } + else { + float value; + if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) { + goto fail; + } + WM_manipulator_target_property_value_set(BPy_GetContext(), mpr, mpr_prop, value); + } + Py_RETURN_NONE; + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } + +fail: + return NULL; +} + + +PyDoc_STRVAR(bpy_manipulator_target_get_range_doc, +".. method:: target_get_range(target):\n" +"\n" +" Get the range for this target property.\n" +"\n" +" :arg target: Target property name.\n" +" :Get the range for this target property" +" :return: The range of this property (min, max).\n" +" :rtype: tuple pair.\n" +); +static PyObject *bpy_manipulator_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + struct { + PyObject *self; + char *target; + } params = { + .self = NULL, + .target = NULL, + }; + + static const char * const _keywords[] = {"self", "target", NULL}; + static _PyArg_Parser _parser = {"Os:target_get_range", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + ¶ms.self, + ¶ms.target)) + { + goto fail; + } + + wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data; + + wmManipulatorProperty *mpr_prop = + WM_manipulator_target_property_find(mpr, params.target); + if (mpr_prop == NULL) { + PyErr_Format(PyExc_ValueError, + "Manipulator target property '%s.%s' not found", + mpr->type->idname, params.target); + goto fail; + } + + switch (mpr_prop->type->data_type) { + case PROP_FLOAT: + { + float range[2]; + WM_manipulator_target_property_range_get(mpr, mpr_prop, range); + return PyC_Tuple_PackArray_F32(range, 2); + } + default: + { + PyErr_SetString(PyExc_RuntimeError, "Not yet supported type"); + goto fail; + } + } + +fail: + return NULL; +} + +/** \} */ + +int BPY_rna_manipulator_module(PyObject *mod_par) +{ + static PyMethodDef method_def_array[] = { + /* Manipulator Target Property Define API */ + {"target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, + METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_set_handler_doc}, + /* Manipulator Target Property Access API */ + {"target_get_value", (PyCFunction)bpy_manipulator_target_get_value, + METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_get_value_doc}, + {"target_set_value", (PyCFunction)bpy_manipulator_target_set_value, + METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_set_value_doc}, + {"target_get_range", (PyCFunction)bpy_manipulator_target_get_range, + METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_get_range_doc}, + /* no sentinel needed. */ + }; + + for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) { + PyMethodDef *m = &method_def_array[i]; + PyObject *func = PyCFunction_New(m, NULL); + PyObject *func_inst = PyInstanceMethod_New(func); + char name_prefix[128]; + PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_manipulator_%s", m->ml_name); + /* TODO, return a type that binds nearly to a method. */ + PyModule_AddObject(mod_par, name_prefix, func_inst); + } + + return 0; +} diff --git a/source/blender/python/intern/bpy_util.h b/source/blender/python/intern/bpy_util.h index 63cb7920bd1..6000bf94aef 100644 --- a/source/blender/python/intern/bpy_util.h +++ b/source/blender/python/intern/bpy_util.h @@ -27,8 +27,8 @@ #ifndef __BPY_UTIL_H__ #define __BPY_UTIL_H__ -#if PY_VERSION_HEX < 0x03050000 -# error "Python 3.5 or greater is required, you'll need to update your python." +#if PY_VERSION_HEX < 0x03060000 +# error "Python 3.6 or greater is required, you'll need to update your python." #endif struct EnumPropertyItem; diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c index e0c70483e3c..0ef689d1a5a 100644 --- a/source/blender/python/intern/bpy_utils_units.c +++ b/source/blender/python/intern/bpy_utils_units.c @@ -174,8 +174,6 @@ PyDoc_STRVAR(bpyunits_to_value_doc, ); static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"unit_system", "unit_category", "str_input", "str_ref_unit", NULL}; - char *usys_str = NULL, *ucat_str = NULL, *inpt = NULL, *uref = NULL; const float scale = 1.0f; @@ -185,8 +183,13 @@ static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObj int usys, ucat; PyObject *ret; - if (!PyArg_ParseTupleAndKeywords(args, kw, "sss#|z:bpy.utils.units.to_value", (char **)kwlist, - &usys_str, &ucat_str, &inpt, &str_len, &uref)) + static const char *_keywords[] = { + "unit_system", "unit_category", "str_input", "str_ref_unit", NULL, + }; + static _PyArg_Parser _parser = {"sss#|z:to_value", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &usys_str, &ucat_str, &inpt, &str_len, &uref)) { return NULL; } @@ -244,9 +247,6 @@ PyDoc_STRVAR(bpyunits_to_string_doc, ); static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { - static const char *kwlist[] = {"unit_system", "unit_category", "value", - "precision", "split_unit", "compatible_unit", NULL}; - char *usys_str = NULL, *ucat_str = NULL; double value = 0.0; int precision = 3; @@ -254,9 +254,13 @@ static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyOb int usys, ucat; - if (!PyArg_ParseTupleAndKeywords( - args, kw, - "ssd|iO&O&:bpy.utils.units.to_string", (char **)kwlist, + static const char *_keywords[] = { + "unit_system", "unit_category", "value", + "precision", "split_unit", "compatible_unit", NULL, + }; + static _PyArg_Parser _parser = {"ssd|iO&O&:to_string", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &usys_str, &ucat_str, &value, &precision, PyC_ParseBool, &split_unit, PyC_ParseBool, &compatible_unit)) diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index 48230a723d2..a7a0ae78f26 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -207,7 +207,7 @@ PyDoc_STRVAR(GPU_export_shader_doc, " :return: Dictionary defining the shader, uniforms and attributes.\n" " :rtype: Dict" ); -static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { PyObject *pyscene; PyObject *pymat; @@ -224,11 +224,14 @@ static PyObject *GPU_export_shader(PyObject *UNUSED(self), PyObject *args, PyObj GPUInputUniform *uniform; GPUInputAttribute *attribute; - static const char *kwlist[] = {"scene", "material", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:export_shader", (char **)(kwlist), &pyscene, &pymat)) + static const char *_keywords[] = {"scene", "material", NULL}; + static _PyArg_Parser _parser = {"OO:export_shader", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, + &pyscene, &pymat)) + { return NULL; - + } scene = (Scene *)PyC_RNA_AsPointer(pyscene, "Scene"); if (scene == NULL) { return NULL; @@ -334,6 +337,14 @@ PyObject *GPU_initPython(void) PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); + PyModule_AddObject(module, "matrix", (submodule = BPyInit_gpu_matrix())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + Py_INCREF(submodule); + + PyModule_AddObject(module, "select", (submodule = BPyInit_gpu_select())); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); + Py_INCREF(submodule); + PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module); return module; } diff --git a/source/blender/python/intern/gpu.h b/source/blender/python/intern/gpu.h index 0da44a4eb87..92841db9027 100644 --- a/source/blender/python/intern/gpu.h +++ b/source/blender/python/intern/gpu.h @@ -37,5 +37,7 @@ PyObject *GPU_initPython(void); PyObject *BPyInit_gpu_offscreen(void); +PyObject *BPyInit_gpu_matrix(void); +PyObject *BPyInit_gpu_select(void); #endif /* __GPU_H__ */ diff --git a/source/blender/python/intern/gpu_offscreen.c b/source/blender/python/intern/gpu_offscreen.c index da8e5d69f02..6c16c274234 100644 --- a/source/blender/python/intern/gpu_offscreen.c +++ b/source/blender/python/intern/gpu_offscreen.c @@ -144,36 +144,6 @@ static PyObject *pygpu_offscreen_unbind(BPy_GPUOffScreen *self, PyObject *args, Py_RETURN_NONE; } -/** - * Use with PyArg_ParseTuple's "O&" formatting. - */ -static int pygpu_offscreen_check_matrix(PyObject *o, void *p) -{ - MatrixObject **pymat_p = p; - MatrixObject *pymat = (MatrixObject *)o; - - if (!MatrixObject_Check(pymat)) { - PyErr_Format(PyExc_TypeError, - "expected a mathutils.Matrix, not a %.200s", - Py_TYPE(o)->tp_name); - return 0; - } - - if (BaseMath_ReadCallback(pymat) == -1) { - return 0; - } - - if ((pymat->num_col != 4) || - (pymat->num_row != 4)) - { - PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); - return 0; - } - - *pymat_p = pymat; - return 1; -} - PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, "draw_view3d(scene, view3d, region, modelview_matrix, projection_matrix)\n" "\n" @@ -192,6 +162,8 @@ PyDoc_STRVAR(pygpu_offscreen_draw_view3d_doc, ); static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *args, PyObject *kwds) { + /* TODO: This doesn't work currently because of eval_ctx. */ +#if 0 static const char *kwlist[] = {"scene", "render_layer", "view3d", "region", "projection_matrix", "modelview_matrix", NULL}; MatrixObject *py_mat_modelview, *py_mat_projection; @@ -210,8 +182,8 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a if (!PyArg_ParseTupleAndKeywords( args, kwds, "OOOOO&O&:draw_view3d", (char **)(kwlist), &py_scene, &py_scene_layer, &py_view3d, &py_region, - pygpu_offscreen_check_matrix, &py_mat_projection, - pygpu_offscreen_check_matrix, &py_mat_modelview) || + Matrix_Parse4x4, &py_mat_projection, + Matrix_Parse4x4, &py_mat_modelview) || (!(scene = PyC_RNA_AsPointer(py_scene, "Scene")) || !(sl = PyC_RNA_AsPointer(py_scene_layer, "SceneLayer")) || !(v3d = PyC_RNA_AsPointer(py_view3d, "SpaceView3D")) || @@ -231,7 +203,7 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a GPU_offscreen_bind(self->ofs, true); /* bind */ ED_view3d_draw_offscreen( - scene, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs), + scene, sl, v3d, ar, GPU_offscreen_width(self->ofs), GPU_offscreen_height(self->ofs), (float(*)[4])py_mat_modelview->matrix, (float(*)[4])py_mat_projection->matrix, false, true, true, "", fx, &fx_settings, @@ -244,6 +216,10 @@ static PyObject *pygpu_offscreen_draw_view3d(BPy_GPUOffScreen *self, PyObject *a MEM_freeN(rv3d_mats); Py_RETURN_NONE; +#else + UNUSED_VARS(self, args, kwds); +#endif + return NULL; } PyDoc_STRVAR(pygpu_offscreen_free_doc, diff --git a/source/blender/python/intern/gpu_py_matrix.c b/source/blender/python/intern/gpu_py_matrix.c new file mode 100644 index 00000000000..68b08dfb324 --- /dev/null +++ b/source/blender/python/intern/gpu_py_matrix.c @@ -0,0 +1,552 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/gpu_py_matrix.c + * \ingroup pythonintern + * + * This file defines the gpu.matrix stack API. + * + * \warning While these functions attempt to ensure correct stack usage. + * Mixing Python and C functions may still crash on invalid use. + */ + +#include <Python.h> + + +#include "BLI_utildefines.h" + +#include "../mathutils/mathutils.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu.h" + +#define USE_GPU_PY_MATRIX_API +#include "GPU_matrix.h" +#undef USE_GPU_PY_MATRIX_API + +/* -------------------------------------------------------------------- */ +/** \name Helper Functions + * \{ */ + +static bool pygpu_stack_is_push_model_view_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_model_view() >= GPU_PY_MATRIX_STACK_LEN) { + PyErr_SetString(PyExc_RuntimeError, + "Maximum model-view stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached"); + return false; + } + return true; +} + +static bool pygpu_stack_is_push_projection_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_projection() >= GPU_PY_MATRIX_STACK_LEN) { + PyErr_SetString(PyExc_RuntimeError, + "Maximum projection stack depth " STRINGIFY(GPU_PY_MATRIX_STACK_DEPTH) " reached"); + return false; + } + return true; +} + +static bool pygpu_stack_is_pop_model_view_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_model_view() == 0) { + PyErr_SetString(PyExc_RuntimeError, + "Minimum model-view stack depth reached"); + return false; + } + return true; +} + +static bool pygpu_stack_is_pop_projection_ok_or_error(void) +{ + if (GPU_matrix_stack_level_get_projection() == 0) { + PyErr_SetString(PyExc_RuntimeError, + "Minimum projection stack depth reached"); + return false; + } + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manage Stack + * \{ */ + +PyDoc_STRVAR(pygpu_matrix_push_doc, +"push()\n" +"\n" +" Add to the model-view matrix stack.\n" +); +static PyObject *pygpu_matrix_push(PyObject *UNUSED(self)) +{ + if (!pygpu_stack_is_push_model_view_ok_or_error()) { + return NULL; + } + gpuPushMatrix(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_pop_doc, +"pop()\n" +"\n" +" Remove the last model-view matrix from the stack.\n" +); +static PyObject *pygpu_matrix_pop(PyObject *UNUSED(self)) +{ + if (!pygpu_stack_is_pop_model_view_ok_or_error()) { + return NULL; + } + gpuPopMatrix(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_push_projection_doc, +"push_projection()\n" +"\n" +" Add to the projection matrix stack.\n" +); +static PyObject *pygpu_matrix_push_projection(PyObject *UNUSED(self)) +{ + if (!pygpu_stack_is_push_projection_ok_or_error()) { + return NULL; + } + gpuPushProjectionMatrix(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_pop_projection_doc, +"pop_projection()\n" +"\n" +" Remove the last projection matrix from the stack.\n" +); +static PyObject *pygpu_matrix_pop_projection(PyObject *UNUSED(self)) +{ + if (!pygpu_stack_is_pop_projection_ok_or_error()) { + return NULL; + } + gpuPopProjectionMatrix(); + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stack (Context Manager) + * + * Safer alternative to ensure balanced push/pop calls. + * + * \{ */ + +typedef struct { + PyObject_HEAD /* required python macro */ + int type; + int level; +} BPy_GPU_MatrixStackContext; + +enum { + PYGPU_MATRIX_TYPE_MODEL_VIEW = 1, + PYGPU_MATRIX_TYPE_PROJECTION = 2, +}; + +static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *self); +static PyObject *pygpu_matrix_stack_context_exit(BPy_GPU_MatrixStackContext *self, PyObject *args); + +static PyMethodDef pygpu_matrix_stack_context_methods[] = { + {"__enter__", (PyCFunction)pygpu_matrix_stack_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)pygpu_matrix_stack_context_exit, METH_VARARGS}, + {NULL} +}; + +static PyTypeObject pygpu_matrix_stack_context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "GPUMatrixStackContext", + .tp_basicsize = sizeof(BPy_GPU_MatrixStackContext), + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_methods = pygpu_matrix_stack_context_methods, +}; + +static PyObject *pygpu_matrix_stack_context_enter(BPy_GPU_MatrixStackContext *self) +{ + /* sanity - should never happen */ + if (self->level != -1) { + PyErr_SetString(PyExc_RuntimeError, "Already in use"); + return NULL; + } + + if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { + if (!pygpu_stack_is_push_model_view_ok_or_error()) { + return NULL; + } + gpuPushMatrix(); + self->level = GPU_matrix_stack_level_get_model_view(); + } + else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { + if (!pygpu_stack_is_push_projection_ok_or_error()) { + return NULL; + } + gpuPushProjectionMatrix(); + self->level = GPU_matrix_stack_level_get_projection(); + } + else { + BLI_assert(0); + } + Py_RETURN_NONE; +} + +static PyObject *pygpu_matrix_stack_context_exit(BPy_GPU_MatrixStackContext *self, PyObject *UNUSED(args)) +{ + /* sanity - should never happen */ + if (self->level == -1) { + fprintf(stderr, "Not yet in use\n"); + goto finally; + } + + if (self->type == PYGPU_MATRIX_TYPE_MODEL_VIEW) { + const int level = GPU_matrix_stack_level_get_model_view(); + if (level != self->level) { + fprintf(stderr, "Level push/pop mismatch, expected %d, got %d\n", self->level, level); + } + if (level != 0) { + gpuPopMatrix(); + } + } + else if (self->type == PYGPU_MATRIX_TYPE_PROJECTION) { + const int level = GPU_matrix_stack_level_get_projection(); + if (level != self->level) { + fprintf(stderr, "Level push/pop mismatch, expected %d, got %d", self->level, level); + } + if (level != 0) { + gpuPopProjectionMatrix(); + } + } + else { + BLI_assert(0); + } +finally: + Py_RETURN_NONE; +} + +static PyObject *pygpu_matrix_push_pop_impl(int type) +{ + BPy_GPU_MatrixStackContext *ret = PyObject_New(BPy_GPU_MatrixStackContext, &pygpu_matrix_stack_context_Type); + ret->type = type; + ret->level = -1; + return (PyObject *)ret; +} + +PyDoc_STRVAR(pygpu_matrix_push_pop_doc, +"push_pop()\n" +"\n" +" Context manager to ensure balanced push/pop calls, even in the case of an error.\n" +); +static PyObject *pygpu_matrix_push_pop(PyObject *UNUSED(self)) +{ + return pygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_MODEL_VIEW); +} + +PyDoc_STRVAR(pygpu_matrix_push_pop_projection_doc, +"push_pop_projection()\n" +"\n" +" Context manager to ensure balanced push/pop calls, even in the case of an error.\n" +); +static PyObject *pygpu_matrix_push_pop_projection(PyObject *UNUSED(self)) +{ + return pygpu_matrix_push_pop_impl(PYGPU_MATRIX_TYPE_PROJECTION); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Manipulate State + * \{ */ + +PyDoc_STRVAR(pygpu_matrix_multiply_matrix_doc, +"multiply_matrix(matrix)\n" +"\n" +" Multiply the current stack matrix.\n" +"\n" +" :param matrix: A 4x4 matrix.\n" +" :type matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_matrix_multiply_matrix(PyObject *UNUSED(self), PyObject *value) +{ + MatrixObject *pymat; + if (!Matrix_Parse4x4(value, &pymat)) { + return NULL; + } + gpuMultMatrix(pymat->matrix); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_scale_doc, +"scale(scale)\n" +"\n" +" Scale the current stack matrix.\n" +"\n" +" :param scale: Scale the current stack matrix.\n" +" :type scale: sequence of 2 or 3 floats\n" +); +static PyObject *pygpu_matrix_scale(PyObject *UNUSED(self), PyObject *value) +{ + float scale[3]; + int len; + if ((len = mathutils_array_parse(scale, 2, 3, value, "gpu.matrix.scale(): invalid vector arg")) == -1) { + return NULL; + } + if (len == 2) { + gpuScale2fv(scale); + } + else { + gpuScale3fv(scale); + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_scale_uniform_doc, +"scale_uniform(scale)\n" +"\n" +" :param scale: Scale the current stack matrix.\n" +" :type scale: sequence of 2 or 3 floats\n" +); +static PyObject *pygpu_matrix_scale_uniform(PyObject *UNUSED(self), PyObject *value) +{ + float scalar; + if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + "expected a number, not %.200s", + Py_TYPE(value)->tp_name); + return NULL; + } + gpuScaleUniform(scalar); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_translate_doc, +"translate(offset)\n" +"\n" +" Scale the current stack matrix.\n" +"\n" +" :param offset: Translate the current stack matrix.\n" +" :type offset: sequence of 2 or 3 floats\n" +); +static PyObject *pygpu_matrix_translate(PyObject *UNUSED(self), PyObject *value) +{ + float offset[3]; + int len; + if ((len = mathutils_array_parse(offset, 2, 3, value, "gpu.matrix.translate(): invalid vector arg")) == -1) { + return NULL; + } + if (len == 2) { + gpuTranslate2fv(offset); + } + else { + gpuTranslate3fv(offset); + } + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Write State + * \{ */ + +PyDoc_STRVAR(pygpu_matrix_reset_doc, +"reset()\n" +"\n" +" Empty stack and set to identity.\n" +); +static PyObject *pygpu_matrix_reset(PyObject *UNUSED(self)) +{ + gpuMatrixReset(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_load_identity_doc, +"load_identity()\n" +"\n" +" Empty stack and set to identity.\n" +); +static PyObject *pygpu_matrix_load_identity(PyObject *UNUSED(self)) +{ + gpuLoadIdentity(); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(pygpu_matrix_load_matrix_doc, +"load_matrix(matrix)\n" +"\n" +" Load a matrix into the stack.\n" +"\n" +" :param matrix: A 4x4 matrix.\n" +" :type matrix: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_matrix_load_matrix(PyObject *UNUSED(self), PyObject *value) +{ + MatrixObject *pymat; + if (!Matrix_Parse4x4(value, &pymat)) { + return NULL; + } + gpuLoadMatrix(pymat->matrix); + Py_RETURN_NONE; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read State + * \{ */ + +PyDoc_STRVAR(pygpu_matrix_get_projection_matrix_doc, +"get_projection_matrix()\n" +"\n" +" Return a copy of the projection matrix.\n" +"\n" +" :return: A 4x4 projection matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_matrix_get_projection_matrix(PyObject *UNUSED(self)) +{ + float matrix[4][4]; + gpuGetModelViewMatrix(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); +} + + +PyDoc_STRVAR(pygpu_matrix_get_modal_view_matrix_doc, +"get_view_matrix()\n" +"\n" +" Return a copy of the view matrix.\n" +"\n" +" :return: A 4x4 view matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_matrix_get_modal_view_matrix(PyObject *UNUSED(self)) +{ + float matrix[4][4]; + gpuGetProjectionMatrix(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 4, 4, NULL); +} + +PyDoc_STRVAR(pygpu_matrix_get_normal_matrix_doc, +"get_normal_matrix()\n" +"\n" +" Return a copy of the normal matrix.\n" +"\n" +" :return: A 3x3 normal matrix.\n" +" :rtype: :class:`mathutils.Matrix`\n" +); +static PyObject *pygpu_matrix_get_normal_matrix(PyObject *UNUSED(self)) +{ + float matrix[3][3]; + gpuGetNormalMatrix(matrix); + return Matrix_CreatePyObject(&matrix[0][0], 3, 3, NULL); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +static struct PyMethodDef BPy_GPU_matrix_methods[] = { + /* Manage Stack */ + {"push", (PyCFunction)pygpu_matrix_push, + METH_NOARGS, pygpu_matrix_push_doc}, + {"pop", (PyCFunction)pygpu_matrix_pop, + METH_NOARGS, pygpu_matrix_pop_doc}, + + {"push_projection", (PyCFunction)pygpu_matrix_push_projection, + METH_NOARGS, pygpu_matrix_push_projection_doc}, + {"pop_projection", (PyCFunction)pygpu_matrix_pop_projection, + METH_NOARGS, pygpu_matrix_pop_projection_doc}, + + /* Stack (Context Manager) */ + {"push_pop", (PyCFunction)pygpu_matrix_push_pop, + METH_NOARGS, pygpu_matrix_push_pop_doc}, + {"push_pop_projection", (PyCFunction)pygpu_matrix_push_pop_projection, + METH_NOARGS, pygpu_matrix_push_pop_projection_doc}, + + /* Manipulate State */ + {"multiply_matrix", (PyCFunction)pygpu_matrix_multiply_matrix, + METH_O, pygpu_matrix_multiply_matrix_doc}, + {"scale", (PyCFunction)pygpu_matrix_scale, + METH_O, pygpu_matrix_scale_doc}, + {"scale_uniform", (PyCFunction)pygpu_matrix_scale_uniform, + METH_O, pygpu_matrix_scale_uniform_doc}, + {"translate", (PyCFunction)pygpu_matrix_translate, + METH_O, pygpu_matrix_translate_doc}, + + /* TODO */ +#if 0 + {"rotate", (PyCFunction)pygpu_matrix_rotate, + METH_O, pygpu_matrix_rotate_doc}, + {"rotate_axis", (PyCFunction)pygpu_matrix_rotate_axis, + METH_O, pygpu_matrix_rotate_axis_doc}, + {"look_at", (PyCFunction)pygpu_matrix_look_at, + METH_O, pygpu_matrix_look_at_doc}, +#endif + + /* Write State */ + {"reset", (PyCFunction)pygpu_matrix_reset, + METH_NOARGS, pygpu_matrix_reset_doc}, + {"load_identity", (PyCFunction)pygpu_matrix_load_identity, + METH_NOARGS, pygpu_matrix_load_identity_doc}, + {"load_matrix", (PyCFunction)pygpu_matrix_load_matrix, + METH_O, pygpu_matrix_load_matrix_doc}, + + /* Read State */ + {"get_projection_matrix", (PyCFunction)pygpu_matrix_get_projection_matrix, + METH_NOARGS, pygpu_matrix_get_projection_matrix_doc}, + {"get_model_view_matrix", (PyCFunction)pygpu_matrix_get_modal_view_matrix, + METH_NOARGS, pygpu_matrix_get_modal_view_matrix_doc}, + {"get_normal_matrix", (PyCFunction)pygpu_matrix_get_normal_matrix, + METH_NOARGS, pygpu_matrix_get_normal_matrix_doc}, + + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(BPy_GPU_matrix_doc, +"This module provides access to the matrix stack." +); +static PyModuleDef BPy_GPU_matrix_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.matrix", + .m_doc = BPy_GPU_matrix_doc, + .m_methods = BPy_GPU_matrix_methods, +}; + +PyObject *BPyInit_gpu_matrix(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPy_GPU_matrix_module_def); + + if (PyType_Ready(&pygpu_matrix_stack_context_Type) < 0) { + return NULL; + } + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/intern/gpu_py_select.c b/source/blender/python/intern/gpu_py_select.c new file mode 100644 index 00000000000..f570c4cdae2 --- /dev/null +++ b/source/blender/python/intern/gpu_py_select.c @@ -0,0 +1,92 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/gpu_py_select.c + * \ingroup pythonintern + * + * This file defines the gpu.select API. + * + * \note Currently only used for manipulator selection, + * will need to add begin/end and a way to access the hits. + */ + +#include <Python.h> + +#include "BLI_utildefines.h" + +#include "../generic/py_capi_utils.h" + +#include "gpu.h" + +#include "GPU_select.h" + +/* -------------------------------------------------------------------- */ +/** \name Methods + * \{ */ + +PyDoc_STRVAR(pygpu_select_load_id_doc, +"load_id(id)\n" +"\n" +" Set the selection ID.\n" +"\n" +" :param id: Number (32-bit unsigned int).\n" +" :type select: int\n" +); +static PyObject *pygpu_select_load_id(PyObject *UNUSED(self), PyObject *value) +{ + uint id; + if ((id = PyC_Long_AsU32(value)) == (uint)-1) { + return NULL; + } + GPU_select_load_id(id); + Py_RETURN_NONE; +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Module + * \{ */ + +static struct PyMethodDef BPy_GPU_select_methods[] = { + /* Manage Stack */ + {"load_id", (PyCFunction)pygpu_select_load_id, METH_O, pygpu_select_load_id_doc}, + {NULL, NULL, 0, NULL} +}; + +PyDoc_STRVAR(BPy_GPU_select_doc, +"This module provides access to selection." +); +static PyModuleDef BPy_GPU_select_module_def = { + PyModuleDef_HEAD_INIT, + .m_name = "gpu.select", + .m_doc = BPy_GPU_select_doc, + .m_methods = BPy_GPU_select_methods, +}; + +PyObject *BPyInit_gpu_select(void) +{ + PyObject *submodule; + + submodule = PyModule_Create(&BPy_GPU_select_module_def); + + return submodule; +} + +/** \} */ diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 1afb1d7be90..96ae0a9e50f 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -554,8 +554,8 @@ char BaseMathObject_freeze_doc[] = ; PyObject *BaseMathObject_freeze(BaseMathObject *self) { - if (self->flag & BASE_MATH_FLAG_IS_WRAP) { - PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped data"); + if ((self->flag & BASE_MATH_FLAG_IS_WRAP) || (self->cb_user != NULL)) { + PyErr_SetString(PyExc_TypeError, "Cannot freeze wrapped/owned data"); return NULL; } diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 6ac75565c66..d1fb6dcdb82 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -41,9 +41,18 @@ extern char BaseMathObject_owner_doc[]; (struct_name *)((base_type ? (base_type)->tp_alloc(base_type, 0) : _PyObject_GC_New(&(root_type)))); -/* BaseMathObject.flag */ +/** BaseMathObject.flag */ enum { + /** + * Do not own the memory used in this vector, + * \note This is error prone if the memory may be freed while this vector is in use. + * Prefer using callbacks where possible, see: #Mathutils_RegisterCallback + */ BASE_MATH_FLAG_IS_WRAP = (1 << 0), + /** + * Prevent changes to the vector so it can be used as a set or dictionary key for example. + * (typical use cases for tuple). + */ BASE_MATH_FLAG_IS_FROZEN = (1 << 1), }; #define BASE_MATH_FLAG_DEFAULT 0 diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index e368e8871f3..2578b19d5ec 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -2914,6 +2914,73 @@ PyObject *Matrix_CreatePyObject_cb(PyObject *cb_user, return (PyObject *) self; } +/** + * Use with PyArg_ParseTuple's "O&" formatting. + */ +static bool Matrix_ParseCheck(MatrixObject *pymat) +{ + if (!MatrixObject_Check(pymat)) { + PyErr_Format(PyExc_TypeError, + "expected a mathutils.Matrix, not a %.200s", + Py_TYPE(pymat)->tp_name); + return 0; + } + /* sets error */ + if (BaseMath_ReadCallback(pymat) == -1) { + return 0; + } + return 1; +} + +int Matrix_ParseAny(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse3x3(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 3) || + (pymat->num_row != 3)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 3x3"); + return 0; + } + + *pymat_p = pymat; + return 1; +} + +int Matrix_Parse4x4(PyObject *o, void *p) +{ + MatrixObject **pymat_p = p; + MatrixObject *pymat = (MatrixObject *)o; + + if (!Matrix_ParseCheck(pymat)) { + return 0; + } + if ((pymat->num_col != 4) || + (pymat->num_row != 4)) + { + PyErr_SetString(PyExc_ValueError, "matrix must be 4x4"); + return 0; + } + + *pymat_p = pymat; + return 1; +} /* ---------------------------------------------------------------------------- * special type for alternate access */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h index 542a0e349c7..9c84716d307 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.h +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -77,6 +77,11 @@ PyObject *Matrix_CreatePyObject_cb( unsigned char cb_type, unsigned char cb_subtype ) ATTR_WARN_UNUSED_RESULT; +/* PyArg_ParseTuple's "O&" formatting helpers. */ +int Matrix_ParseAny(PyObject *o, void *p); +int Matrix_Parse3x3(PyObject *o, void *p); +int Matrix_Parse4x4(PyObject *o, void *p); + extern unsigned char mathutils_matrix_row_cb_index; /* default */ extern unsigned char mathutils_matrix_col_cb_index; extern unsigned char mathutils_matrix_translation_cb_index; diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index afc8a30a6b5..65450505e08 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -32,10 +32,17 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "../generic/py_capi_utils.h" + #ifndef MATH_STANDALONE # include "BLI_dynstr.h" #endif +/** + * Higher dimensions are supported, for many common operations + * (dealing with vector/matrix multiply or handling as 3D locations) + * stack memory is used with a fixed size - defined here. + */ #define MAX_DIMENSIONS 4 /* Swizzle axes get packed into a single value that is used as a closure. Each @@ -50,7 +57,8 @@ static PyObject *Vector_deepcopy(VectorObject *self, PyObject *args); static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits); static int row_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat); -/* Supports 2D, 3D, and 4D vector objects both int and float values +/** + * Supports 2D, 3D, and 4D vector objects both int and float values * accepted. Mixed float and int values accepted. Ints are parsed to float */ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -403,7 +411,7 @@ static PyObject *Vector_resize(VectorObject *self, PyObject *value) return NULL; } - if ((size = PyLong_AsLong(value)) == -1) { + if ((size = PyC_Long_AsI32(value)) == -1) { PyErr_SetString(PyExc_TypeError, "Vector.resize(size): " "expected size argument to be an integer"); @@ -836,9 +844,11 @@ static PyObject *Vector_orthogonal(VectorObject *self) } -/* - * Vector.reflect(mirror): return a reflected vector on the mirror normal - * vec - ((2 * DotVecs(vec, mirror)) * mirror) +/** + * Vector.reflect(mirror): return a reflected vector on the mirror normal. + * <pre> + * vec - ((2 * dot(vec, mirror)) * mirror) + * </pre> */ PyDoc_STRVAR(Vector_reflect_doc, ".. method:: reflect(mirror)\n" @@ -1644,13 +1654,16 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2) * multiplication */ -/* COLUMN VECTOR Multiplication (Matrix X Vector) +/** + * column vector multiplication (Matrix * Vector) + * <pre> * [1][4][7] [a] * [2][5][8] * [b] * [3][6][9] [c] + * </pre> * - * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!! - * note: assume read callbacks have been done first. + * \note Vector/Matrix multiplication is not commutative. + * \note Assume read callbacks have been done first. */ int column_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { @@ -2199,9 +2212,67 @@ static PyObject *Vector_length_squared_get(VectorObject *self, void *UNUSED(clos return PyFloat_FromDouble(dot_vn_vn(self->vec, self->vec, self->size)); } -/* Get a new Vector according to the provided swizzle. This function has little - * error checking, as we are in control of the inputs: the closure is set by us - * in Vector_createSwizzleGetSeter. */ + +/** + * Python script used to make swizzle array: + * + * \code{.py} + * SWIZZLE_BITS_PER_AXIS = 3 + * SWIZZLE_VALID_AXIS = 0x4 + * + * axis_dict = {} + * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} + * axises = 'xyzw' + * while len(axises) >= 2: + * for axis_0 in axises: + * axis_0_pos = axis_pos[axis_0] + * for axis_1 in axises: + * axis_1_pos = axis_pos[axis_1] + * axis_dict[axis_0 + axis_1] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % + * (axis_0_pos, axis_1_pos)) + * if len(axises) > 2: + * for axis_2 in axises: + * axis_2_pos = axis_pos[axis_2] + * axis_dict[axis_0 + axis_1 + axis_2] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % + * (axis_0_pos, axis_1_pos, axis_2_pos)) + * if len(axises) > 3: + * for axis_3 in axises: + * axis_3_pos = axis_pos[axis_3] + * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( + * '((%s | SWIZZLE_VALID_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' + * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % + * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) + * + * axises = axises[:-1] + * + * + * items = list(axis_dict.items()) + * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) + * + * unique = set() + * for key, val in items: + * num = eval(val) + * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' + * key_args = ', '.join(["'%s'" % c for c in key.upper()]) + * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE%d(%s)},' % + * (key, (' ' * (4 - len(key))), set_str, len(key), key_args)) + * unique.add(num) + * + * if len(unique) != len(items): + * print("ERROR, duplicate values found") + * \endcode + */ + +/** + * Get a new Vector according to the provided swizzle bits. + */ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) { size_t axis_to; @@ -2232,7 +2303,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) return Vector_CreatePyObject(vec, axis_to, Py_TYPE(self)); } -/* Set the items of this vector using a swizzle. +/** + * Set the items of this vector using a swizzle. * - If value is a vector or list this operates like an array copy, except that * the destination is effectively re-ordered as defined by the swizzle. At * most min(len(source), len(dest)) values will be copied. @@ -2240,8 +2312,8 @@ static PyObject *Vector_swizzle_get(VectorObject *self, void *closure) * - If an axis appears more than once in the swizzle, the final occurrence is * the one that determines its value. * - * Returns 0 on success and -1 on failure. On failure, the vector will be - * unchanged. */ + * \return 0 on success and -1 on failure. On failure, the vector will be unchanged. + */ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure) { size_t size_from; @@ -2324,19 +2396,14 @@ static int Vector_swizzle_set(VectorObject *self, PyObject *value, void *closure return 0; } -/* XYZW -> 0123 */ -#define AXIS_FROM_CHAR(a) (((a) != 'W') ? ((a) - 'X') : 3) - -#define _VA_SWIZZLE_1(a) ( \ - ((AXIS_FROM_CHAR(a) | SWIZZLE_VALID_AXIS))) -#define _VA_SWIZZLE_2(a, b) (_VA_SWIZZLE_1(a) | \ - ((AXIS_FROM_CHAR(b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) -#define _VA_SWIZZLE_3(a, b, c) (_VA_SWIZZLE_2(a, b) | \ - ((AXIS_FROM_CHAR(c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) -#define _VA_SWIZZLE_4(a, b, c, d) (_VA_SWIZZLE_3(a, b, c) | \ - ((AXIS_FROM_CHAR(d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) +#define _SWIZZLE1(a) ((a) | SWIZZLE_VALID_AXIS) +#define _SWIZZLE2(a, b) (_SWIZZLE1(a) | (((b) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS))) +#define _SWIZZLE3(a, b, c) (_SWIZZLE2(a, b) | (((c) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2))) +#define _SWIZZLE4(a, b, c, d) (_SWIZZLE3(a, b, c) | (((d) | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) -#define SWIZZLE(...) SET_INT_IN_POINTER(VA_NARGS_CALL_OVERLOAD(_VA_SWIZZLE_, __VA_ARGS__)) +#define SWIZZLE2(a, b) SET_INT_IN_POINTER(_SWIZZLE2(a, b)) +#define SWIZZLE3(a, b, c) SET_INT_IN_POINTER(_SWIZZLE3(a, b, c)) +#define SWIZZLE4(a, b, c, d) SET_INT_IN_POINTER(_SWIZZLE4(a, b, c, d)) /*****************************************************************************/ /* Python attributes get/set structure: */ @@ -2353,416 +2420,366 @@ static PyGetSetDef Vector_getseters[] = { {(char *)"is_frozen", (getter)BaseMathObject_is_frozen_get, (setter)NULL, BaseMathObject_is_frozen_doc, NULL}, {(char *)"owner", (getter)BaseMathObject_owner_get, (setter)NULL, BaseMathObject_owner_doc, NULL}, - /* autogenerated swizzle attrs, see python script below */ - {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X')}, - {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X')}, - {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'X')}, - {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Y')}, - {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'Z')}, - {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'X', 'W')}, - {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y')}, - {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'X')}, - {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Y')}, - {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'Z')}, - {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Y', 'W')}, - {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z')}, - {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'X')}, - {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Y')}, - {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'Z')}, - {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'Z', 'W')}, - {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W')}, - {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'X')}, - {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Y')}, - {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'Z')}, - {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'X', 'W', 'W')}, - {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y')}, - {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X')}, - {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'X')}, - {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Y')}, - {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'Z')}, - {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'X', 'W')}, - {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y')}, - {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'X')}, - {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Y')}, - {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'Z')}, - {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Y', 'W')}, - {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z')}, - {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'X')}, - {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Y')}, - {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'Z', 'Z')}, - {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'Z', 'W')}, - {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W')}, - {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'X')}, - {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'Y')}, - {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Y', 'W', 'Z')}, - {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Y', 'W', 'W')}, - {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z')}, - {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X')}, - {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'X')}, - {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Y')}, - {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'Z')}, - {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'X', 'W')}, - {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y')}, - {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'X')}, - {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Y')}, - {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Y', 'Z')}, - {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'Y', 'W')}, - {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z')}, - {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'X')}, - {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Y')}, - {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'Z')}, - {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'Z', 'W')}, - {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W')}, - {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'X')}, - {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'Z', 'W', 'Y')}, - {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'Z')}, - {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'Z', 'W', 'W')}, - {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W')}, - {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X')}, - {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'X')}, - {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Y')}, - {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'Z')}, - {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'X', 'W')}, - {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y')}, - {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'X')}, - {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'Y')}, - {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Y', 'Z')}, - {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Y', 'W')}, - {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z')}, - {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'X')}, - {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('X', 'W', 'Z', 'Y')}, - {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'Z')}, - {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'Z', 'W')}, - {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W')}, - {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'X')}, - {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Y')}, - {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'Z')}, - {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('X', 'W', 'W', 'W')}, - {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X')}, - {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X')}, - {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'X')}, - {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Y')}, - {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'Z')}, - {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'X', 'W')}, - {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y')}, - {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'X')}, - {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Y')}, - {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'Z')}, - {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Y', 'W')}, - {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z')}, - {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'X')}, - {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Y')}, - {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'Z', 'Z')}, - {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'Z', 'W')}, - {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W')}, - {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'X')}, - {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'Y')}, - {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'X', 'W', 'Z')}, - {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'X', 'W', 'W')}, - {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y')}, - {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X')}, - {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'X')}, - {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Y')}, - {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'Z')}, - {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'X', 'W')}, - {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y')}, - {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'X')}, - {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Y')}, - {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'Z')}, - {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Y', 'W')}, - {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z')}, - {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'X')}, - {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Y')}, - {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'Z')}, - {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'Z', 'W')}, - {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W')}, - {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'X')}, - {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Y')}, - {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'Z')}, - {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Y', 'W', 'W')}, - {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z')}, - {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X')}, - {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'X')}, - {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Y')}, - {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'X', 'Z')}, - {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'X', 'W')}, - {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y')}, - {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'X')}, - {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Y')}, - {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'Z')}, - {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Y', 'W')}, - {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z')}, - {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'X')}, - {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Y')}, - {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'Z')}, - {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'Z', 'W')}, - {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W')}, - {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'Z', 'W', 'X')}, - {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Y')}, - {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'Z')}, - {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'Z', 'W', 'W')}, - {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W')}, - {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X')}, - {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'X')}, - {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'Y')}, - {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'X', 'Z')}, - {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'X', 'W')}, - {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y')}, - {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'X')}, - {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Y')}, - {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'Z')}, - {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Y', 'W')}, - {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z')}, - {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Y', 'W', 'Z', 'X')}, - {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Y')}, - {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'Z')}, - {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'Z', 'W')}, - {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W')}, - {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'X')}, - {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Y')}, - {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'Z')}, - {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Y', 'W', 'W', 'W')}, - {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X')}, - {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X')}, - {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'X')}, - {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Y')}, - {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'Z')}, - {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'X', 'W')}, - {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y')}, - {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'X')}, - {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Y')}, - {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Y', 'Z')}, - {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'Y', 'W')}, - {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z')}, - {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'X')}, - {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Y')}, - {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'Z')}, - {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'Z', 'W')}, - {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W')}, - {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'X')}, - {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'X', 'W', 'Y')}, - {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'Z')}, - {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'X', 'W', 'W')}, - {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y')}, - {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X')}, - {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'X')}, - {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Y')}, - {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'X', 'Z')}, - {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'X', 'W')}, - {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y')}, - {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'X')}, - {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Y')}, - {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'Z')}, - {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Y', 'W')}, - {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z')}, - {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'X')}, - {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Y')}, - {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'Z')}, - {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'Z', 'W')}, - {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W')}, - {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'Y', 'W', 'X')}, - {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Y')}, - {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'Z')}, - {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Y', 'W', 'W')}, - {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z')}, - {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X')}, - {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'X')}, - {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Y')}, - {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'Z')}, - {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'X', 'W')}, - {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y')}, - {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'X')}, - {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Y')}, - {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'Z')}, - {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Y', 'W')}, - {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z')}, - {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'X')}, - {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Y')}, - {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'Z')}, - {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'Z', 'W')}, - {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W')}, - {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'X')}, - {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Y')}, - {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'Z')}, - {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'Z', 'W', 'W')}, - {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W')}, - {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X')}, - {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'X')}, - {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'X', 'Y')}, - {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'Z')}, - {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'X', 'W')}, - {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y')}, - {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('Z', 'W', 'Y', 'X')}, - {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Y')}, - {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'Z')}, - {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Y', 'W')}, - {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z')}, - {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'X')}, - {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Y')}, - {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'Z')}, - {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'Z', 'W')}, - {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W')}, - {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'X')}, - {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Y')}, - {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'Z')}, - {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('Z', 'W', 'W', 'W')}, - {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X')}, - {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X')}, - {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'X')}, - {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Y')}, - {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'Z')}, - {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'X', 'W')}, - {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y')}, - {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'X')}, - {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'Y')}, - {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Y', 'Z')}, - {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Y', 'W')}, - {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z')}, - {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'X')}, - {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'X', 'Z', 'Y')}, - {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'Z')}, - {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'Z', 'W')}, - {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W')}, - {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'X')}, - {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Y')}, - {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'Z')}, - {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'X', 'W', 'W')}, - {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y')}, - {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X')}, - {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'X')}, - {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'Y')}, - {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'X', 'Z')}, - {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'X', 'W')}, - {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y')}, - {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'X')}, - {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Y')}, - {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'Z')}, - {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Y', 'W')}, - {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z')}, - {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Y', 'Z', 'X')}, - {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Y')}, - {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'Z')}, - {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'Z', 'W')}, - {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W')}, - {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'X')}, - {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Y')}, - {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'Z')}, - {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Y', 'W', 'W')}, - {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z')}, - {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X')}, - {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'X')}, - {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'X', 'Y')}, - {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'Z')}, - {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'X', 'W')}, - {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y')}, - {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE('W', 'Z', 'Y', 'X')}, - {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Y')}, - {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'Z')}, - {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Y', 'W')}, - {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z')}, - {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'X')}, - {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Y')}, - {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'Z')}, - {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'Z', 'W')}, - {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W')}, - {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'X')}, - {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Y')}, - {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'Z')}, - {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'Z', 'W', 'W')}, - {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W')}, - {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X')}, - {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'X')}, - {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Y')}, - {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'Z')}, - {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'X', 'W')}, - {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y')}, - {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'X')}, - {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Y')}, - {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'Z')}, - {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Y', 'W')}, - {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z')}, - {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'X')}, - {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Y')}, - {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'Z')}, - {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'Z', 'W')}, - {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W')}, - {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'X')}, - {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Y')}, - {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'Z')}, - {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE('W', 'W', 'W', 'W')}, + /* autogenerated swizzle attrs, see Python script above */ + {(char *)"xx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(0, 0)}, + {(char *)"xxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 0)}, + {(char *)"xxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 0)}, + {(char *)"xxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 1)}, + {(char *)"xxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 2)}, + {(char *)"xxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 0, 3)}, + {(char *)"xxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 1)}, + {(char *)"xxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 0)}, + {(char *)"xxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 1)}, + {(char *)"xxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 2)}, + {(char *)"xxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 1, 3)}, + {(char *)"xxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 2)}, + {(char *)"xxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 0)}, + {(char *)"xxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 1)}, + {(char *)"xxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 2)}, + {(char *)"xxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 2, 3)}, + {(char *)"xxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 0, 3)}, + {(char *)"xxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 0)}, + {(char *)"xxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 1)}, + {(char *)"xxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 2)}, + {(char *)"xxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 0, 3, 3)}, + {(char *)"xy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 1)}, + {(char *)"xyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 0)}, + {(char *)"xyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 0)}, + {(char *)"xyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 1)}, + {(char *)"xyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 2)}, + {(char *)"xyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 0, 3)}, + {(char *)"xyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 1, 1)}, + {(char *)"xyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 0)}, + {(char *)"xyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 1)}, + {(char *)"xyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 2)}, + {(char *)"xyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 1, 3)}, + {(char *)"xyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 2)}, + {(char *)"xyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 0)}, + {(char *)"xyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 1)}, + {(char *)"xyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 2, 2)}, + {(char *)"xyzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 2, 3)}, + {(char *)"xyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 1, 3)}, + {(char *)"xywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 0)}, + {(char *)"xywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 1)}, + {(char *)"xywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 1, 3, 2)}, + {(char *)"xyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 1, 3, 3)}, + {(char *)"xz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 2)}, + {(char *)"xzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 0)}, + {(char *)"xzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 0)}, + {(char *)"xzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 1)}, + {(char *)"xzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 2)}, + {(char *)"xzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 0, 3)}, + {(char *)"xzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 1)}, + {(char *)"xzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 0)}, + {(char *)"xzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 1)}, + {(char *)"xzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 1, 2)}, + {(char *)"xzyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 1, 3)}, + {(char *)"xzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 2, 2)}, + {(char *)"xzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 0)}, + {(char *)"xzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 1)}, + {(char *)"xzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 2)}, + {(char *)"xzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 2, 3)}, + {(char *)"xzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 2, 3)}, + {(char *)"xzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 0)}, + {(char *)"xzwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 2, 3, 1)}, + {(char *)"xzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 2)}, + {(char *)"xzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 2, 3, 3)}, + {(char *)"xw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(0, 3)}, + {(char *)"xwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 0)}, + {(char *)"xwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 0)}, + {(char *)"xwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 1)}, + {(char *)"xwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 2)}, + {(char *)"xwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 0, 3)}, + {(char *)"xwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 1)}, + {(char *)"xwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 0)}, + {(char *)"xwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 1)}, + {(char *)"xwyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 1, 2)}, + {(char *)"xwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 1, 3)}, + {(char *)"xwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(0, 3, 2)}, + {(char *)"xwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 0)}, + {(char *)"xwzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(0, 3, 2, 1)}, + {(char *)"xwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 2)}, + {(char *)"xwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 2, 3)}, + {(char *)"xww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(0, 3, 3)}, + {(char *)"xwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 0)}, + {(char *)"xwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 1)}, + {(char *)"xwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 2)}, + {(char *)"xwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(0, 3, 3, 3)}, + {(char *)"yx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 0)}, + {(char *)"yxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 0)}, + {(char *)"yxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 0)}, + {(char *)"yxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 1)}, + {(char *)"yxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 2)}, + {(char *)"yxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 0, 3)}, + {(char *)"yxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 0, 1)}, + {(char *)"yxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 0)}, + {(char *)"yxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 1)}, + {(char *)"yxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 2)}, + {(char *)"yxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 1, 3)}, + {(char *)"yxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 2)}, + {(char *)"yxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 0)}, + {(char *)"yxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 1)}, + {(char *)"yxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 2, 2)}, + {(char *)"yxzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 2, 3)}, + {(char *)"yxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 0, 3)}, + {(char *)"yxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 0)}, + {(char *)"yxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 1)}, + {(char *)"yxwz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 0, 3, 2)}, + {(char *)"yxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 0, 3, 3)}, + {(char *)"yy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(1, 1)}, + {(char *)"yyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 0)}, + {(char *)"yyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 0)}, + {(char *)"yyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 1)}, + {(char *)"yyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 2)}, + {(char *)"yyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 0, 3)}, + {(char *)"yyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 1)}, + {(char *)"yyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 0)}, + {(char *)"yyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 1)}, + {(char *)"yyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 2)}, + {(char *)"yyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 1, 3)}, + {(char *)"yyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 2)}, + {(char *)"yyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 0)}, + {(char *)"yyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 1)}, + {(char *)"yyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 2)}, + {(char *)"yyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 2, 3)}, + {(char *)"yyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 1, 3)}, + {(char *)"yywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 0)}, + {(char *)"yywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 1)}, + {(char *)"yywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 2)}, + {(char *)"yyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 1, 3, 3)}, + {(char *)"yz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 2)}, + {(char *)"yzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 0)}, + {(char *)"yzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 0)}, + {(char *)"yzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 1)}, + {(char *)"yzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 0, 2)}, + {(char *)"yzxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 0, 3)}, + {(char *)"yzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 1)}, + {(char *)"yzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 0)}, + {(char *)"yzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 1)}, + {(char *)"yzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 2)}, + {(char *)"yzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 1, 3)}, + {(char *)"yzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 2, 2)}, + {(char *)"yzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 0)}, + {(char *)"yzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 1)}, + {(char *)"yzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 2)}, + {(char *)"yzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 2, 3)}, + {(char *)"yzw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 2, 3)}, + {(char *)"yzwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 2, 3, 0)}, + {(char *)"yzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 1)}, + {(char *)"yzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 2)}, + {(char *)"yzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 2, 3, 3)}, + {(char *)"yw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(1, 3)}, + {(char *)"ywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 0)}, + {(char *)"ywxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 0)}, + {(char *)"ywxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 1)}, + {(char *)"ywxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 0, 2)}, + {(char *)"ywxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 0, 3)}, + {(char *)"ywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 1)}, + {(char *)"ywyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 0)}, + {(char *)"ywyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 1)}, + {(char *)"ywyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 2)}, + {(char *)"ywyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 1, 3)}, + {(char *)"ywz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(1, 3, 2)}, + {(char *)"ywzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(1, 3, 2, 0)}, + {(char *)"ywzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 1)}, + {(char *)"ywzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 2)}, + {(char *)"ywzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 2, 3)}, + {(char *)"yww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(1, 3, 3)}, + {(char *)"ywwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 0)}, + {(char *)"ywwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 1)}, + {(char *)"ywwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 2)}, + {(char *)"ywww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(1, 3, 3, 3)}, + {(char *)"zx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 0)}, + {(char *)"zxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 0)}, + {(char *)"zxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 0)}, + {(char *)"zxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 1)}, + {(char *)"zxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 2)}, + {(char *)"zxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 0, 3)}, + {(char *)"zxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 1)}, + {(char *)"zxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 0)}, + {(char *)"zxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 1)}, + {(char *)"zxyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 1, 2)}, + {(char *)"zxyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 1, 3)}, + {(char *)"zxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 0, 2)}, + {(char *)"zxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 0)}, + {(char *)"zxzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 1)}, + {(char *)"zxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 2)}, + {(char *)"zxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 2, 3)}, + {(char *)"zxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 0, 3)}, + {(char *)"zxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 0)}, + {(char *)"zxwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 0, 3, 1)}, + {(char *)"zxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 2)}, + {(char *)"zxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 0, 3, 3)}, + {(char *)"zy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 1)}, + {(char *)"zyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 0)}, + {(char *)"zyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 0)}, + {(char *)"zyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 1)}, + {(char *)"zyxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 0, 2)}, + {(char *)"zyxw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 0, 3)}, + {(char *)"zyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 1)}, + {(char *)"zyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 0)}, + {(char *)"zyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 1)}, + {(char *)"zyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 2)}, + {(char *)"zyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 1, 3)}, + {(char *)"zyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 1, 2)}, + {(char *)"zyzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 0)}, + {(char *)"zyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 1)}, + {(char *)"zyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 2)}, + {(char *)"zyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 2, 3)}, + {(char *)"zyw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 1, 3)}, + {(char *)"zywx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 1, 3, 0)}, + {(char *)"zywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 1)}, + {(char *)"zywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 2)}, + {(char *)"zyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 1, 3, 3)}, + {(char *)"zz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(2, 2)}, + {(char *)"zzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 0)}, + {(char *)"zzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 0)}, + {(char *)"zzxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 1)}, + {(char *)"zzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 2)}, + {(char *)"zzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 0, 3)}, + {(char *)"zzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 1)}, + {(char *)"zzyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 0)}, + {(char *)"zzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 1)}, + {(char *)"zzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 2)}, + {(char *)"zzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 1, 3)}, + {(char *)"zzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 2)}, + {(char *)"zzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 0)}, + {(char *)"zzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 1)}, + {(char *)"zzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 2)}, + {(char *)"zzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 2, 3)}, + {(char *)"zzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 2, 3)}, + {(char *)"zzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 0)}, + {(char *)"zzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 1)}, + {(char *)"zzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 2)}, + {(char *)"zzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 2, 3, 3)}, + {(char *)"zw", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(2, 3)}, + {(char *)"zwx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 0)}, + {(char *)"zwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 0)}, + {(char *)"zwxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 0, 1)}, + {(char *)"zwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 2)}, + {(char *)"zwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 0, 3)}, + {(char *)"zwy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(2, 3, 1)}, + {(char *)"zwyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(2, 3, 1, 0)}, + {(char *)"zwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 1)}, + {(char *)"zwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 2)}, + {(char *)"zwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 1, 3)}, + {(char *)"zwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 2)}, + {(char *)"zwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 0)}, + {(char *)"zwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 1)}, + {(char *)"zwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 2)}, + {(char *)"zwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 2, 3)}, + {(char *)"zww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(2, 3, 3)}, + {(char *)"zwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 0)}, + {(char *)"zwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 1)}, + {(char *)"zwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 2)}, + {(char *)"zwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(2, 3, 3, 3)}, + {(char *)"wx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 0)}, + {(char *)"wxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 0)}, + {(char *)"wxxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 0)}, + {(char *)"wxxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 1)}, + {(char *)"wxxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 2)}, + {(char *)"wxxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 0, 3)}, + {(char *)"wxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 1)}, + {(char *)"wxyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 0)}, + {(char *)"wxyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 1)}, + {(char *)"wxyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 1, 2)}, + {(char *)"wxyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 1, 3)}, + {(char *)"wxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 0, 2)}, + {(char *)"wxzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 0)}, + {(char *)"wxzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 0, 2, 1)}, + {(char *)"wxzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 2)}, + {(char *)"wxzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 2, 3)}, + {(char *)"wxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 0, 3)}, + {(char *)"wxwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 0)}, + {(char *)"wxwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 1)}, + {(char *)"wxwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 2)}, + {(char *)"wxww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 0, 3, 3)}, + {(char *)"wy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 1)}, + {(char *)"wyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 0)}, + {(char *)"wyxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 0)}, + {(char *)"wyxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 1)}, + {(char *)"wyxz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 0, 2)}, + {(char *)"wyxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 0, 3)}, + {(char *)"wyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 1)}, + {(char *)"wyyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 0)}, + {(char *)"wyyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 1)}, + {(char *)"wyyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 2)}, + {(char *)"wyyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 1, 3)}, + {(char *)"wyz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 1, 2)}, + {(char *)"wyzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 1, 2, 0)}, + {(char *)"wyzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 1)}, + {(char *)"wyzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 2)}, + {(char *)"wyzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 2, 3)}, + {(char *)"wyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 1, 3)}, + {(char *)"wywx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 0)}, + {(char *)"wywy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 1)}, + {(char *)"wywz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 2)}, + {(char *)"wyww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 1, 3, 3)}, + {(char *)"wz", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE2(3, 2)}, + {(char *)"wzx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 0)}, + {(char *)"wzxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 0)}, + {(char *)"wzxy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 0, 1)}, + {(char *)"wzxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 2)}, + {(char *)"wzxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 0, 3)}, + {(char *)"wzy", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE3(3, 2, 1)}, + {(char *)"wzyx", (getter)Vector_swizzle_get, (setter)Vector_swizzle_set, NULL, SWIZZLE4(3, 2, 1, 0)}, + {(char *)"wzyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 1)}, + {(char *)"wzyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 2)}, + {(char *)"wzyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 1, 3)}, + {(char *)"wzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 2)}, + {(char *)"wzzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 0)}, + {(char *)"wzzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 1)}, + {(char *)"wzzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 2)}, + {(char *)"wzzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 2, 3)}, + {(char *)"wzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 2, 3)}, + {(char *)"wzwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 0)}, + {(char *)"wzwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 1)}, + {(char *)"wzwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 2)}, + {(char *)"wzww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 2, 3, 3)}, + {(char *)"ww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE2(3, 3)}, + {(char *)"wwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 0)}, + {(char *)"wwxx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 0)}, + {(char *)"wwxy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 1)}, + {(char *)"wwxz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 2)}, + {(char *)"wwxw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 0, 3)}, + {(char *)"wwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 1)}, + {(char *)"wwyx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 0)}, + {(char *)"wwyy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 1)}, + {(char *)"wwyz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 2)}, + {(char *)"wwyw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 1, 3)}, + {(char *)"wwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 2)}, + {(char *)"wwzx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 0)}, + {(char *)"wwzy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 1)}, + {(char *)"wwzz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 2)}, + {(char *)"wwzw", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 2, 3)}, + {(char *)"www", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE3(3, 3, 3)}, + {(char *)"wwwx", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 0)}, + {(char *)"wwwy", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 1)}, + {(char *)"wwwz", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 2)}, + {(char *)"wwww", (getter)Vector_swizzle_get, (setter)NULL, NULL, SWIZZLE4(3, 3, 3, 3)}, #undef AXIS_FROM_CHAR -#undef SWIZZLE -#undef _VA_SWIZZLE_1 -#undef _VA_SWIZZLE_2 -#undef _VA_SWIZZLE_3 -#undef _VA_SWIZZLE_4 +#undef SWIZZLE1 +#undef SWIZZLE2 +#undef SWIZZLE3 +#undef SWIZZLE4 +#undef _SWIZZLE1 +#undef _SWIZZLE2 +#undef _SWIZZLE3 +#undef _SWIZZLE4 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; /** - * Python script used to make swizzle array: - * - * \code{.py} - * SWIZZLE_BITS_PER_AXIS = 3 - * SWIZZLE_VALID_AXIS = 0x4 - * - * axis_dict = {} - * axis_pos = {'x': 0, 'y': 1, 'z': 2, 'w': 3} - * axises = 'xyzw' - * while len(axises) >= 2: - * for axis_0 in axises: - * axis_0_pos = axis_pos[axis_0] - * for axis_1 in axises: - * axis_1_pos = axis_pos[axis_1] - * axis_dict[axis_0 + axis_1] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS))' % - * (axis_0_pos, axis_1_pos)) - * if len(axises) > 2: - * for axis_2 in axises: - * axis_2_pos = axis_pos[axis_2] - * axis_dict[axis_0 + axis_1 + axis_2] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)))' % - * (axis_0_pos, axis_1_pos, axis_2_pos)) - * if len(axises) > 3: - * for axis_3 in axises: - * axis_3_pos = axis_pos[axis_3] - * axis_dict[axis_0 + axis_1 + axis_2 + axis_3] = ( - * '((%s | SWIZZLE_VALID_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << SWIZZLE_BITS_PER_AXIS) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 2)) | ' - * '((%s | SWIZZLE_VALID_AXIS) << (SWIZZLE_BITS_PER_AXIS * 3))) ' % - * (axis_0_pos, axis_1_pos, axis_2_pos, axis_3_pos)) - * - * axises = axises[:-1] - * - * - * items = list(axis_dict.items()) - * items.sort(key=lambda a: a[0].replace('x', '0').replace('y', '1').replace('z', '2').replace('w', '3')) - * - * unique = set() - * for key, val in items: - * num = eval(val) - * set_str = 'Vector_swizzle_set' if (len(set(key)) == len(key)) else 'NULL' - * key_args = ', '.join(["'%s'" % c for c in key.upper()]) - * print('\t{(char *)"%s", %s(getter)Vector_swizzle_get, (setter)%s, NULL, SWIZZLE(%s)},' % - * (key, (' ' * (4 - len(key))), set_str, key_args)) - * unique.add(num) - * - * if len(unique) != len(items): - * print("ERROR, duplicate values found") - * \endcode - */ - -/* ROW VECTOR Multiplication - Vector X Matrix + * Row vector multiplication - (Vector * Matrix) + * <pre> * [x][y][z] * [1][4][7] * [2][5][8] * [3][6][9] - * vector/matrix multiplication IS NOT COMMUTATIVE!!!! */ + * </pre> + * \note vector/matrix multiplication is not commutative. + */ static int row_vector_multiplication(float r_vec[MAX_DIMENSIONS], VectorObject *vec, MatrixObject *mat) { float vec_cpy[MAX_DIMENSIONS]; @@ -2863,10 +2880,11 @@ static struct PyMethodDef Vector_methods[] = { }; -/* Note - * Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing - * but this means for eg that - * (vec * mat) and (mat * vec) both get sent to Vector_mul and it needs to sort out the order +/** + * Note: + * #Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing + * but this means for eg that (vec * mat) and (mat * vec) + * both get sent to Vector_mul and it needs to sort out the order */ PyDoc_STRVAR(vector_doc, @@ -3010,6 +3028,11 @@ PyObject *Vector_CreatePyObject( return (PyObject *)self; } +/** + * Create a vector that wraps existing memory. + * + * \param vec: Use this vector in-place. + */ PyObject *Vector_CreatePyObject_wrap( float *vec, const int size, PyTypeObject *base_type) @@ -3036,6 +3059,10 @@ PyObject *Vector_CreatePyObject_wrap( return (PyObject *) self; } +/** + * Create a vector where the value is defined by registered callbacks, + * see: #Mathutils_RegisterCallback + */ PyObject *Vector_CreatePyObject_cb( PyObject *cb_user, int size, unsigned char cb_type, unsigned char cb_subtype) @@ -3052,6 +3079,9 @@ PyObject *Vector_CreatePyObject_cb( return (PyObject *)self; } +/** + * \param vec: Initialized vector value to use in-place, allocated with: PyMem_Malloc + */ PyObject *Vector_CreatePyObject_alloc( float *vec, const int size, PyTypeObject *base_type) diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index 1eb8644a9a6..8162f8e9d0c 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -761,7 +761,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P py_tricoords_fast_items = PySequence_Fast_ITEMS(py_tricoords_fast); for (j = 0; j < 3; j++) { - tri[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + tri[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(tri[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -812,7 +812,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P p_plink_prev = &plink->next; for (j = 0; j < py_tricoords_len; j++) { - plink->poly[j] = (unsigned int)_PyLong_AsInt(py_tricoords_fast_items[j]); + plink->poly[j] = PyC_Long_AsU32(py_tricoords_fast_items[j]); if (UNLIKELY(plink->poly[j] >= (unsigned int)coords_len)) { PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", @@ -1049,6 +1049,8 @@ static DerivedMesh *bvh_get_derived_mesh( const char *funcname, struct Scene *scene, Object *ob, bool use_deform, bool use_render, bool use_cage) { + /* TODO: This doesn't work currently because of eval_ctx. */ +#if 0 /* we only need minimum mesh data for topology and vertex locations */ CustomDataMask mask = CD_MASK_BAREMESH; @@ -1096,6 +1098,11 @@ static DerivedMesh *bvh_get_derived_mesh( } } } +#else + UNUSED_VARS(funcname, scene, ob, use_deform, use_render, use_cage); +#endif + + return NULL; } PyDoc_STRVAR(C_BVHTree_FromObject_doc, @@ -1156,7 +1163,6 @@ static PyObject *C_BVHTree_FromObject(PyObject *UNUSED(cls), PyObject *args, PyO /* Get data for tessellation */ { - DM_ensure_looptri(dm); lt = dm->getLoopTriArray(dm); tris_len = (unsigned int)dm->getNumLoopTri(dm); diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c index 868e4b38408..1dc18dbe509 100644 --- a/source/blender/python/mathutils/mathutils_geometry.c +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -1279,7 +1279,7 @@ static PyObject *M_Geometry_tessellate_polygon(PyObject *UNUSED(self), PyObject index = 0; dl_face = dl->index; while (index < dl->parts) { - PyList_SET_ITEM(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2])); + PyList_SET_ITEM(tri_list, index, PyC_Tuple_Pack_I32(dl_face[0], dl_face[1], dl_face[2])); dl_face += 3; index++; } |