Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2017-10-09 12:49:27 +0300
committerCampbell Barton <ideasman42@gmail.com>2017-10-09 12:49:27 +0300
commita5b4b0f21c1ae8c96e4fea9abdcfac2fab1cf300 (patch)
tree0658d8bdfb8ec03652aa04f82ee8a4d243ec6370 /source/blender/python
parentd68f698cf0321477c0734474150eb4bc43c4e85f (diff)
parentabcda06934aba054de8540b66b13c2bbc5f8f515 (diff)
Merge branch '28' into custom-manipulatorscustom-manipulators
Diffstat (limited to 'source/blender/python')
-rw-r--r--source/blender/python/CMakeLists.txt1
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c43
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c84
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c11
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_meshdata.c11
-rw-r--r--source/blender/python/gawain/CMakeLists.txt47
-rw-r--r--source/blender/python/gawain/gwn_py_api.c63
-rw-r--r--source/blender/python/gawain/gwn_py_api.h30
-rw-r--r--source/blender/python/gawain/gwn_py_types.c823
-rw-r--r--source/blender/python/gawain/gwn_py_types.h67
-rw-r--r--source/blender/python/generic/bgl.c135
-rw-r--r--source/blender/python/generic/bpy_internal_import.c25
-rw-r--r--source/blender/python/generic/idprop_py_api.c6
-rw-r--r--source/blender/python/generic/py_capi_utils.c187
-rw-r--r--source/blender/python/generic/py_capi_utils.h43
-rw-r--r--source/blender/python/generic/python_utildefines.h6
-rw-r--r--source/blender/python/intern/CMakeLists.txt6
-rw-r--r--source/blender/python/intern/bpy.c27
-rw-r--r--source/blender/python/intern/bpy_app.c7
-rw-r--r--source/blender/python/intern/bpy_app_alembic.c6
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c7
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c5
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c7
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c7
-rw-r--r--source/blender/python/intern/bpy_app_opensubdiv.c7
-rw-r--r--source/blender/python/intern/bpy_app_openvdb.c7
-rw-r--r--source/blender/python/intern/bpy_app_sdl.c6
-rw-r--r--source/blender/python/intern/bpy_interface.c3
-rw-r--r--source/blender/python/intern/bpy_library_load.c14
-rw-r--r--source/blender/python/intern/bpy_library_write.c21
-rw-r--r--source/blender/python/intern/bpy_manipulator_wrap.c43
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_operator_wrap.c10
-rw-r--r--source/blender/python/intern/bpy_props.c257
-rw-r--r--source/blender/python/intern/bpy_rna.c175
-rw-r--r--source/blender/python/intern/bpy_rna_array.c4
-rw-r--r--source/blender/python/intern/bpy_rna_driver.c10
-rw-r--r--source/blender/python/intern/bpy_rna_id_collection.c8
-rw-r--r--source/blender/python/intern/bpy_rna_manipulator.c266
-rw-r--r--source/blender/python/intern/bpy_util.h4
-rw-r--r--source/blender/python/intern/bpy_utils_units.c24
-rw-r--r--source/blender/python/intern/gpu.c21
-rw-r--r--source/blender/python/intern/gpu.h2
-rw-r--r--source/blender/python/intern/gpu_offscreen.c42
-rw-r--r--source/blender/python/intern/gpu_py_matrix.c552
-rw-r--r--source/blender/python/intern/gpu_py_select.c92
-rw-r--r--source/blender/python/mathutils/mathutils.c4
-rw-r--r--source/blender/python/mathutils/mathutils.h11
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c67
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h5
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c890
-rw-r--r--source/blender/python/mathutils/mathutils_bvhtree.c12
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c2
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,
+ &params.id,
+ bpygwn_ParseVertCompType, &params.comp_type,
+ &params.len,
+ bpygwn_ParseVertFetchMode, &params.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,
+ &params.len,
+ &BPyGwn_VertFormat_Type, &params.py_fmt))
+ {
+ return NULL;
+ }
+
+ struct Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&params.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,
+ &params.id,
+ &params.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, &params.type_id,
+ &BPyGwn_VertBuf_Type, &params.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,
+ &params.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",
+ &params.id,
+ PyC_ParseBool, &params.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",
+ &params.id,
+ &params.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",
+ &params.id,
+ &params.values[0], &params.values[1], &params.values[2], &params.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,
&params.self,
&params.target,
&params.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,
+ &params.self,
+ &params.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,
+ &params.self,
+ &params.target,
+ &params.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,
+ &params.self,
+ &params.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++;
}