diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-07-15 08:01:47 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-07-15 08:01:47 +0400 |
commit | 3a6158a8bf2b5518ef3a126b003debeba6bbea90 (patch) | |
tree | e4fe01e9fbc035dd116c3abf8ba6976b696196cb /source/blender/python/mathutils | |
parent | 5ff9acfd28211d90045e9dc08da7790099b9c462 (diff) |
move mathutils into its own lib.
Diffstat (limited to 'source/blender/python/mathutils')
-rw-r--r-- | source/blender/python/mathutils/CMakeLists.txt | 52 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils.c | 384 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils.h | 111 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Color.c | 870 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Color.h | 55 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Euler.c | 721 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Euler.h | 60 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Matrix.c | 2041 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Matrix.h | 63 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Quaternion.c | 1164 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Quaternion.h | 55 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Vector.c | 2410 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_Vector.h | 52 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_geometry.c | 1135 | ||||
-rw-r--r-- | source/blender/python/mathutils/mathutils_geometry.h | 43 |
15 files changed, 9216 insertions, 0 deletions
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt new file mode 100644 index 00000000000..b28496d612e --- /dev/null +++ b/source/blender/python/mathutils/CMakeLists.txt @@ -0,0 +1,52 @@ +# ***** 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 + . + ../../blenlib + ../../blenkernel + ../../makesdna + ../../../../intern/guardedalloc +) + +set(INC_SYS + ${PYTHON_INCLUDE_DIRS} +) + +set(SRC + mathutils.c + mathutils_Color.c + mathutils_Euler.c + mathutils_Matrix.c + mathutils_Quaternion.c + mathutils_Vector.c + mathutils_geometry.c + + mathutils.h + mathutils_Color.h + mathutils_Euler.h + mathutils_Matrix.h + mathutils_Quaternion.h + mathutils_Vector.h + mathutils_geometry.h +) + + +blender_add_lib(bf_python_mathutils "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c new file mode 100644 index 00000000000..50b75b09cb2 --- /dev/null +++ b/source/blender/python/mathutils/mathutils.c @@ -0,0 +1,384 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils.c + * \ingroup pygen + */ + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +PyDoc_STRVAR(M_Mathutils_doc, +"This module provides access to matrices, eulers, quaternions and vectors." +); +static int mathutils_array_parse_fast(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix) +{ + PyObject *value_fast= NULL; + PyObject *item; + + int i, size; + + /* non list/tuple cases */ + if(!(value_fast=PySequence_Fast(value, error_prefix))) { + /* PySequence_Fast sets the error */ + return -1; + } + + size= PySequence_Fast_GET_SIZE(value_fast); + + if(size > array_max || size < array_min) { + if (array_max == array_min) { + PyErr_Format(PyExc_ValueError, + "%.200s: sequence size is %d, expected %d", + error_prefix, size, array_max); + } + else { + PyErr_Format(PyExc_ValueError, + "%.200s: sequence size is %d, expected [%d - %d]", + error_prefix, size, array_min, array_max); + } + Py_DECREF(value_fast); + return -1; + } + + i= size; + do { + i--; + if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + "%.200s: sequence index %d expected a number, " + "found '%.200s' type, ", + error_prefix, i, Py_TYPE(item)->tp_name); + Py_DECREF(value_fast); + return -1; + } + } while(i); + + Py_XDECREF(value_fast); + return size; +} + +/* helper functionm returns length of the 'value', -1 on error */ +int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix) +{ +#if 1 /* approx 6x speedup for mathutils types */ + int size; + + if( (VectorObject_Check(value) && (size= ((VectorObject *)value)->size)) || + (EulerObject_Check(value) && (size= 3)) || + (QuaternionObject_Check(value) && (size= 4)) || + (ColorObject_Check(value) && (size= 3)) + ) { + if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) { + return -1; + } + + if(size > array_max || size < array_min) { + if (array_max == array_min) { + PyErr_Format(PyExc_ValueError, + "%.200s: sequence size is %d, expected %d", + error_prefix, size, array_max); + } + else { + PyErr_Format(PyExc_ValueError, + "%.200s: sequence size is %d, expected [%d - %d]", + error_prefix, size, array_min, array_max); + } + return -1; + } + + memcpy(array, ((BaseMathObject *)value)->data, size * sizeof(float)); + return size; + } + else +#endif + { + return mathutils_array_parse_fast(array, array_min, array_max, value, error_prefix); + } +} + +int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix) +{ + if(EulerObject_Check(value)) { + if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) { + return -1; + } + else { + eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order); + return 0; + } + } + else if (QuaternionObject_Check(value)) { + if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) { + return -1; + } + else { + float tquat[4]; + normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat); + quat_to_mat3(rmat, tquat); + return 0; + } + } + else if (MatrixObject_Check(value)) { + if(BaseMath_ReadCallback((BaseMathObject *)value) == -1) { + return -1; + } + else if(((MatrixObject *)value)->col_size < 3 || ((MatrixObject *)value)->row_size < 3) { + PyErr_Format(PyExc_ValueError, + "%.200s: matrix must have minimum 3x3 dimensions", + error_prefix); + return -1; + } + else { + matrix_as_3x3(rmat, (MatrixObject *)value); + normalize_m3(rmat); + return 0; + } + } + else { + PyErr_Format(PyExc_TypeError, + "%.200s: expected a Euler, Quaternion or Matrix type, " + "found %.200s", error_prefix, Py_TYPE(value)->tp_name); + return -1; + } +} + + +//----------------------------------MATRIX FUNCTIONS-------------------- + + +/* Utility functions */ + +// LomontRRDCompare4, Ever Faster Float Comparisons by Randy Dillon +#define SIGNMASK(i) (-(int)(((unsigned int)(i))>>31)) + +int EXPP_FloatsAreEqual(float af, float bf, int maxDiff) +{ // solid, fast routine across all platforms + // with constant time behavior + int ai = *(int *)(&af); + int bi = *(int *)(&bf); + int test = SIGNMASK(ai^bi); + int diff, v1, v2; + + assert((0 == test) || (0xFFFFFFFF == test)); + diff = (ai ^ (test & 0x7fffffff)) - bi; + v1 = maxDiff + diff; + v2 = maxDiff - diff; + return (v1|v2) >= 0; +} + +/*---------------------- EXPP_VectorsAreEqual ------------------------- + Builds on EXPP_FloatsAreEqual to test vectors */ +int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps) +{ + int x; + for (x=0; x< size; x++){ + if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0) + return 0; + } + return 1; +} + + +/* Mathutils Callbacks */ + +/* for mathutils internal use only, eventually should re-alloc but to start with we only have a few users */ +static Mathutils_Callback *mathutils_callbacks[8] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +int Mathutils_RegisterCallback(Mathutils_Callback *cb) +{ + int i; + + /* find the first free slot */ + for(i= 0; mathutils_callbacks[i]; i++) { + if(mathutils_callbacks[i]==cb) /* already registered? */ + return i; + } + + mathutils_callbacks[i] = cb; + return i; +} + +/* use macros to check for NULL */ +int _BaseMathObject_ReadCallback(BaseMathObject *self) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->get(self, self->cb_subtype) != -1) + return 0; + + if(!PyErr_Occurred()) { + PyErr_Format(PyExc_RuntimeError, + "%s read, user has become invalid", + Py_TYPE(self)->tp_name); + } + return -1; +} + +int _BaseMathObject_WriteCallback(BaseMathObject *self) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->set(self, self->cb_subtype) != -1) + return 0; + + if(!PyErr_Occurred()) { + PyErr_Format(PyExc_RuntimeError, + "%s write, user has become invalid", + Py_TYPE(self)->tp_name); + } + return -1; +} + +int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->get_index(self, self->cb_subtype, index) != -1) + return 0; + + if(!PyErr_Occurred()) { + PyErr_Format(PyExc_RuntimeError, + "%s read index, user has become invalid", + Py_TYPE(self)->tp_name); + } + return -1; +} + +int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index) +{ + Mathutils_Callback *cb= mathutils_callbacks[self->cb_type]; + if(cb->set_index(self, self->cb_subtype, index) != -1) + return 0; + + if(!PyErr_Occurred()) { + PyErr_Format(PyExc_RuntimeError, + "%s write index, user has become invalid", + Py_TYPE(self)->tp_name); + } + return -1; +} + +/* BaseMathObject generic functions for all mathutils types */ +char BaseMathObject_Owner_doc[] = "The item this is wrapping or None (readonly)."; +PyObject *BaseMathObject_getOwner(BaseMathObject *self, void *UNUSED(closure)) +{ + PyObject *ret= self->cb_user ? self->cb_user : Py_None; + Py_INCREF(ret); + return ret; +} + +char BaseMathObject_Wrapped_doc[] = "True when this object wraps external data (readonly).\n\n:type: boolean"; +PyObject *BaseMathObject_getWrapped(BaseMathObject *self, void *UNUSED(closure)) +{ + return PyBool_FromLong((self->wrapped == Py_WRAP) ? 1:0); +} + +int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->cb_user); + return 0; +} + +int BaseMathObject_clear(BaseMathObject *self) +{ + Py_CLEAR(self->cb_user); + return 0; +} + +void BaseMathObject_dealloc(BaseMathObject *self) +{ + /* only free non wrapped */ + if(self->wrapped != Py_WRAP) { + PyMem_Free(self->data); + } + + if(self->cb_user) { + PyObject_GC_UnTrack(self); + BaseMathObject_clear(self); + } + + Py_TYPE(self)->tp_free(self); // PyObject_DEL(self); // breaks subtypes +} + +/*----------------------------MODULE INIT-------------------------*/ +static struct PyMethodDef M_Mathutils_methods[] = { + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_Mathutils_module_def = { + PyModuleDef_HEAD_INIT, + "mathutils", /* m_name */ + M_Mathutils_doc, /* m_doc */ + 0, /* m_size */ + M_Mathutils_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +PyMODINIT_FUNC PyInit_mathutils(void) +{ + PyObject *submodule; + PyObject *item; + + if(PyType_Ready(&vector_Type) < 0) + return NULL; + if(PyType_Ready(&matrix_Type) < 0) + return NULL; + if(PyType_Ready(&euler_Type) < 0) + return NULL; + if(PyType_Ready(&quaternion_Type) < 0) + return NULL; + if(PyType_Ready(&color_Type) < 0) + return NULL; + + submodule = PyModule_Create(&M_Mathutils_module_def); + + /* each type has its own new() function */ + PyModule_AddObject(submodule, "Vector", (PyObject *)&vector_Type); + PyModule_AddObject(submodule, "Matrix", (PyObject *)&matrix_Type); + PyModule_AddObject(submodule, "Euler", (PyObject *)&euler_Type); + PyModule_AddObject(submodule, "Quaternion", (PyObject *)&quaternion_Type); + PyModule_AddObject(submodule, "Color", (PyObject *)&color_Type); + + /* submodule */ + PyModule_AddObject(submodule, "geometry", (item=PyInit_mathutils_geometry())); + /* XXX, python doesnt do imports with this usefully yet + * 'from mathutils.geometry import PolyFill' + * ...fails without this. */ + PyDict_SetItemString(PyThreadState_GET()->interp->modules, "mathutils.geometry", item); + Py_INCREF(item); + + mathutils_matrix_vector_cb_index= Mathutils_RegisterCallback(&mathutils_matrix_vector_cb); + + return submodule; +} diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h new file mode 100644 index 00000000000..7454cfe78b3 --- /dev/null +++ b/source/blender/python/mathutils/mathutils.h @@ -0,0 +1,111 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file blender/python/generic/mathutils.h + * \ingroup pygen + */ + +//Include this file for access to vector, quat, matrix, euler, etc... + +#ifndef MATHUTILS_H +#define MATHUTILS_H + +/* Can cast different mathutils types to this, use for generic funcs */ + +extern char BaseMathObject_Wrapped_doc[]; +extern char BaseMathObject_Owner_doc[]; + +#define BASE_MATH_MEMBERS(_data) \ + PyObject_VAR_HEAD \ + float *_data; /* array of data (alias), wrapped status depends on wrapped status */ \ + PyObject *cb_user; /* if this vector references another object, otherwise NULL, *Note* this owns its reference */ \ + unsigned char cb_type; /* which user funcs do we adhere to, RNA, GameObject, etc */ \ + unsigned char cb_subtype; /* subtype: location, rotation... to avoid defining many new functions for every attribute of the same type */ \ + unsigned char wrapped; /* wrapped data type? */ \ + +typedef struct { + BASE_MATH_MEMBERS(data) +} BaseMathObject; + +#include "mathutils_Vector.h" +#include "mathutils_Matrix.h" +#include "mathutils_Quaternion.h" +#include "mathutils_Euler.h" +#include "mathutils_Color.h" +#include "mathutils_geometry.h" + +PyObject *BaseMathObject_getOwner( BaseMathObject * self, void * ); +PyObject *BaseMathObject_getWrapped( BaseMathObject *self, void * ); + +int BaseMathObject_traverse(BaseMathObject *self, visitproc visit, void *arg); +int BaseMathObject_clear(BaseMathObject *self); +void BaseMathObject_dealloc(BaseMathObject * self); + +PyMODINIT_FUNC PyInit_mathutils(void); + +int EXPP_FloatsAreEqual(float A, float B, int floatSteps); +int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps); + +#define Py_NEW 1 +#define Py_WRAP 2 + +typedef struct Mathutils_Callback Mathutils_Callback; + +typedef int (*BaseMathCheckFunc)(BaseMathObject *); /* checks the user is still valid */ +typedef int (*BaseMathGetFunc)(BaseMathObject *, int); /* gets the vector from the user */ +typedef int (*BaseMathSetFunc)(BaseMathObject *, int); /* sets the users vector values once the vector is modified */ +typedef int (*BaseMathGetIndexFunc)(BaseMathObject *, int, int); /* same as above but only for an index */ +typedef int (*BaseMathSetIndexFunc)(BaseMathObject *, int, int); /* same as above but only for an index */ + +struct Mathutils_Callback { + BaseMathCheckFunc check; + BaseMathGetFunc get; + BaseMathSetFunc set; + BaseMathGetIndexFunc get_index; + BaseMathSetIndexFunc set_index; +}; + +int Mathutils_RegisterCallback(Mathutils_Callback *cb); + +int _BaseMathObject_ReadCallback(BaseMathObject *self); +int _BaseMathObject_WriteCallback(BaseMathObject *self); +int _BaseMathObject_ReadIndexCallback(BaseMathObject *self, int index); +int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); + +/* since this is called so often avoid where possible */ +#define BaseMath_ReadCallback(_self) (((_self)->cb_user ? _BaseMathObject_ReadCallback((BaseMathObject *)_self):0)) +#define BaseMath_WriteCallback(_self) (((_self)->cb_user ?_BaseMathObject_WriteCallback((BaseMathObject *)_self):0)) +#define BaseMath_ReadIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_ReadIndexCallback((BaseMathObject *)_self, _index):0)) +#define BaseMath_WriteIndexCallback(_self, _index) (((_self)->cb_user ? _BaseMathObject_WriteIndexCallback((BaseMathObject *)_self, _index):0)) + +/* utility func */ +int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix); +int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix); + +#endif /* MATHUTILS_H */ diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c new file mode 100644 index 00000000000..d0c7ec72cea --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -0,0 +1,870 @@ +/* + * $Id$ + * + * ***** 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 ***** + */ + +/** \file blender/python/generic/mathutils_Color.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#define COLOR_SIZE 3 + +//----------------------------------mathutils.Color() ------------------- +//makes a new color for you to play with +static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + float col[3]= {0.0f, 0.0f, 0.0f}; + + if(kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, + "mathutils.Color(): " + "takes no keyword args"); + return NULL; + } + + switch(PyTuple_GET_SIZE(args)) { + case 0: + break; + case 1: + if((mathutils_array_parse(col, COLOR_SIZE, COLOR_SIZE, PyTuple_GET_ITEM(args, 0), "mathutils.Color()")) == -1) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, + "mathutils.Color(): " + "more then a single arg given"); + return NULL; + } + return newColorObject(col, Py_NEW, type); +} + +//-----------------------------METHODS---------------------------- + +/* note: BaseMath_ReadCallback must be called beforehand */ +static PyObject *Color_ToTupleExt(ColorObject *self, int ndigits) +{ + PyObject *ret; + int i; + + ret= PyTuple_New(COLOR_SIZE); + + if(ndigits >= 0) { + for(i= 0; i < COLOR_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->col[i], ndigits))); + } + } + else { + for(i= 0; i < COLOR_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->col[i])); + } + } + + return ret; +} + +PyDoc_STRVAR(Color_copy_doc, +".. function:: copy()\n" +"\n" +" Returns a copy of this color.\n" +"\n" +" :return: A copy of the color.\n" +" :rtype: :class:`Color`\n" +"\n" +" .. note:: use this to get a copy of a wrapped color with\n" +" no reference to the original data.\n" +); +static PyObject *Color_copy(ColorObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return newColorObject(self->col, Py_NEW, Py_TYPE(self)); +} + +//----------------------------print object (internal)-------------- +//print the object to screen + +static PyObject *Color_repr(ColorObject * self) +{ + PyObject *ret, *tuple; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + tuple= Color_ToTupleExt(self, -1); + + ret= PyUnicode_FromFormat("Color(%R)", tuple); + + Py_DECREF(tuple); + return ret; +} + +//------------------------tp_richcmpr +//returns -1 execption, 0 false, 1 true +static PyObject* Color_richcmpr(PyObject *a, PyObject *b, int op) +{ + PyObject *res; + int ok= -1; /* zero is true */ + + if (ColorObject_Check(a) && ColorObject_Check(b)) { + ColorObject *colA= (ColorObject*)a; + ColorObject *colB= (ColorObject*)b; + + if(BaseMath_ReadCallback(colA) == -1 || BaseMath_ReadCallback(colB) == -1) + return NULL; + + ok= EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1; + } + + switch (op) { + case Py_NE: + ok = !ok; /* pass through */ + case Py_EQ: + res = ok ? Py_False : Py_True; + break; + + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + res = Py_NotImplemented; + break; + default: + PyErr_BadArgument(); + return NULL; + } + + return Py_INCREF(res), res; +} + +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Color_len(ColorObject *UNUSED(self)) +{ + return COLOR_SIZE; +} +//----------------------------object[]--------------------------- +//sequence accessor (get) +static PyObject *Color_item(ColorObject * self, int i) +{ + if(i<0) i= COLOR_SIZE-i; + + if(i < 0 || i >= COLOR_SIZE) { + PyErr_SetString(PyExc_IndexError, + "color[attribute]: " + "array index out of range"); + return NULL; + } + + if(BaseMath_ReadIndexCallback(self, i) == -1) + return NULL; + + return PyFloat_FromDouble(self->col[i]); + +} +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Color_ass_item(ColorObject * self, int i, PyObject *value) +{ + float f = PyFloat_AsDouble(value); + + if(f == -1 && PyErr_Occurred()) { // parsed item not a number + PyErr_SetString(PyExc_TypeError, + "color[attribute] = x: " + "argument not a number"); + return -1; + } + + if(i<0) i= COLOR_SIZE-i; + + if(i < 0 || i >= COLOR_SIZE){ + PyErr_SetString(PyExc_IndexError, "color[attribute] = x: " + "array assignment index out of range"); + return -1; + } + + self->col[i] = f; + + if(BaseMath_WriteIndexCallback(self, i) == -1) + return -1; + + return 0; +} +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Color_slice(ColorObject * self, int begin, int end) +{ + PyObject *tuple; + int count; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + CLAMP(begin, 0, COLOR_SIZE); + if (end<0) end= (COLOR_SIZE + 1) + end; + CLAMP(end, 0, COLOR_SIZE); + begin= MIN2(begin, end); + + tuple= PyTuple_New(end - begin); + for(count= begin; count < end; count++) { + PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->col[count])); + } + + return tuple; +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq) +{ + int i, size; + float col[COLOR_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + CLAMP(begin, 0, COLOR_SIZE); + if (end<0) end= (COLOR_SIZE + 1) + end; + CLAMP(end, 0, COLOR_SIZE); + begin = MIN2(begin, end); + + if((size=mathutils_array_parse(col, 0, COLOR_SIZE, seq, "mathutils.Color[begin:end] = []")) == -1) + return -1; + + if(size != (end - begin)){ + PyErr_SetString(PyExc_ValueError, + "color[begin:end] = []: " + "size mismatch in slice assignment"); + return -1; + } + + for(i= 0; i < COLOR_SIZE; i++) + self->col[begin + i] = col[i]; + + (void)BaseMath_WriteCallback(self); + return 0; +} + +static PyObject *Color_subscript(ColorObject *self, PyObject *item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += COLOR_SIZE; + return Color_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Color_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with color"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "color indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + +static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += COLOR_SIZE; + return Color_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, COLOR_SIZE, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Color_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with color"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "color indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + +//-----------------PROTCOL DECLARATIONS-------------------------- +static PySequenceMethods Color_SeqMethods = { + (lenfunc) Color_len, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) NULL, /* sq_repeat */ + (ssizeargfunc) Color_item, /* sq_item */ + NULL, /* sq_slice, deprecated */ + (ssizeobjargproc) Color_ass_item, /* sq_ass_item */ + NULL, /* sq_ass_slice, deprecated */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyMappingMethods Color_AsMapping = { + (lenfunc)Color_len, + (binaryfunc)Color_subscript, + (objobjargproc)Color_ass_subscript +}; + +/* numeric */ + + +/* addition: obj + obj */ +static PyObject *Color_add(PyObject *v1, PyObject *v2) +{ + ColorObject *color1 = NULL, *color2 = NULL; + float col[COLOR_SIZE]; + + if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { + PyErr_SetString(PyExc_TypeError, + "Color addition: " + "arguments not valid for this operation"); + return NULL; + } + color1 = (ColorObject*)v1; + color2 = (ColorObject*)v2; + + if(BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + return NULL; + + add_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE); + + return newColorObject(col, Py_NEW, Py_TYPE(v1)); +} + +/* addition in-place: obj += obj */ +static PyObject *Color_iadd(PyObject *v1, PyObject *v2) +{ + ColorObject *color1 = NULL, *color2 = NULL; + + if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { + PyErr_SetString(PyExc_TypeError, + "Color addition: " + "arguments not valid for this operation"); + return NULL; + } + color1 = (ColorObject*)v1; + color2 = (ColorObject*)v2; + + if(BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + return NULL; + + add_vn_vn(color1->col, color2->col, COLOR_SIZE); + + (void)BaseMath_WriteCallback(color1); + Py_INCREF(v1); + return v1; +} + +/* subtraction: obj - obj */ +static PyObject *Color_sub(PyObject *v1, PyObject *v2) +{ + ColorObject *color1 = NULL, *color2 = NULL; + float col[COLOR_SIZE]; + + if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { + PyErr_SetString(PyExc_TypeError, + "Color subtraction: " + "arguments not valid for this operation"); + return NULL; + } + color1 = (ColorObject*)v1; + color2 = (ColorObject*)v2; + + if(BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + return NULL; + + sub_vn_vnvn(col, color1->col, color2->col, COLOR_SIZE); + + return newColorObject(col, Py_NEW, Py_TYPE(v1)); +} + +/* subtraction in-place: obj -= obj */ +static PyObject *Color_isub(PyObject *v1, PyObject *v2) +{ + ColorObject *color1= NULL, *color2= NULL; + + if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { + PyErr_SetString(PyExc_TypeError, + "Color subtraction: " + "arguments not valid for this operation"); + return NULL; + } + color1 = (ColorObject*)v1; + color2 = (ColorObject*)v2; + + if(BaseMath_ReadCallback(color1) == -1 || BaseMath_ReadCallback(color2) == -1) + return NULL; + + sub_vn_vn(color1->col, color2->col, COLOR_SIZE); + + (void)BaseMath_WriteCallback(color1); + Py_INCREF(v1); + return v1; +} + +static PyObject *color_mul_float(ColorObject *color, const float scalar) +{ + float tcol[COLOR_SIZE]; + mul_vn_vn_fl(tcol, color->col, COLOR_SIZE, scalar); + return newColorObject(tcol, Py_NEW, Py_TYPE(color)); +} + + +static PyObject *Color_mul(PyObject *v1, PyObject *v2) +{ + ColorObject *color1 = NULL, *color2 = NULL; + float scalar; + + if ColorObject_Check(v1) { + color1= (ColorObject *)v1; + if(BaseMath_ReadCallback(color1) == -1) + return NULL; + } + if ColorObject_Check(v2) { + color2= (ColorObject *)v2; + if(BaseMath_ReadCallback(color2) == -1) + return NULL; + } + + + /* make sure v1 is always the vector */ + if (color1 && color2) { + /* col * col, dont support yet! */ + } + else if (color1) { + if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* COLOR * FLOAT */ + return color_mul_float(color1, scalar); + } + } + else if (color2) { + if (((scalar= PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred())==0) { /* FLOAT * COLOR */ + return color_mul_float(color2, scalar); + } + } + else { + BLI_assert(!"internal error"); + } + + PyErr_Format(PyExc_TypeError, + "Color multiplication: not supported between " + "'%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +} + +static PyObject *Color_div(PyObject *v1, PyObject *v2) +{ + ColorObject *color1 = NULL; + float scalar; + + if ColorObject_Check(v1) { + color1= (ColorObject *)v1; + if(BaseMath_ReadCallback(color1) == -1) + return NULL; + } + else { + PyErr_SetString(PyExc_TypeError, + "Color division not supported in this order"); + return NULL; + } + + /* make sure v1 is always the vector */ + if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* COLOR * FLOAT */ + if(scalar==0.0f) { + PyErr_SetString(PyExc_ZeroDivisionError, + "Color division: divide by zero error"); + return NULL; + } + return color_mul_float(color1, 1.0f / scalar); + } + + PyErr_Format(PyExc_TypeError, + "Color multiplication: not supported between " + "'%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +} + +/* mulplication in-place: obj *= obj */ +static PyObject *Color_imul(PyObject *v1, PyObject *v2) +{ + ColorObject *color = (ColorObject *)v1; + float scalar; + + if(BaseMath_ReadCallback(color) == -1) + return NULL; + + /* only support color *= float */ + if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* COLOR *= FLOAT */ + mul_vn_fl(color->col, COLOR_SIZE, scalar); + } + else { + PyErr_SetString(PyExc_TypeError, + "Color multiplication: " + "arguments not acceptable for this operation"); + return NULL; + } + + (void)BaseMath_WriteCallback(color); + Py_INCREF(v1); + return v1; +} + +/* mulplication in-place: obj *= obj */ +static PyObject *Color_idiv(PyObject *v1, PyObject *v2) +{ + ColorObject *color = (ColorObject *)v1; + float scalar; + + if(BaseMath_ReadCallback(color) == -1) + return NULL; + + /* only support color /= float */ + if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* COLOR /= FLOAT */ + if(scalar==0.0f) { + PyErr_SetString(PyExc_ZeroDivisionError, + "Color division: divide by zero error"); + return NULL; + } + + mul_vn_fl(color->col, COLOR_SIZE, 1.0f / scalar); + } + else { + PyErr_SetString(PyExc_TypeError, + "Color multiplication: " + "arguments not acceptable for this operation"); + return NULL; + } + + (void)BaseMath_WriteCallback(color); + Py_INCREF(v1); + return v1; +} + +/* -obj + returns the negative of this object*/ +static PyObject *Color_neg(ColorObject *self) +{ + float tcol[COLOR_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + negate_vn_vn(tcol, self->col, COLOR_SIZE); + return newColorObject(tcol, Py_NEW, Py_TYPE(self)); +} + + +static PyNumberMethods Color_NumMethods = { + (binaryfunc) Color_add, /*nb_add*/ + (binaryfunc) Color_sub, /*nb_subtract*/ + (binaryfunc) Color_mul, /*nb_multiply*/ + NULL, /*nb_remainder*/ + NULL, /*nb_divmod*/ + NULL, /*nb_power*/ + (unaryfunc) Color_neg, /*nb_negative*/ + (unaryfunc) NULL, /*tp_positive*/ + (unaryfunc) NULL, /*tp_absolute*/ + (inquiry) NULL, /*tp_bool*/ + (unaryfunc) NULL, /*nb_invert*/ + NULL, /*nb_lshift*/ + (binaryfunc)NULL, /*nb_rshift*/ + NULL, /*nb_and*/ + NULL, /*nb_xor*/ + NULL, /*nb_or*/ + NULL, /*nb_int*/ + NULL, /*nb_reserved*/ + NULL, /*nb_float*/ + Color_iadd, /* nb_inplace_add */ + Color_isub, /* nb_inplace_subtract */ + Color_imul, /* nb_inplace_multiply */ + NULL, /* nb_inplace_remainder */ + NULL, /* nb_inplace_power */ + NULL, /* nb_inplace_lshift */ + NULL, /* nb_inplace_rshift */ + NULL, /* nb_inplace_and */ + NULL, /* nb_inplace_xor */ + NULL, /* nb_inplace_or */ + NULL, /* nb_floor_divide */ + Color_div, /* nb_true_divide */ + NULL, /* nb_inplace_floor_divide */ + Color_idiv, /* nb_inplace_true_divide */ + NULL, /* nb_index */ +}; + +/* color channel, vector.r/g/b */ +static PyObject *Color_getChannel(ColorObject * self, void *type) +{ + return Color_item(self, GET_INT_FROM_POINTER(type)); +} + +static int Color_setChannel(ColorObject * self, PyObject *value, void * type) +{ + return Color_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +/* color channel (HSV), color.h/s/v */ +static PyObject *Color_getChannelHSV(ColorObject * self, void *type) +{ + float hsv[3]; + int i= GET_INT_FROM_POINTER(type); + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2])); + + return PyFloat_FromDouble(hsv[i]); +} + +static int Color_setChannelHSV(ColorObject * self, PyObject *value, void * type) +{ + float hsv[3]; + int i= GET_INT_FROM_POINTER(type); + float f = PyFloat_AsDouble(value); + + if(f == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "color.h/s/v = value: " + "argument not a number"); + return -1; + } + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2])); + CLAMP(f, 0.0f, 1.0f); + hsv[i] = f; + hsv_to_rgb(hsv[0], hsv[1], hsv[2], &(self->col[0]), &(self->col[1]), &(self->col[2])); + + if(BaseMath_WriteCallback(self) == -1) + return -1; + + return 0; +} + +/* color channel (HSV), color.h/s/v */ +static PyObject *Color_getHSV(ColorObject * self, void *UNUSED(closure)) +{ + float hsv[3]; + PyObject *ret; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + rgb_to_hsv(self->col[0], self->col[1], self->col[2], &(hsv[0]), &(hsv[1]), &(hsv[2])); + + ret= PyTuple_New(3); + PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(hsv[0])); + PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(hsv[1])); + PyTuple_SET_ITEM(ret, 2, PyFloat_FromDouble(hsv[2])); + return ret; +} + +static int Color_setHSV(ColorObject * self, PyObject *value, void *UNUSED(closure)) +{ + float hsv[3]; + + if(mathutils_array_parse(hsv, 3, 3, value, "mathutils.Color.hsv = value") == -1) + return -1; + + CLAMP(hsv[0], 0.0f, 1.0f); + CLAMP(hsv[1], 0.0f, 1.0f); + CLAMP(hsv[2], 0.0f, 1.0f); + + hsv_to_rgb(hsv[0], hsv[1], hsv[2], &(self->col[0]), &(self->col[1]), &(self->col[2])); + + if(BaseMath_WriteCallback(self) == -1) + return -1; + + return 0; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Color_getseters[] = { + {(char *)"r", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Red color channel.\n\n:type: float", (void *)0}, + {(char *)"g", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Green color channel.\n\n:type: float", (void *)1}, + {(char *)"b", (getter)Color_getChannel, (setter)Color_setChannel, (char *)"Blue color channel.\n\n:type: float", (void *)2}, + + {(char *)"h", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Hue component in [0, 1].\n\n:type: float", (void *)0}, + {(char *)"s", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Saturation component in [0, 1].\n\n:type: float", (void *)1}, + {(char *)"v", (getter)Color_getChannelHSV, (setter)Color_setChannelHSV, (char *)"HSV Value component in [0, 1].\n\n:type: float", (void *)2}, + + {(char *)"hsv", (getter)Color_getHSV, (setter)Color_setHSV, (char *)"HSV Values in [0, 1].\n\n:type: float triplet", (void *)0}, + + {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, BaseMathObject_Wrapped_doc, NULL}, + {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, BaseMathObject_Owner_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Color_methods[] = { + {"__copy__", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc}, + {"copy", (PyCFunction) Color_copy, METH_NOARGS, Color_copy_doc}, + {NULL, NULL, 0, NULL} +}; + +//------------------PY_OBECT DEFINITION-------------------------- +PyDoc_STRVAR(color_doc, +"This object gives access to Colors in Blender." +); +PyTypeObject color_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "mathutils.Color", //tp_name + sizeof(ColorObject), //tp_basicsize + 0, //tp_itemsize + (destructor)BaseMathObject_dealloc, //tp_dealloc + NULL, //tp_print + NULL, //tp_getattr + NULL, //tp_setattr + NULL, //tp_compare + (reprfunc) Color_repr, //tp_repr + &Color_NumMethods, //tp_as_number + &Color_SeqMethods, //tp_as_sequence + &Color_AsMapping, //tp_as_mapping + NULL, //tp_hash + NULL, //tp_call + NULL, //tp_str + NULL, //tp_getattro + NULL, //tp_setattro + NULL, //tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags + color_doc, //tp_doc + (traverseproc)BaseMathObject_traverse, //tp_traverse + (inquiry)BaseMathObject_clear, //tp_clear + (richcmpfunc)Color_richcmpr, //tp_richcompare + 0, //tp_weaklistoffset + NULL, //tp_iter + NULL, //tp_iternext + Color_methods, //tp_methods + NULL, //tp_members + Color_getseters, //tp_getset + NULL, //tp_base + NULL, //tp_dict + NULL, //tp_descr_get + NULL, //tp_descr_set + 0, //tp_dictoffset + NULL, //tp_init + NULL, //tp_alloc + Color_new, //tp_new + NULL, //tp_free + NULL, //tp_is_gc + NULL, //tp_bases + NULL, //tp_mro + NULL, //tp_cache + NULL, //tp_subclasses + NULL, //tp_weaklist + NULL //tp_del +}; +//------------------------newColorObject (internal)------------- +//creates a new color object +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newColorObject(float *col, int type, PyTypeObject *base_type) +{ + ColorObject *self; + + self= base_type ? (ColorObject *)base_type->tp_alloc(base_type, 0) : + (ColorObject *)PyObject_GC_New(ColorObject, &color_Type); + + if(self) { + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP){ + self->col = col; + self->wrapped = Py_WRAP; + } + else if (type == Py_NEW){ + self->col = PyMem_Malloc(COLOR_SIZE * sizeof(float)); + if(col) + copy_v3_v3(self->col, col); + else + zero_v3(self->col); + + self->wrapped = Py_NEW; + } + else { + Py_FatalError("Color(): invalid type!"); + } + } + + return (PyObject *)self; +} + +PyObject *newColorObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) +{ + ColorObject *self= (ColorObject *)newColorObject(NULL, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + PyObject_GC_Track(self); + } + + return (PyObject *)self; +} diff --git a/source/blender/python/mathutils/mathutils_Color.h b/source/blender/python/mathutils/mathutils_Color.h new file mode 100644 index 00000000000..0fc880363f4 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Color.h @@ -0,0 +1,55 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/python/generic/mathutils_Color.h + * \ingroup pygen + */ + + +#ifndef MATHUTILS_COLOR_H +#define MATHUTILS_COLOR_H + +extern PyTypeObject color_Type; +#define ColorObject_Check(_v) PyObject_TypeCheck((_v), &color_Type) + +typedef struct { + BASE_MATH_MEMBERS(col) +} ColorObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +be stored in py_data) or be a wrapper for data allocated through +blender (stored in blend_data). This is an either/or struct not both*/ + +//prototypes +PyObject *newColorObject( float *col, int type, PyTypeObject *base_type); +PyObject *newColorObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); + +#endif /* MATHUTILS_COLOR_H */ diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c new file mode 100644 index 00000000000..5c609d8961f --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Euler.c @@ -0,0 +1,721 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils_Euler.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#define EULER_SIZE 3 + +//----------------------------------mathutils.Euler() ------------------- +//makes a new euler for you to play with +static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *seq= NULL; + const char *order_str= NULL; + + float eul[EULER_SIZE]= {0.0f, 0.0f, 0.0f}; + short order= EULER_ORDER_XYZ; + + if(kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, + "mathutils.Euler(): " + "takes no keyword args"); + return NULL; + } + + if(!PyArg_ParseTuple(args, "|Os:mathutils.Euler", &seq, &order_str)) + return NULL; + + switch(PyTuple_GET_SIZE(args)) { + case 0: + break; + case 2: + if((order=euler_order_from_string(order_str, "mathutils.Euler()")) == -1) + return NULL; + /* intentionally pass through */ + case 1: + if (mathutils_array_parse(eul, EULER_SIZE, EULER_SIZE, seq, "mathutils.Euler()") == -1) + return NULL; + break; + } + return newEulerObject(eul, order, Py_NEW, type); +} + +/* internal use, assuem read callback is done */ +static const char *euler_order_str(EulerObject *self) +{ + static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"}; + return order[self->order-EULER_ORDER_XYZ]; +} + +short euler_order_from_string(const char *str, const char *error_prefix) +{ + if((str[0] && str[1] && str[2] && str[3]=='\0')) { + switch(*((PY_INT32_T *)str)) { + case 'X'|'Y'<<8|'Z'<<16: return EULER_ORDER_XYZ; + case 'X'|'Z'<<8|'Y'<<16: return EULER_ORDER_XZY; + case 'Y'|'X'<<8|'Z'<<16: return EULER_ORDER_YXZ; + case 'Y'|'Z'<<8|'X'<<16: return EULER_ORDER_YZX; + case 'Z'|'X'<<8|'Y'<<16: return EULER_ORDER_ZXY; + case 'Z'|'Y'<<8|'X'<<16: return EULER_ORDER_ZYX; + } + } + + PyErr_Format(PyExc_ValueError, + "%s: invalid euler order '%s'", + error_prefix, str); + return -1; +} + +/* note: BaseMath_ReadCallback must be called beforehand */ +static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits) +{ + PyObject *ret; + int i; + + ret= PyTuple_New(EULER_SIZE); + + if(ndigits >= 0) { + for(i= 0; i < EULER_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->eul[i], ndigits))); + } + } + else { + for(i= 0; i < EULER_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->eul[i])); + } + } + + return ret; +} + +//-----------------------------METHODS---------------------------- +//return a quaternion representation of the euler + +PyDoc_STRVAR(Euler_to_quaternion_doc, +".. method:: to_quaternion()\n" +"\n" +" Return a quaternion representation of the euler.\n" +"\n" +" :return: Quaternion representation of the euler.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Euler_to_quaternion(EulerObject * self) +{ + float quat[4]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + eulO_to_quat(quat, self->eul, self->order); + + return newQuaternionObject(quat, Py_NEW, NULL); +} + +//return a matrix representation of the euler +PyDoc_STRVAR(Euler_to_matrix_doc, +".. method:: to_matrix()\n" +"\n" +" Return a matrix representation of the euler.\n" +"\n" +" :return: A 3x3 roation matrix representation of the euler.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Euler_to_matrix(EulerObject * self) +{ + float mat[9]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + eulO_to_mat3((float (*)[3])mat, self->eul, self->order); + + return newMatrixObject(mat, 3, 3 , Py_NEW, NULL); +} + +PyDoc_STRVAR(Euler_zero_doc, +".. method:: zero()\n" +"\n" +" Set all values to zero.\n" +); +static PyObject *Euler_zero(EulerObject * self) +{ + zero_v3(self->eul); + + if(BaseMath_WriteCallback(self) == -1) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Euler_rotate_axis_doc, +".. method:: rotate_axis(axis, angle)\n" +"\n" +" Rotates the euler a certain amount and returning a unique euler rotation\n" +" (no 720 degree pitches).\n" +"\n" +" :arg axis: single character in ['X, 'Y', 'Z'].\n" +" :type axis: string\n" +" :arg angle: angle in radians.\n" +" :type angle: float\n" +); +static PyObject *Euler_rotate_axis(EulerObject * self, PyObject *args) +{ + float angle = 0.0f; + const char *axis; + + if(!PyArg_ParseTuple(args, "sf:rotate", &axis, &angle)){ + PyErr_SetString(PyExc_TypeError, + "euler.rotate(): " + "expected angle (float) and axis (x, y, z)"); + return NULL; + } + if(!(ELEM3(*axis, 'X', 'Y', 'Z') && axis[1]=='\0')){ + PyErr_SetString(PyExc_ValueError, "euler.rotate(): " + "expected axis to be 'X', 'Y' or 'Z'"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + + rotate_eulO(self->eul, self->order, *axis, angle); + + (void)BaseMath_WriteCallback(self); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Euler_rotate_doc, +".. method:: rotate(other)\n" +"\n" +" Rotates the euler a by another mathutils value.\n" +"\n" +" :arg other: rotation component of mathutils value\n" +" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" +); +static PyObject *Euler_rotate(EulerObject * self, PyObject *value) +{ + float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) + return NULL; + + eulO_to_mat3(self_rmat, self->eul, self->order); + mul_m3_m3m3(rmat, self_rmat, other_rmat); + + mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Euler_make_compatible_doc, +".. method:: make_compatible(other)\n" +"\n" +" Make this euler compatible with another,\n" +" so interpolating between them works as intended.\n" +"\n" +" .. note:: the rotation order is not taken into account for this function.\n" +); +static PyObject *Euler_make_compatible(EulerObject * self, PyObject *value) +{ + float teul[EULER_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value, "euler.make_compatible(other), invalid 'other' arg") == -1) + return NULL; + + compatible_eul(self->eul, teul); + + (void)BaseMath_WriteCallback(self); + + Py_RETURN_NONE; +} + +//----------------------------Euler.rotate()----------------------- +// return a copy of the euler + +PyDoc_STRVAR(Euler_copy_doc, +".. function:: copy()\n" +"\n" +" Returns a copy of this euler.\n" +"\n" +" :return: A copy of the euler.\n" +" :rtype: :class:`Euler`\n" +"\n" +" .. note:: use this to get a copy of a wrapped euler with\n" +" no reference to the original data.\n" +); +static PyObject *Euler_copy(EulerObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return newEulerObject(self->eul, self->order, Py_NEW, Py_TYPE(self)); +} + +//----------------------------print object (internal)-------------- +//print the object to screen + +static PyObject *Euler_repr(EulerObject * self) +{ + PyObject *ret, *tuple; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + tuple= Euler_ToTupleExt(self, -1); + + ret= PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self)); + + Py_DECREF(tuple); + return ret; +} + +static PyObject* Euler_richcmpr(PyObject *a, PyObject *b, int op) +{ + PyObject *res; + int ok= -1; /* zero is true */ + + if (EulerObject_Check(a) && EulerObject_Check(b)) { + EulerObject *eulA= (EulerObject*)a; + EulerObject *eulB= (EulerObject*)b; + + if(BaseMath_ReadCallback(eulA) == -1 || BaseMath_ReadCallback(eulB) == -1) + return NULL; + + ok= ((eulA->order == eulB->order) && EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ? 0 : -1; + } + + switch (op) { + case Py_NE: + ok = !ok; /* pass through */ + case Py_EQ: + res = ok ? Py_False : Py_True; + break; + + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + res = Py_NotImplemented; + break; + default: + PyErr_BadArgument(); + return NULL; + } + + return Py_INCREF(res), res; +} + +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Euler_len(EulerObject *UNUSED(self)) +{ + return EULER_SIZE; +} +//----------------------------object[]--------------------------- +//sequence accessor (get) +static PyObject *Euler_item(EulerObject * self, int i) +{ + if(i<0) i= EULER_SIZE-i; + + if(i < 0 || i >= EULER_SIZE) { + PyErr_SetString(PyExc_IndexError, + "euler[attribute]: " + "array index out of range"); + return NULL; + } + + if(BaseMath_ReadIndexCallback(self, i) == -1) + return NULL; + + return PyFloat_FromDouble(self->eul[i]); + +} +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Euler_ass_item(EulerObject * self, int i, PyObject *value) +{ + float f = PyFloat_AsDouble(value); + + if(f == -1 && PyErr_Occurred()) { // parsed item not a number + PyErr_SetString(PyExc_TypeError, + "euler[attribute] = x: " + "argument not a number"); + return -1; + } + + if(i<0) i= EULER_SIZE-i; + + if(i < 0 || i >= EULER_SIZE){ + PyErr_SetString(PyExc_IndexError, + "euler[attribute] = x: " + "array assignment index out of range"); + return -1; + } + + self->eul[i] = f; + + if(BaseMath_WriteIndexCallback(self, i) == -1) + return -1; + + return 0; +} +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Euler_slice(EulerObject * self, int begin, int end) +{ + PyObject *tuple; + int count; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + CLAMP(begin, 0, EULER_SIZE); + if (end<0) end= (EULER_SIZE + 1) + end; + CLAMP(end, 0, EULER_SIZE); + begin= MIN2(begin, end); + + tuple= PyTuple_New(end - begin); + for(count = begin; count < end; count++) { + PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->eul[count])); + } + + return tuple; +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) +{ + int i, size; + float eul[EULER_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + CLAMP(begin, 0, EULER_SIZE); + if (end<0) end= (EULER_SIZE + 1) + end; + CLAMP(end, 0, EULER_SIZE); + begin = MIN2(begin, end); + + if((size=mathutils_array_parse(eul, 0, EULER_SIZE, seq, "mathutils.Euler[begin:end] = []")) == -1) + return -1; + + if(size != (end - begin)){ + PyErr_SetString(PyExc_ValueError, + "euler[begin:end] = []: " + "size mismatch in slice assignment"); + return -1; + } + + for(i= 0; i < EULER_SIZE; i++) + self->eul[begin + i] = eul[i]; + + (void)BaseMath_WriteCallback(self); + return 0; +} + +static PyObject *Euler_subscript(EulerObject *self, PyObject *item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += EULER_SIZE; + return Euler_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Euler_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with eulers"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "euler indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + + +static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += EULER_SIZE; + return Euler_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, EULER_SIZE, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Euler_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with euler"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "euler indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + +//-----------------PROTCOL DECLARATIONS-------------------------- +static PySequenceMethods Euler_SeqMethods = { + (lenfunc) Euler_len, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) NULL, /* sq_repeat */ + (ssizeargfunc) Euler_item, /* sq_item */ + (ssizessizeargfunc) NULL, /* sq_slice, deprecated */ + (ssizeobjargproc) Euler_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyMappingMethods Euler_AsMapping = { + (lenfunc)Euler_len, + (binaryfunc)Euler_subscript, + (objobjargproc)Euler_ass_subscript +}; + +/* + * euler axis, euler.x/y/z + */ +static PyObject *Euler_getAxis(EulerObject *self, void *type) +{ + return Euler_item(self, GET_INT_FROM_POINTER(type)); +} + +static int Euler_setAxis(EulerObject *self, PyObject *value, void *type) +{ + return Euler_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +/* rotation order */ +static PyObject *Euler_getOrder(EulerObject *self, void *UNUSED(closure)) +{ + if(BaseMath_ReadCallback(self) == -1) /* can read order too */ + return NULL; + + return PyUnicode_FromString(euler_order_str(self)); +} + +static int Euler_setOrder(EulerObject *self, PyObject *value, void *UNUSED(closure)) +{ + const char *order_str= _PyUnicode_AsString(value); + short order= euler_order_from_string(order_str, "euler.order"); + + if(order == -1) + return -1; + + self->order= order; + (void)BaseMath_WriteCallback(self); /* order can be written back */ + return 0; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Euler_getseters[] = { + {(char *)"x", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler X axis in radians.\n\n:type: float", (void *)0}, + {(char *)"y", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler Y axis in radians.\n\n:type: float", (void *)1}, + {(char *)"z", (getter)Euler_getAxis, (setter)Euler_setAxis, (char *)"Euler Z axis in radians.\n\n:type: float", (void *)2}, + {(char *)"order", (getter)Euler_getOrder, (setter)Euler_setOrder, (char *)"Euler rotation order.\n\n:type: string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']", (void *)NULL}, + + {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL}, + {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Euler_methods[] = { + {"zero", (PyCFunction) Euler_zero, METH_NOARGS, Euler_zero_doc}, + {"to_matrix", (PyCFunction) Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc}, + {"to_quaternion", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc}, + {"rotate_axis", (PyCFunction) Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc}, + {"rotate", (PyCFunction) Euler_rotate, METH_O, Euler_rotate_doc}, + {"make_compatible", (PyCFunction) Euler_make_compatible, METH_O, Euler_make_compatible_doc}, + {"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc}, + {"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc}, + {NULL, NULL, 0, NULL} +}; + +//------------------PY_OBECT DEFINITION-------------------------- +PyDoc_STRVAR(euler_doc, +"This object gives access to Eulers in Blender." +); +PyTypeObject euler_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "mathutils.Euler", //tp_name + sizeof(EulerObject), //tp_basicsize + 0, //tp_itemsize + (destructor)BaseMathObject_dealloc, //tp_dealloc + NULL, //tp_print + NULL, //tp_getattr + NULL, //tp_setattr + NULL, //tp_compare + (reprfunc) Euler_repr, //tp_repr + NULL, //tp_as_number + &Euler_SeqMethods, //tp_as_sequence + &Euler_AsMapping, //tp_as_mapping + NULL, //tp_hash + NULL, //tp_call + NULL, //tp_str + NULL, //tp_getattro + NULL, //tp_setattro + NULL, //tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags + euler_doc, //tp_doc + (traverseproc)BaseMathObject_traverse, //tp_traverse + (inquiry)BaseMathObject_clear, //tp_clear + (richcmpfunc)Euler_richcmpr, //tp_richcompare + 0, //tp_weaklistoffset + NULL, //tp_iter + NULL, //tp_iternext + Euler_methods, //tp_methods + NULL, //tp_members + Euler_getseters, //tp_getset + NULL, //tp_base + NULL, //tp_dict + NULL, //tp_descr_get + NULL, //tp_descr_set + 0, //tp_dictoffset + NULL, //tp_init + NULL, //tp_alloc + Euler_new, //tp_new + NULL, //tp_free + NULL, //tp_is_gc + NULL, //tp_bases + NULL, //tp_mro + NULL, //tp_cache + NULL, //tp_subclasses + NULL, //tp_weaklist + NULL //tp_del +}; +//------------------------newEulerObject (internal)------------- +//creates a new euler object +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newEulerObject(float *eul, short order, int type, PyTypeObject *base_type) +{ + EulerObject *self; + + self= base_type ? (EulerObject *)base_type->tp_alloc(base_type, 0) : + (EulerObject *)PyObject_GC_New(EulerObject, &euler_Type); + + if(self) { + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP) { + self->eul = eul; + self->wrapped = Py_WRAP; + } + else if (type == Py_NEW) { + self->eul = PyMem_Malloc(EULER_SIZE * sizeof(float)); + if(eul) { + copy_v3_v3(self->eul, eul); + } + else { + zero_v3(self->eul); + } + + self->wrapped = Py_NEW; + } + else { + Py_FatalError("Euler(): invalid type!"); + } + + self->order= order; + } + + return (PyObject *)self; +} + +PyObject *newEulerObject_cb(PyObject *cb_user, short order, int cb_type, int cb_subtype) +{ + EulerObject *self= (EulerObject *)newEulerObject(NULL, order, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + PyObject_GC_Track(self); + } + + return (PyObject *)self; +} diff --git a/source/blender/python/mathutils/mathutils_Euler.h b/source/blender/python/mathutils/mathutils_Euler.h new file mode 100644 index 00000000000..849e16c2bb7 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Euler.h @@ -0,0 +1,60 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/python/generic/mathutils_Euler.h + * \ingroup pygen + */ + + +#ifndef MATHUTILS_EULER_H +#define MATHUTILS_EULER_H + +extern PyTypeObject euler_Type; +#define EulerObject_Check(_v) PyObject_TypeCheck((_v), &euler_Type) + +typedef struct { + BASE_MATH_MEMBERS(eul) + unsigned char order; /* rotation order */ + +} EulerObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +be stored in py_data) or be a wrapper for data allocated through +blender (stored in blend_data). This is an either/or struct not both*/ + +//prototypes +PyObject *newEulerObject( float *eul, short order, int type, PyTypeObject *base_type); +PyObject *newEulerObject_cb(PyObject *cb_user, short order, int cb_type, int cb_subtype); + +short euler_order_from_string(const char *str, const char *error_prefix); + + +#endif /* MATHUTILS_EULER_H */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c new file mode 100644 index 00000000000..b0187c1ef25 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -0,0 +1,2041 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * Contributor(s): Michel Selten & Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils_Matrix.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +static PyObject *Matrix_copy(MatrixObject *self); +static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value); +static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self); + +/* matrix vector callbacks */ +int mathutils_matrix_vector_cb_index= -1; + +static int mathutils_matrix_vector_check(BaseMathObject *bmo) +{ + MatrixObject *self= (MatrixObject *)bmo->cb_user; + return BaseMath_ReadCallback(self); +} + +static int mathutils_matrix_vector_get(BaseMathObject *bmo, int subtype) +{ + MatrixObject *self= (MatrixObject *)bmo->cb_user; + int i; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + for(i=0; i < self->col_size; i++) + bmo->data[i]= self->matrix[subtype][i]; + + return 0; +} + +static int mathutils_matrix_vector_set(BaseMathObject *bmo, int subtype) +{ + MatrixObject *self= (MatrixObject *)bmo->cb_user; + int i; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + for(i=0; i < self->col_size; i++) + self->matrix[subtype][i]= bmo->data[i]; + + (void)BaseMath_WriteCallback(self); + return 0; +} + +static int mathutils_matrix_vector_get_index(BaseMathObject *bmo, int subtype, int index) +{ + MatrixObject *self= (MatrixObject *)bmo->cb_user; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + bmo->data[index]= self->matrix[subtype][index]; + return 0; +} + +static int mathutils_matrix_vector_set_index(BaseMathObject *bmo, int subtype, int index) +{ + MatrixObject *self= (MatrixObject *)bmo->cb_user; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + self->matrix[subtype][index]= bmo->data[index]; + + (void)BaseMath_WriteCallback(self); + return 0; +} + +Mathutils_Callback mathutils_matrix_vector_cb = { + mathutils_matrix_vector_check, + mathutils_matrix_vector_get, + mathutils_matrix_vector_set, + mathutils_matrix_vector_get_index, + mathutils_matrix_vector_set_index +}; +/* matrix vector callbacks, this is so you can do matrix[i][j] = val */ + +//----------------------------------mathutils.Matrix() ----------------- +//mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. +//create a new matrix type +static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if(kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, + "mathutils.Matrix(): " + "takes no keyword args"); + return NULL; + } + + switch(PyTuple_GET_SIZE(args)) { + case 0: + return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW, type); + case 1: + { + PyObject *arg= PyTuple_GET_ITEM(args, 0); + + /* -1 is an error, size checks will accunt for this */ + const unsigned short row_size= PySequence_Size(arg); + + if(row_size >= 2 && row_size <= 4) { + PyObject *item= PySequence_GetItem(arg, 0); + const unsigned short col_size= PySequence_Size(item); + Py_XDECREF(item); + + if(col_size >= 2 && col_size <= 4) { + /* sane row & col size, new matrix and assign as slice */ + PyObject *matrix= newMatrixObject(NULL, row_size, col_size, Py_NEW, type); + if(Matrix_ass_slice((MatrixObject *)matrix, 0, INT_MAX, arg) == 0) { + return matrix; + } + else { /* matrix ok, slice assignment not */ + Py_DECREF(matrix); + } + } + } + } + } + + /* will overwrite error */ + PyErr_SetString(PyExc_TypeError, + "mathutils.Matrix(): " + "expects no args or 2-4 numeric sequences"); + return NULL; +} + +static PyObject *matrix__apply_to_copy(PyNoArgsFunction matrix_func, MatrixObject *self) +{ + PyObject *ret= Matrix_copy(self); + PyObject *ret_dummy= matrix_func(ret); + if(ret_dummy) { + Py_DECREF(ret_dummy); + return (PyObject *)ret; + } + else { /* error */ + Py_DECREF(ret); + return NULL; + } +} + +/* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */ +static void matrix_3x3_as_4x4(float mat[16]) +{ + mat[10] = mat[8]; + mat[9] = mat[7]; + mat[8] = mat[6]; + mat[7] = 0.0f; + mat[6] = mat[5]; + mat[5] = mat[4]; + mat[4] = mat[3]; + mat[3] = 0.0f; +} + +/*-----------------------CLASS-METHODS----------------------------*/ + +//mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. +PyDoc_STRVAR(C_Matrix_Rotation_doc, +".. classmethod:: Rotation(angle, size, axis)\n" +"\n" +" Create a matrix representing a rotation.\n" +"\n" +" :arg angle: The angle of rotation desired, in radians.\n" +" :type angle: float\n" +" :arg size: The size of the rotation matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object\n" +" (optional when size is 2).\n" +" :type axis: string or :class:`Vector`\n" +" :return: A new rotation matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) +{ + PyObject *vec= NULL; + const char *axis= NULL; + int matSize; + double angle; /* use double because of precision problems at high values */ + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "di|O", &angle, &matSize, &vec)) { + PyErr_SetString(PyExc_TypeError, + "mathutils.RotationMatrix(angle, size, axis): " + "expected float int and a string or vector"); + return NULL; + } + + if(vec && PyUnicode_Check(vec)) { + axis= _PyUnicode_AsString((PyObject *)vec); + if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') { + PyErr_SetString(PyExc_ValueError, + "mathutils.RotationMatrix(): " + "3rd argument axis value must be a 3D vector " + "or a string in 'X', 'Y', 'Z'"); + return NULL; + } + else { + /* use the string */ + vec= NULL; + } + } + + angle= angle_wrap_rad(angle); + + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_ValueError, + "mathutils.RotationMatrix(): " + "can only return a 2x2 3x3 or 4x4 matrix"); + return NULL; + } + if(matSize == 2 && (vec != NULL)) { + PyErr_SetString(PyExc_ValueError, + "mathutils.RotationMatrix(): " + "cannot create a 2x2 rotation matrix around arbitrary axis"); + return NULL; + } + if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) { + PyErr_SetString(PyExc_ValueError, + "mathutils.RotationMatrix(): " + "axis of rotation for 3d and 4d matrices is required"); + return NULL; + } + + /* check for valid vector/axis above */ + if(vec) { + float tvec[3]; + + if (mathutils_array_parse(tvec, 3, 3, vec, "mathutils.RotationMatrix(angle, size, axis), invalid 'axis' arg") == -1) + return NULL; + + axis_angle_to_mat3((float (*)[3])mat, tvec, angle); + } + else if(matSize == 2) { + //2D rotation matrix + mat[0] = (float) cos (angle); + mat[1] = (float) sin (angle); + mat[2] = -((float) sin(angle)); + mat[3] = (float) cos(angle); + } + else if(strcmp(axis, "X") == 0) { + //rotation around X + mat[0] = 1.0f; + mat[4] = (float) cos(angle); + mat[5] = (float) sin(angle); + mat[7] = -((float) sin(angle)); + mat[8] = (float) cos(angle); + } + else if(strcmp(axis, "Y") == 0) { + //rotation around Y + mat[0] = (float) cos(angle); + mat[2] = -((float) sin(angle)); + mat[4] = 1.0f; + mat[6] = (float) sin(angle); + mat[8] = (float) cos(angle); + } + else if(strcmp(axis, "Z") == 0) { + //rotation around Z + mat[0] = (float) cos(angle); + mat[1] = (float) sin(angle); + mat[3] = -((float) sin(angle)); + mat[4] = (float) cos(angle); + mat[8] = 1.0f; + } + else { + /* should never get here */ + PyErr_SetString(PyExc_ValueError, + "mathutils.RotationMatrix(): unknown error"); + return NULL; + } + + if(matSize == 4) { + matrix_3x3_as_4x4(mat); + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); +} + + +PyDoc_STRVAR(C_Matrix_Translation_doc, +".. classmethod:: Translation(vector)\n" +"\n" +" Create a matrix representing a translation.\n" +"\n" +" :arg vector: The translation vector.\n" +" :type vector: :class:`Vector`\n" +" :return: An identity matrix with a translation.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value) +{ + float mat[16], tvec[3]; + + if (mathutils_array_parse(tvec, 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1) + return NULL; + + /* create a identity matrix and add translation */ + unit_m4((float(*)[4]) mat); + copy_v3_v3(mat + 12, tvec); /* 12, 13, 14 */ + return newMatrixObject(mat, 4, 4, Py_NEW, (PyTypeObject *)cls); +} +//----------------------------------mathutils.Matrix.Scale() ------------- +//mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. +PyDoc_STRVAR(C_Matrix_Scale_doc, +".. classmethod:: Scale(factor, size, axis)\n" +"\n" +" Create a matrix representing a scaling.\n" +"\n" +" :arg factor: The factor of scaling to apply.\n" +" :type factor: float\n" +" :arg size: The size of the scale matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg axis: Direction to influence scale. (optional).\n" +" :type axis: :class:`Vector`\n" +" :return: A new scale matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args) +{ + PyObject *vec= NULL; + int vec_size; + float tvec[3]; + float factor; + int matSize; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "fi|O:Matrix.Scale", &factor, &matSize, &vec)) { + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_ValueError, + "Matrix.Scale(): " + "can only return a 2x2 3x3 or 4x4 matrix"); + return NULL; + } + if(vec) { + vec_size= (matSize == 2 ? 2 : 3); + if(mathutils_array_parse(tvec, vec_size, vec_size, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) { + return NULL; + } + } + if(vec == NULL) { //scaling along axis + if(matSize == 2) { + mat[0] = factor; + mat[3] = factor; + } + else { + mat[0] = factor; + mat[4] = factor; + mat[8] = factor; + } + } + else { //scaling in arbitrary direction + //normalize arbitrary axis + float norm = 0.0f; + int x; + for(x = 0; x < vec_size; x++) { + norm += tvec[x] * tvec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec_size; x++) { + tvec[x] /= norm; + } + if(matSize == 2) { + mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0])); + mat[1] = ((factor - 1) *(tvec[0] * tvec[1])); + mat[2] = ((factor - 1) *(tvec[0] * tvec[1])); + mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1])); + } + else { + mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0])); + mat[1] = ((factor - 1) *(tvec[0] * tvec[1])); + mat[2] = ((factor - 1) *(tvec[0] * tvec[2])); + mat[3] = ((factor - 1) *(tvec[0] * tvec[1])); + mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1])); + mat[5] = ((factor - 1) *(tvec[1] * tvec[2])); + mat[6] = ((factor - 1) *(tvec[0] * tvec[2])); + mat[7] = ((factor - 1) *(tvec[1] * tvec[2])); + mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2])); + } + } + if(matSize == 4) { + matrix_3x3_as_4x4(mat); + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); +} +//----------------------------------mathutils.Matrix.OrthoProjection() --- +//mat is a 1D array of floats - row[0][0], row[0][1], row[1][0], etc. +PyDoc_STRVAR(C_Matrix_OrthoProjection_doc, +".. classmethod:: OrthoProjection(axis, size)\n" +"\n" +" Create a matrix to represent an orthographic projection.\n" +"\n" +" :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n" +" where a single axis is for a 2D matrix.\n" +" Or a vector for an arbitrary axis\n" +" :type axis: string or :class:`Vector`\n" +" :arg size: The size of the projection matrix to construct [2, 4].\n" +" :type size: int\n" +" :return: A new projection matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args) +{ + PyObject *axis; + + int matSize, x; + float norm = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) { + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_ValueError, + "mathutils.Matrix.OrthoProjection(): " + "can only return a 2x2 3x3 or 4x4 matrix"); + return NULL; + } + + if(PyUnicode_Check(axis)) { //ortho projection onto cardinal plane + Py_ssize_t plane_len; + const char *plane= _PyUnicode_AsStringAndSize(axis, &plane_len); + if(matSize == 2) { + if(plane_len == 1 && plane[0]=='X') { + mat[0]= 1.0f; + } + else if (plane_len == 1 && plane[0]=='Y') { + mat[3]= 1.0f; + } + else { + PyErr_Format(PyExc_ValueError, + "mathutils.Matrix.OrthoProjection(): " + "unknown plane, expected: X, Y, not '%.200s'", + plane); + return NULL; + } + } + else { + if(plane_len == 2 && plane[0]=='X' && plane[1]=='Y') { + mat[0]= 1.0f; + mat[4]= 1.0f; + } + else if (plane_len == 2 && plane[0]=='X' && plane[1]=='Z') { + mat[0]= 1.0f; + mat[8]= 1.0f; + } + else if (plane_len == 2 && plane[0]=='Y' && plane[1]=='Z') { + mat[4]= 1.0f; + mat[8]= 1.0f; + } + else { + PyErr_Format(PyExc_ValueError, + "mathutils.Matrix.OrthoProjection(): " + "unknown plane, expected: XY, XZ, YZ, not '%.200s'", + plane); + return NULL; + } + } + } + else { + //arbitrary plane + + int vec_size= (matSize == 2 ? 2 : 3); + float tvec[4]; + + if(mathutils_array_parse(tvec, vec_size, vec_size, axis, "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1) { + return NULL; + } + + //normalize arbitrary axis + for(x = 0; x < vec_size; x++) { + norm += tvec[x] * tvec[x]; + } + norm = (float) sqrt(norm); + for(x = 0; x < vec_size; x++) { + tvec[x] /= norm; + } + if(matSize == 2) { + mat[0] = 1 - (tvec[0] * tvec[0]); + mat[1] = -(tvec[0] * tvec[1]); + mat[2] = -(tvec[0] * tvec[1]); + mat[3] = 1 - (tvec[1] * tvec[1]); + } + else if(matSize > 2) { + mat[0] = 1 - (tvec[0] * tvec[0]); + mat[1] = -(tvec[0] * tvec[1]); + mat[2] = -(tvec[0] * tvec[2]); + mat[3] = -(tvec[0] * tvec[1]); + mat[4] = 1 - (tvec[1] * tvec[1]); + mat[5] = -(tvec[1] * tvec[2]); + mat[6] = -(tvec[0] * tvec[2]); + mat[7] = -(tvec[1] * tvec[2]); + mat[8] = 1 - (tvec[2] * tvec[2]); + } + } + if(matSize == 4) { + matrix_3x3_as_4x4(mat); + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); +} + +PyDoc_STRVAR(C_Matrix_Shear_doc, +".. classmethod:: Shear(plane, size, factor)\n" +"\n" +" Create a matrix to represent an shear transformation.\n" +"\n" +" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'],\n" +" where a single axis is for a 2D matrix only.\n" +" :type plane: string\n" +" :arg size: The size of the shear matrix to construct [2, 4].\n" +" :type size: int\n" +" :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix\n" +" pass a pair of floats corrasponding with the *plane* axis.\n" +" :type factor: float or float pair\n" +" :return: A new shear matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) +{ + int matSize; + const char *plane; + PyObject *fac; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) { + return NULL; + } + if(matSize != 2 && matSize != 3 && matSize != 4) { + PyErr_SetString(PyExc_ValueError, + "mathutils.Matrix.Shear(): " + "can only return a 2x2 3x3 or 4x4 matrix"); + return NULL; + } + + if(matSize == 2) { + float const factor= PyFloat_AsDouble(fac); + + if(factor==-1.0f && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "mathutils.Matrix.Shear(): " + "the factor to be a float"); + return NULL; + } + + /* unit */ + mat[0] = 1.0f; + mat[3] = 1.0f; + + if(strcmp(plane, "X") == 0) { + mat[2] = factor; + } + else if(strcmp(plane, "Y") == 0) { + mat[1] = factor; + } + else { + PyErr_SetString(PyExc_ValueError, + "Matrix.Shear(): " + "expected: X, Y or wrong matrix size for shearing plane"); + return NULL; + } + } + else { + /* 3 or 4, apply as 3x3, resize later if needed */ + float factor[2]; + + if(mathutils_array_parse(factor, 2, 2, fac, "Matrix.Shear()") < 0) { + return NULL; + } + + /* unit */ + mat[0] = 1.0f; + mat[4] = 1.0f; + mat[8] = 1.0f; + + if(strcmp(plane, "XY") == 0) { + mat[6] = factor[0]; + mat[7] = factor[1]; + } + else if(strcmp(plane, "XZ") == 0) { + mat[3] = factor[0]; + mat[5] = factor[1]; + } + else if(strcmp(plane, "YZ") == 0) { + mat[1] = factor[0]; + mat[2] = factor[1]; + } + else { + PyErr_SetString(PyExc_ValueError, + "mathutils.Matrix.Shear(): " + "expected: X, Y, XY, XZ, YZ"); + return NULL; + } + } + + if(matSize == 4) { + matrix_3x3_as_4x4(mat); + } + //pass to matrix creation + return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls); +} + +void matrix_as_3x3(float mat[3][3], MatrixObject *self) +{ + copy_v3_v3(mat[0], self->matrix[0]); + copy_v3_v3(mat[1], self->matrix[1]); + copy_v3_v3(mat[2], self->matrix[2]); +} + +/* assumes rowsize == colsize is checked and the read callback has run */ +static float matrix_determinant_internal(MatrixObject *self) +{ + if(self->row_size == 2) { + return determinant_m2(self->matrix[0][0], self->matrix[0][1], + self->matrix[1][0], self->matrix[1][1]); + } + else if(self->row_size == 3) { + return determinant_m3(self->matrix[0][0], self->matrix[0][1], + self->matrix[0][2], self->matrix[1][0], + self->matrix[1][1], self->matrix[1][2], + self->matrix[2][0], self->matrix[2][1], + self->matrix[2][2]); + } + else { + return determinant_m4((float (*)[4])self->contigPtr); + } +} + + +/*-----------------------------METHODS----------------------------*/ +PyDoc_STRVAR(Matrix_to_quaternion_doc, +".. method:: to_quaternion()\n" +"\n" +" Return a quaternion representation of the rotation matrix.\n" +"\n" +" :return: Quaternion representation of the rotation matrix.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Matrix_to_quaternion(MatrixObject *self) +{ + float quat[4]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if((self->col_size < 3) || (self->row_size < 3) || (self->col_size != self->row_size)) { + PyErr_SetString(PyExc_ValueError, + "matrix.to_quat(): " + "inappropriate matrix size - expects 3x3 or 4x4 matrix"); + return NULL; + } + if(self->col_size == 3){ + mat3_to_quat(quat, (float (*)[3])self->contigPtr); + } + else { + mat4_to_quat(quat, (float (*)[4])self->contigPtr); + } + + return newQuaternionObject(quat, Py_NEW, NULL); +} + +/*---------------------------matrix.toEuler() --------------------*/ +PyDoc_STRVAR(Matrix_to_euler_doc, +".. method:: to_euler(order, euler_compat)\n" +"\n" +" Return an Euler representation of the rotation matrix\n" +" (3x3 or 4x4 matrix only).\n" +"\n" +" :arg order: Optional rotation order argument in\n" +" ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n" +" :type order: string\n" +" :arg euler_compat: Optional euler argument the new euler will be made\n" +" compatible with (no axis flipping between them).\n" +" Useful for converting a series of matrices to animation curves.\n" +" :type euler_compat: :class:`Euler`\n" +" :return: Euler representation of the matrix.\n" +" :rtype: :class:`Euler`\n" +); +static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args) +{ + const char *order_str= NULL; + short order= EULER_ORDER_XYZ; + float eul[3], eul_compatf[3]; + EulerObject *eul_compat = NULL; + + float tmat[3][3]; + float (*mat)[3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) + return NULL; + + if(eul_compat) { + if(BaseMath_ReadCallback(eul_compat) == -1) + return NULL; + + copy_v3_v3(eul_compatf, eul_compat->eul); + } + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->col_size ==3 && self->row_size ==3) { + mat= (float (*)[3])self->contigPtr; + } + else if (self->col_size ==4 && self->row_size ==4) { + copy_m3_m4(tmat, (float (*)[4])self->contigPtr); + mat= tmat; + } + else { + PyErr_SetString(PyExc_ValueError, + "matrix.to_euler(): " + "inappropriate matrix size - expects 3x3 or 4x4 matrix"); + return NULL; + } + + if(order_str) { + order= euler_order_from_string(order_str, "matrix.to_euler()"); + + if(order == -1) + return NULL; + } + + if(eul_compat) { + if(order == 1) mat3_to_compatible_eul(eul, eul_compatf, mat); + else mat3_to_compatible_eulO(eul, eul_compatf, order, mat); + } + else { + if(order == 1) mat3_to_eul(eul, mat); + else mat3_to_eulO(eul, order, mat); + } + + return newEulerObject(eul, order, Py_NEW, NULL); +} + +PyDoc_STRVAR(Matrix_resize_4x4_doc, +".. method:: resize_4x4()\n" +"\n" +" Resize the matrix to 4x4.\n" +); +static PyObject *Matrix_resize_4x4(MatrixObject *self) +{ + int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index; + + if(self->wrapped==Py_WRAP){ + PyErr_SetString(PyExc_TypeError, + "cannot resize wrapped data - make a copy and resize that"); + return NULL; + } + if(self->cb_user){ + PyErr_SetString(PyExc_TypeError, + "cannot resize owned data - make a copy and resize that"); + return NULL; + } + + self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16)); + if(self->contigPtr == NULL) { + PyErr_SetString(PyExc_MemoryError, + "matrix.resize_4x4(): problem allocating pointer space"); + return NULL; + } + /*set row pointers*/ + for(x = 0; x < 4; x++) { + self->matrix[x] = self->contigPtr + (x * 4); + } + /*move data to new spot in array + clean*/ + for(blank_rows = (4 - self->row_size); blank_rows > 0; blank_rows--){ + for(x = 0; x < 4; x++){ + index = (4 * (self->row_size + (blank_rows - 1))) + x; + if (index == 10 || index == 15){ + self->contigPtr[index] = 1.0f; + } + else { + self->contigPtr[index] = 0.0f; + } + } + } + for(x = 1; x <= self->row_size; x++){ + first_row_elem = (self->col_size * (self->row_size - x)); + curr_pos = (first_row_elem + (self->col_size -1)); + new_pos = (4 * (self->row_size - x)) + (curr_pos - first_row_elem); + for(blank_columns = (4 - self->col_size); blank_columns > 0; blank_columns--){ + self->contigPtr[new_pos + blank_columns] = 0.0f; + } + for( ; curr_pos >= first_row_elem; curr_pos--){ + self->contigPtr[new_pos] = self->contigPtr[curr_pos]; + new_pos--; + } + } + self->row_size = 4; + self->col_size = 4; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Matrix_to_4x4_doc, +".. method:: to_4x4()\n" +"\n" +" Return a 4x4 copy of this matrix.\n" +"\n" +" :return: a new matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_to_4x4(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(self->col_size==4 && self->row_size==4) { + return (PyObject *)newMatrixObject(self->contigPtr, 4, 4, Py_NEW, Py_TYPE(self)); + } + else if(self->col_size==3 && self->row_size==3) { + float mat[4][4]; + copy_m4_m3(mat, (float (*)[3])self->contigPtr); + return (PyObject *)newMatrixObject((float *)mat, 4, 4, Py_NEW, Py_TYPE(self)); + } + /* TODO, 2x2 matrix */ + + PyErr_SetString(PyExc_TypeError, + "matrix.to_4x4(): inappropriate matrix size"); + return NULL; +} + +PyDoc_STRVAR(Matrix_to_3x3_doc, +".. method:: to_3x3()\n" +"\n" +" Return a 3x3 copy of this matrix.\n" +"\n" +" :return: a new matrix.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_to_3x3(MatrixObject *self) +{ + float mat[3][3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if((self->col_size < 3) || (self->row_size < 3)) { + PyErr_SetString(PyExc_TypeError, + "matrix.to_3x3(): inappropriate matrix size"); + return NULL; + } + + matrix_as_3x3(mat, self); + + return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Matrix_to_translation_doc, +".. method:: to_translation()\n" +"\n" +" Return a the translation part of a 4 row matrix.\n" +"\n" +" :return: Return a the translation of a matrix.\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Matrix_to_translation(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if((self->col_size < 3) || self->row_size < 4){ + PyErr_SetString(PyExc_TypeError, + "matrix.to_translation(): " + "inappropriate matrix size"); + return NULL; + } + + return newVectorObject(self->matrix[3], 3, Py_NEW, NULL); +} + +PyDoc_STRVAR(Matrix_to_scale_doc, +".. method:: to_scale()\n" +"\n" +" Return a the scale part of a 3x3 or 4x4 matrix.\n" +"\n" +" :return: Return a the scale of a matrix.\n" +" :rtype: :class:`Vector`\n" +"\n" +" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n" +); +static PyObject *Matrix_to_scale(MatrixObject *self) +{ + float rot[3][3]; + float mat[3][3]; + float size[3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if((self->col_size < 3) || (self->row_size < 3)) { + PyErr_SetString(PyExc_TypeError, + "matrix.to_scale(): " + "inappropriate matrix size, 3x3 minimum size"); + return NULL; + } + + matrix_as_3x3(mat, self); + + /* compatible mat4_to_loc_rot_size */ + mat3_to_rot_size(rot, size, mat); + + return newVectorObject(size, 3, Py_NEW, NULL); +} + +/*---------------------------matrix.invert() ---------------------*/ +PyDoc_STRVAR(Matrix_invert_doc, +".. method:: invert()\n" +"\n" +" Set the matrix to its inverse.\n" +"\n" +" .. note:: :exc:`ValueError` exception is raised.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n" +); +static PyObject *Matrix_invert(MatrixObject *self) +{ + + int x, y, z = 0; + float det = 0.0f; + float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(self->row_size != self->col_size){ + PyErr_SetString(PyExc_TypeError, + "matrix.invert(ed): " + "only square matrices are supported"); + return NULL; + } + + /*calculate the determinant*/ + det = matrix_determinant_internal(self); + + if(det != 0) { + /*calculate the classical adjoint*/ + if(self->row_size == 2) { + mat[0] = self->matrix[1][1]; + mat[1] = -self->matrix[0][1]; + mat[2] = -self->matrix[1][0]; + mat[3] = self->matrix[0][0]; + } else if(self->row_size == 3) { + adjoint_m3_m3((float (*)[3]) mat,(float (*)[3])self->contigPtr); + } else if(self->row_size == 4) { + adjoint_m4_m4((float (*)[4]) mat, (float (*)[4])self->contigPtr); + } + /*divide by determinate*/ + for(x = 0; x < (self->row_size * self->col_size); x++) { + mat[x] /= det; + } + /*set values*/ + for(x = 0; x < self->row_size; x++) { + for(y = 0; y < self->col_size; y++) { + self->matrix[x][y] = mat[z]; + z++; + } + } + /*transpose + Matrix_transpose(self);*/ + } + else { + PyErr_SetString(PyExc_ValueError, + "matrix does not have an inverse"); + return NULL; + } + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Matrix_inverted_doc, +".. method:: inverted()\n" +"\n" +" Return an inverted copy of the matrix.\n" +"\n" +" :return: the inverted matrix.\n" +" :rtype: :class:`Matrix`\n" +"\n" +" .. note:: :exc:`ValueError` exception is raised.\n" +); +static PyObject *Matrix_inverted(MatrixObject *self) +{ + return matrix__apply_to_copy((PyNoArgsFunction)Matrix_invert, self); +} + +PyDoc_STRVAR(Matrix_rotate_doc, +".. method:: rotate(other)\n" +"\n" +" Rotates the matrix a by another mathutils value.\n" +"\n" +" :arg other: rotation component of mathutils value\n" +" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" +"\n" +" .. note:: If any of the columns are not unit length this may not have desired results.\n" +); +static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value) +{ + float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1) + return NULL; + + if(self->col_size != 3 || self->row_size != 3) { + PyErr_SetString(PyExc_TypeError, + "Matrix must have 3x3 dimensions"); + return NULL; + } + + matrix_as_3x3(self_rmat, self); + mul_m3_m3m3(rmat, self_rmat, other_rmat); + + copy_m3_m3((float (*)[3])(self->contigPtr), rmat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +/*---------------------------matrix.decompose() ---------------------*/ +PyDoc_STRVAR(Matrix_decompose_doc, +".. method:: decompose()\n" +"\n" +" Return the location, rotaion and scale components of this matrix.\n" +"\n" +" :return: loc, rot, scale triple.\n" +" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)" +); +static PyObject *Matrix_decompose(MatrixObject *self) +{ + PyObject *ret; + float loc[3]; + float rot[3][3]; + float quat[4]; + float size[3]; + + if(self->col_size != 4 || self->row_size != 4) { + PyErr_SetString(PyExc_TypeError, + "matrix.decompose(): " + "inappropriate matrix size - expects 4x4 matrix"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + mat4_to_loc_rot_size(loc, rot, size, (float (*)[4])self->contigPtr); + mat3_to_quat(quat, rot); + + ret= PyTuple_New(3); + PyTuple_SET_ITEM(ret, 0, newVectorObject(loc, 3, Py_NEW, NULL)); + PyTuple_SET_ITEM(ret, 1, newQuaternionObject(quat, Py_NEW, NULL)); + PyTuple_SET_ITEM(ret, 2, newVectorObject(size, 3, Py_NEW, NULL)); + + return ret; +} + + + +PyDoc_STRVAR(Matrix_lerp_doc, +".. function:: lerp(other, factor)\n" +"\n" +" Returns the interpolation of two matricies.\n" +"\n" +" :arg other: value to interpolate with.\n" +" :type other: :class:`Matrix`\n" +" :arg factor: The interpolation value in [0.0, 1.0].\n" +" :type factor: float\n" +" :return: The interpolated rotation.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) +{ + MatrixObject *mat2 = NULL; + float fac, mat[MATRIX_MAX_DIM*MATRIX_MAX_DIM]; + + if(!PyArg_ParseTuple(args, "O!f:lerp", &matrix_Type, &mat2, &fac)) + return NULL; + + if(self->row_size != mat2->row_size || self->col_size != mat2->col_size) { + PyErr_SetString(PyExc_ValueError, + "matrix.lerp(): " + "expects both matrix objects of the same dimensions"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1 || BaseMath_ReadCallback(mat2) == -1) + return NULL; + + /* TODO, different sized matrix */ + if(self->row_size==4 && self->col_size==4) { + blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->contigPtr, (float (*)[4])mat2->contigPtr, fac); + } + else if (self->row_size==3 && self->col_size==3) { + blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->contigPtr, (float (*)[3])mat2->contigPtr, fac); + } + else { + PyErr_SetString(PyExc_ValueError, + "matrix.lerp(): " + "only 3x3 and 4x4 matrices supported"); + return NULL; + } + + return (PyObject*)newMatrixObject(mat, self->row_size, self->col_size, Py_NEW, Py_TYPE(self)); +} + +/*---------------------------matrix.determinant() ----------------*/ +PyDoc_STRVAR(Matrix_determinant_doc, +".. method:: determinant()\n" +"\n" +" Return the determinant of a matrix.\n" +"\n" +" :return: Return a the determinant of a matrix.\n" +" :rtype: float\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n" +); +static PyObject *Matrix_determinant(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(self->row_size != self->col_size){ + PyErr_SetString(PyExc_TypeError, + "matrix.determinant: " + "only square matrices are supported"); + return NULL; + } + + return PyFloat_FromDouble((double)matrix_determinant_internal(self)); +} +/*---------------------------matrix.transpose() ------------------*/ +PyDoc_STRVAR(Matrix_transpose_doc, +".. method:: transpose()\n" +"\n" +" Set the matrix to its transpose.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n" +); +static PyObject *Matrix_transpose(MatrixObject *self) +{ + float t = 0.0f; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(self->row_size != self->col_size){ + PyErr_SetString(PyExc_TypeError, + "matrix.transpose(d): " + "only square matrices are supported"); + return NULL; + } + + if(self->row_size == 2) { + t = self->matrix[1][0]; + self->matrix[1][0] = self->matrix[0][1]; + self->matrix[0][1] = t; + } else if(self->row_size == 3) { + transpose_m3((float (*)[3])self->contigPtr); + } + else { + transpose_m4((float (*)[4])self->contigPtr); + } + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Matrix_transposed_doc, +".. method:: transposed()\n" +"\n" +" Return a new, transposed matrix.\n" +"\n" +" :return: a transposed matrix\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_transposed(MatrixObject *self) +{ + return matrix__apply_to_copy((PyNoArgsFunction)Matrix_transpose, self); +} + +/*---------------------------matrix.zero() -----------------------*/ +PyDoc_STRVAR(Matrix_zero_doc, +".. method:: zero()\n" +"\n" +" Set all the matrix values to zero.\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_zero(MatrixObject *self) +{ + fill_vn(self->contigPtr, self->row_size * self->col_size, 0.0f); + + if(BaseMath_WriteCallback(self) == -1) + return NULL; + + Py_RETURN_NONE; +} +/*---------------------------matrix.identity(() ------------------*/ +PyDoc_STRVAR(Matrix_identity_doc, +".. method:: identity()\n" +"\n" +" Set the matrix to the identity matrix.\n" +"\n" +" .. note:: An object with zero location and rotation, a scale of one,\n" +" will have an identity matrix.\n" +"\n" +" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n" +); +static PyObject *Matrix_identity(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(self->row_size != self->col_size){ + PyErr_SetString(PyExc_TypeError, + "matrix.identity: " + "only square matrices are supported"); + return NULL; + } + + if(self->row_size == 2) { + self->matrix[0][0] = 1.0f; + self->matrix[0][1] = 0.0f; + self->matrix[1][0] = 0.0f; + self->matrix[1][1] = 1.0f; + } else if(self->row_size == 3) { + unit_m3((float (*)[3])self->contigPtr); + } + else { + unit_m4((float (*)[4])self->contigPtr); + } + + if(BaseMath_WriteCallback(self) == -1) + return NULL; + + Py_RETURN_NONE; +} + +/*---------------------------Matrix.copy() ------------------*/ +PyDoc_STRVAR(Matrix_copy_doc, +".. method:: copy()\n" +"\n" +" Returns a copy of this matrix.\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Matrix_copy(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->row_size, self->col_size, Py_NEW, Py_TYPE(self)); +} + +/*----------------------------print object (internal)-------------*/ +/*print the object to screen*/ +static PyObject *Matrix_repr(MatrixObject *self) +{ + int x, y; + PyObject *rows[MATRIX_MAX_DIM]= {NULL}; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + for(x = 0; x < self->row_size; x++){ + rows[x]= PyTuple_New(self->col_size); + for(y = 0; y < self->col_size; y++) { + PyTuple_SET_ITEM(rows[x], y, PyFloat_FromDouble(self->matrix[x][y])); + } + } + switch(self->row_size) { + case 2: return PyUnicode_FromFormat("Matrix(%R,\n" + " %R)", rows[0], rows[1]); + + case 3: return PyUnicode_FromFormat("Matrix(%R,\n" + " %R,\n" + " %R)", rows[0], rows[1], rows[2]); + + case 4: return PyUnicode_FromFormat("Matrix(%R,\n" + " %R,\n" + " %R,\n" + " %R)", rows[0], rows[1], rows[2], rows[3]); + } + + PyErr_SetString(PyExc_RuntimeError, + "internal error!"); + return NULL; +} + +static PyObject* Matrix_richcmpr(PyObject *a, PyObject *b, int op) +{ + PyObject *res; + int ok= -1; /* zero is true */ + + if (MatrixObject_Check(a) && MatrixObject_Check(b)) { + MatrixObject *matA= (MatrixObject*)a; + MatrixObject *matB= (MatrixObject*)b; + + if(BaseMath_ReadCallback(matA) == -1 || BaseMath_ReadCallback(matB) == -1) + return NULL; + + ok= ( (matA->col_size == matB->col_size) && + (matA->row_size == matB->row_size) && + EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, (matA->row_size * matA->col_size), 1) + ) ? 0 : -1; + } + + switch (op) { + case Py_NE: + ok = !ok; /* pass through */ + case Py_EQ: + res = ok ? Py_False : Py_True; + break; + + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + res = Py_NotImplemented; + break; + default: + PyErr_BadArgument(); + return NULL; + } + + return Py_INCREF(res), res; +} + +/*---------------------SEQUENCE PROTOCOLS------------------------ + ----------------------------len(object)------------------------ + sequence length*/ +static int Matrix_len(MatrixObject *self) +{ + return (self->row_size); +} +/*----------------------------object[]--------------------------- + sequence accessor (get) + the wrapped vector gives direct access to the matrix data*/ +static PyObject *Matrix_item(MatrixObject *self, int i) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(i < 0 || i >= self->row_size) { + PyErr_SetString(PyExc_IndexError, + "matrix[attribute]: " + "array index out of range"); + return NULL; + } + return newVectorObject_cb((PyObject *)self, self->col_size, mathutils_matrix_vector_cb_index, i); +} +/*----------------------------object[]------------------------- + sequence accessor (set) */ + +static int Matrix_ass_item(MatrixObject *self, int i, PyObject *value) +{ + float vec[4]; + if(BaseMath_ReadCallback(self) == -1) + return -1; + + if(i >= self->row_size || i < 0){ + PyErr_SetString(PyExc_IndexError, + "matrix[attribute] = x: bad column"); + return -1; + } + + if(mathutils_array_parse(vec, self->col_size, self->col_size, value, "matrix[i] = value assignment") < 0) { + return -1; + } + + memcpy(self->matrix[i], vec, self->col_size *sizeof(float)); + + (void)BaseMath_WriteCallback(self); + return 0; +} + +/*----------------------------object[z:y]------------------------ + sequence slice (get)*/ +static PyObject *Matrix_slice(MatrixObject *self, int begin, int end) +{ + + PyObject *tuple; + int count; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + CLAMP(begin, 0, self->row_size); + CLAMP(end, 0, self->row_size); + begin= MIN2(begin, end); + + tuple= PyTuple_New(end - begin); + for(count= begin; count < end; count++) { + PyTuple_SET_ITEM(tuple, count - begin, + newVectorObject_cb((PyObject *)self, self->col_size, mathutils_matrix_vector_cb_index, count)); + + } + + return tuple; +} +/*----------------------------object[z:y]------------------------ + sequence slice (set)*/ +static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value) +{ + PyObject *value_fast= NULL; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + CLAMP(begin, 0, self->row_size); + CLAMP(end, 0, self->row_size); + begin = MIN2(begin, end); + + /* non list/tuple cases */ + if(!(value_fast=PySequence_Fast(value, "matrix[begin:end] = value"))) { + /* PySequence_Fast sets the error */ + return -1; + } + else { + const int size= end - begin; + int i; + float mat[16]; + + if(PySequence_Fast_GET_SIZE(value_fast) != size) { + Py_DECREF(value_fast); + PyErr_SetString(PyExc_ValueError, + "matrix[begin:end] = []: " + "size mismatch in slice assignment"); + return -1; + } + + /*parse sub items*/ + for (i = 0; i < size; i++) { + /*parse each sub sequence*/ + PyObject *item= PySequence_Fast_GET_ITEM(value_fast, i); + + if(mathutils_array_parse(&mat[i * self->col_size], self->col_size, self->col_size, item, "matrix[begin:end] = value assignment") < 0) { + return -1; + } + } + + Py_DECREF(value_fast); + + /*parsed well - now set in matrix*/ + memcpy(self->contigPtr + (begin * self->col_size), mat, sizeof(float) * (size * self->col_size)); + + (void)BaseMath_WriteCallback(self); + return 0; + } +} +/*------------------------NUMERIC PROTOCOLS---------------------- + ------------------------obj + obj------------------------------*/ +static PyObject *Matrix_add(PyObject *m1, PyObject *m2) +{ + float mat[16]; + MatrixObject *mat1 = NULL, *mat2 = NULL; + + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; + + if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { + PyErr_SetString(PyExc_TypeError, + "Matrix addition: " + "arguments not valid for this operation"); + return NULL; + } + + if(BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) + return NULL; + + if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){ + PyErr_SetString(PyExc_TypeError, + "Matrix addition: " + "matrices must have the same dimensions for this operation"); + return NULL; + } + + add_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->row_size * mat1->col_size); + + return newMatrixObject(mat, mat1->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1)); +} +/*------------------------obj - obj------------------------------ + subtraction*/ +static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) +{ + float mat[16]; + MatrixObject *mat1 = NULL, *mat2 = NULL; + + mat1 = (MatrixObject*)m1; + mat2 = (MatrixObject*)m2; + + if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { + PyErr_SetString(PyExc_TypeError, + "Matrix addition: " + "arguments not valid for this operation"); + return NULL; + } + + if(BaseMath_ReadCallback(mat1) == -1 || BaseMath_ReadCallback(mat2) == -1) + return NULL; + + if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){ + PyErr_SetString(PyExc_TypeError, + "Matrix addition: " + "matrices must have the same dimensions for this operation"); + return NULL; + } + + sub_vn_vnvn(mat, mat1->contigPtr, mat2->contigPtr, mat1->row_size * mat1->col_size); + + return newMatrixObject(mat, mat1->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1)); +} +/*------------------------obj * obj------------------------------ + mulplication*/ +static PyObject *matrix_mul_float(MatrixObject *mat, const float scalar) +{ + float tmat[16]; + mul_vn_vn_fl(tmat, mat->contigPtr, mat->row_size * mat->col_size, scalar); + return newMatrixObject(tmat, mat->row_size, mat->col_size, Py_NEW, Py_TYPE(mat)); +} + +static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) +{ + float scalar; + + MatrixObject *mat1 = NULL, *mat2 = NULL; + + if(MatrixObject_Check(m1)) { + mat1 = (MatrixObject*)m1; + if(BaseMath_ReadCallback(mat1) == -1) + return NULL; + } + if(MatrixObject_Check(m2)) { + mat2 = (MatrixObject*)m2; + if(BaseMath_ReadCallback(mat2) == -1) + return NULL; + } + + if(mat1 && mat2) { + /*MATRIX * MATRIX*/ + if(mat1->row_size != mat2->col_size){ + PyErr_SetString(PyExc_ValueError, + "Matrix multiplication: " + "matrix A rowsize must equal matrix B colsize"); + return NULL; + } + else { + float mat[16]= {0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + double dot = 0.0f; + int x, y, z; + + for(x = 0; x < mat2->row_size; x++) { + for(y = 0; y < mat1->col_size; y++) { + for(z = 0; z < mat1->row_size; z++) { + dot += (mat1->matrix[z][y] * mat2->matrix[x][z]); + } + mat[((x * mat1->col_size) + y)] = (float)dot; + dot = 0.0f; + } + } + + return newMatrixObject(mat, mat2->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1)); + } + } + else if(mat2) { + /*FLOAT/INT * MATRIX */ + if (((scalar= PyFloat_AsDouble(m1)) == -1.0f && PyErr_Occurred())==0) { + return matrix_mul_float(mat2, scalar); + } + } + else if(mat1) { + /*FLOAT/INT * MATRIX */ + if (((scalar= PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred())==0) { + return matrix_mul_float(mat1, scalar); + } + } + else { + BLI_assert(!"internal error"); + } + + PyErr_Format(PyExc_TypeError, + "Matrix multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(m1)->tp_name, Py_TYPE(m2)->tp_name); + return NULL; +} +static PyObject* Matrix_inv(MatrixObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return Matrix_invert(self); +} + +/*-----------------PROTOCOL DECLARATIONS--------------------------*/ +static PySequenceMethods Matrix_SeqMethods = { + (lenfunc) Matrix_len, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) NULL, /* sq_repeat */ + (ssizeargfunc) Matrix_item, /* sq_item */ + (ssizessizeargfunc) NULL, /* sq_slice, deprecated */ + (ssizeobjargproc) Matrix_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + + +static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->row_size; + return Matrix_item(self, i); + } else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, self->row_size, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Matrix_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with matricies"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "matrix indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + +static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->row_size; + return Matrix_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, self->row_size, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Matrix_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with matricies"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "matrix indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + +static PyMappingMethods Matrix_AsMapping = { + (lenfunc)Matrix_len, + (binaryfunc)Matrix_subscript, + (objobjargproc)Matrix_ass_subscript +}; + + +static PyNumberMethods Matrix_NumMethods = { + (binaryfunc) Matrix_add, /*nb_add*/ + (binaryfunc) Matrix_sub, /*nb_subtract*/ + (binaryfunc) Matrix_mul, /*nb_multiply*/ + NULL, /*nb_remainder*/ + NULL, /*nb_divmod*/ + NULL, /*nb_power*/ + (unaryfunc) 0, /*nb_negative*/ + (unaryfunc) 0, /*tp_positive*/ + (unaryfunc) 0, /*tp_absolute*/ + (inquiry) 0, /*tp_bool*/ + (unaryfunc) Matrix_inv, /*nb_invert*/ + NULL, /*nb_lshift*/ + (binaryfunc)0, /*nb_rshift*/ + NULL, /*nb_and*/ + NULL, /*nb_xor*/ + NULL, /*nb_or*/ + NULL, /*nb_int*/ + NULL, /*nb_reserved*/ + NULL, /*nb_float*/ + NULL, /* nb_inplace_add */ + NULL, /* nb_inplace_subtract */ + NULL, /* nb_inplace_multiply */ + NULL, /* nb_inplace_remainder */ + NULL, /* nb_inplace_power */ + NULL, /* nb_inplace_lshift */ + NULL, /* nb_inplace_rshift */ + NULL, /* nb_inplace_and */ + NULL, /* nb_inplace_xor */ + NULL, /* nb_inplace_or */ + NULL, /* nb_floor_divide */ + NULL, /* nb_true_divide */ + NULL, /* nb_inplace_floor_divide */ + NULL, /* nb_inplace_true_divide */ + NULL, /* nb_index */ +}; + +static PyObject *Matrix_getRowSize(MatrixObject *self, void *UNUSED(closure)) +{ + return PyLong_FromLong((long) self->row_size); +} + +static PyObject *Matrix_getColSize(MatrixObject *self, void *UNUSED(closure)) +{ + return PyLong_FromLong((long) self->col_size); +} + +static PyObject *Matrix_median_scale_get(MatrixObject *self, void *UNUSED(closure)) +{ + float mat[3][3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if((self->col_size < 3) || (self->row_size < 3)) { + PyErr_SetString(PyExc_AttributeError, + "matrix.median_scale: " + "inappropriate matrix size, 3x3 minimum"); + return NULL; + } + + matrix_as_3x3(mat, self); + + return PyFloat_FromDouble(mat3_to_scale(mat)); +} + +static PyObject *Matrix_is_negative_get(MatrixObject *self, void *UNUSED(closure)) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->col_size == 4 && self->row_size == 4) + return PyBool_FromLong(is_negative_m4((float (*)[4])self->contigPtr)); + else if(self->col_size == 3 && self->row_size == 3) + return PyBool_FromLong(is_negative_m3((float (*)[3])self->contigPtr)); + else { + PyErr_SetString(PyExc_AttributeError, + "matrix.is_negative: " + "inappropriate matrix size - expects 3x3 or 4x4 matrix"); + return NULL; + } +} + +static PyObject *Matrix_is_orthogonal_get(MatrixObject *self, void *UNUSED(closure)) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /*must be 3-4 cols, 3-4 rows, square matrix*/ + if(self->col_size == 4 && self->row_size == 4) + return PyBool_FromLong(is_orthogonal_m4((float (*)[4])self->contigPtr)); + else if(self->col_size == 3 && self->row_size == 3) + return PyBool_FromLong(is_orthogonal_m3((float (*)[3])self->contigPtr)); + else { + PyErr_SetString(PyExc_AttributeError, + "matrix.is_orthogonal: " + "inappropriate matrix size - expects 3x3 or 4x4 matrix"); + return NULL; + } +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Matrix_getseters[] = { + {(char *)"row_size", (getter)Matrix_getRowSize, (setter)NULL, (char *)"The row size of the matrix (readonly).\n\n:type: int", NULL}, + {(char *)"col_size", (getter)Matrix_getColSize, (setter)NULL, (char *)"The column size of the matrix (readonly).\n\n:type: int", NULL}, + {(char *)"median_scale", (getter)Matrix_median_scale_get, (setter)NULL, (char *)"The average scale applied to each axis (readonly).\n\n:type: float", NULL}, + {(char *)"is_negative", (getter)Matrix_is_negative_get, (setter)NULL, (char *)"True if this matrix results in a negative scale, 3x3 and 4x4 only, (readonly).\n\n:type: bool", NULL}, + {(char *)"is_orthogonal", (getter)Matrix_is_orthogonal_get, (setter)NULL, (char *)"True if this matrix is orthogonal, 3x3 and 4x4 only, (readonly).\n\n:type: bool", NULL}, + {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL}, + {(char *)"owner",(getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +/*-----------------------METHOD DEFINITIONS ----------------------*/ +static struct PyMethodDef Matrix_methods[] = { + /* derived values */ + {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc}, + {"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc}, + + /* in place only */ + {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc}, + {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc}, + + /* operate on original or copy */ + {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc}, + {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc}, + {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc}, + {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc}, + {"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc}, + // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc}, + {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc}, + {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc}, + {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc}, + + /* return converted representation */ + {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc}, + {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc}, + {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc}, + {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc}, + + /* operation between 2 or more types */ + {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc}, + {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, + {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc}, + + /* class methods */ + {"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc}, + {"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc}, + {"Shear", (PyCFunction) C_Matrix_Shear, METH_VARARGS | METH_CLASS, C_Matrix_Shear_doc}, + {"Translation", (PyCFunction) C_Matrix_Translation, METH_O | METH_CLASS, C_Matrix_Translation_doc}, + {"OrthoProjection", (PyCFunction) C_Matrix_OrthoProjection, METH_VARARGS | METH_CLASS, C_Matrix_OrthoProjection_doc}, + {NULL, NULL, 0, NULL} +}; + +/*------------------PY_OBECT DEFINITION--------------------------*/ +PyDoc_STRVAR(matrix_doc, +"This object gives access to Matrices in Blender." +); +PyTypeObject matrix_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "mathutils.Matrix", /*tp_name*/ + sizeof(MatrixObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BaseMathObject_dealloc, /*tp_dealloc*/ + NULL, /*tp_print*/ + NULL, /*tp_getattr*/ + NULL, /*tp_setattr*/ + NULL, /*tp_compare*/ + (reprfunc) Matrix_repr, /*tp_repr*/ + &Matrix_NumMethods, /*tp_as_number*/ + &Matrix_SeqMethods, /*tp_as_sequence*/ + &Matrix_AsMapping, /*tp_as_mapping*/ + NULL, /*tp_hash*/ + NULL, /*tp_call*/ + NULL, /*tp_str*/ + NULL, /*tp_getattro*/ + NULL, /*tp_setattro*/ + NULL, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + matrix_doc, /*tp_doc*/ + (traverseproc)BaseMathObject_traverse, //tp_traverse + (inquiry)BaseMathObject_clear, //tp_clear + (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + NULL, /*tp_iter*/ + NULL, /*tp_iternext*/ + Matrix_methods, /*tp_methods*/ + NULL, /*tp_members*/ + Matrix_getseters, /*tp_getset*/ + NULL, /*tp_base*/ + NULL, /*tp_dict*/ + NULL, /*tp_descr_get*/ + NULL, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + NULL, /*tp_init*/ + NULL, /*tp_alloc*/ + Matrix_new, /*tp_new*/ + NULL, /*tp_free*/ + NULL, /*tp_is_gc*/ + NULL, /*tp_bases*/ + NULL, /*tp_mro*/ + NULL, /*tp_cache*/ + NULL, /*tp_subclasses*/ + NULL, /*tp_weaklist*/ + NULL /*tp_del*/ +}; + +/*------------------------newMatrixObject (internal)------------- +creates a new matrix object +self->matrix self->contiguous_ptr (reference to data.xxx) + [0]------------->[0] + [1] + [2] + [1]------------->[3] + [4] + [5] + +self->matrix[1][1] = self->contigPtr[4] */ + +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsigned short colSize, int type, PyTypeObject *base_type) +{ + MatrixObject *self; + int x, row, col; + + /*matrix objects can be any 2-4row x 2-4col matrix*/ + if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4) { + PyErr_SetString(PyExc_RuntimeError, + "Matrix(): " + "row and column sizes must be between 2 and 4"); + return NULL; + } + + self= base_type ? (MatrixObject *)base_type->tp_alloc(base_type, 0) : + (MatrixObject *)PyObject_GC_New(MatrixObject, &matrix_Type); + + if(self) { + self->row_size = rowSize; + self->col_size = colSize; + + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP){ + self->contigPtr = mat; + /*pointer array points to contigous memory*/ + for(x = 0; x < rowSize; x++) { + self->matrix[x] = self->contigPtr + (x * colSize); + } + self->wrapped = Py_WRAP; + } + else if (type == Py_NEW){ + self->contigPtr = PyMem_Malloc(rowSize * colSize * sizeof(float)); + if(self->contigPtr == NULL) { /*allocation failure*/ + PyErr_SetString(PyExc_MemoryError, + "Matrix(): " + "problem allocating pointer space"); + return NULL; + } + /*pointer array points to contigous memory*/ + for(x = 0; x < rowSize; x++) { + self->matrix[x] = self->contigPtr + (x * colSize); + } + /*parse*/ + if(mat) { /*if a float array passed*/ + for(row = 0; row < rowSize; row++) { + for(col = 0; col < colSize; col++) { + self->matrix[row][col] = mat[(row * colSize) + col]; + } + } + } + else if (rowSize == colSize) { /*or if no arguments are passed return identity matrix for square matrices */ + PyObject *ret_dummy= Matrix_identity(self); + Py_DECREF(ret_dummy); + } + self->wrapped = Py_NEW; + } + else { + Py_FatalError("Matrix(): invalid type!"); + return NULL; + } + } + return (PyObject *) self; +} + +PyObject *newMatrixObject_cb(PyObject *cb_user, int rowSize, int colSize, int cb_type, int cb_subtype) +{ + MatrixObject *self= (MatrixObject *)newMatrixObject(NULL, rowSize, colSize, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + PyObject_GC_Track(self); + } + return (PyObject *) self; +} diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h new file mode 100644 index 00000000000..aa736d1e959 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Matrix.h @@ -0,0 +1,63 @@ +/* + * $Id$ + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/python/generic/mathutils_Matrix.h + * \ingroup pygen + */ + + +#ifndef MATHUTILS_MATRIX_H +#define MATHUTILS_MATRIX_H + +extern PyTypeObject matrix_Type; +#define MatrixObject_Check(_v) PyObject_TypeCheck((_v), &matrix_Type) +#define MATRIX_MAX_DIM 4 + +typedef struct { + BASE_MATH_MEMBERS(contigPtr) + float *matrix[MATRIX_MAX_DIM]; /* ptr to the contigPtr (accessor) */ + unsigned short row_size; + unsigned short col_size; +} MatrixObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +be stored in py_data) or be a wrapper for data allocated through +blender (stored in blend_data). This is an either/or struct not both*/ + +/*prototypes*/ +PyObject *newMatrixObject(float *mat, const unsigned short row_size, const unsigned short col_size, int type, PyTypeObject *base_type); +PyObject *newMatrixObject_cb(PyObject *user, int row_size, int col_size, int cb_type, int cb_subtype); + +extern int mathutils_matrix_vector_cb_index; +extern struct Mathutils_Callback mathutils_matrix_vector_cb; + +void matrix_as_3x3(float mat[3][3], MatrixObject *self); + +#endif /* MATHUTILS_MATRIX_H */ diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c new file mode 100644 index 00000000000..3b05b9a250b --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -0,0 +1,1164 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils_Quaternion.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#define QUAT_SIZE 4 + +static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self); +static PyObject *Quaternion_copy(QuaternionObject *self); + +//-----------------------------METHODS------------------------------ + +/* note: BaseMath_ReadCallback must be called beforehand */ +static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits) +{ + PyObject *ret; + int i; + + ret= PyTuple_New(QUAT_SIZE); + + if(ndigits >= 0) { + for(i= 0; i < QUAT_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->quat[i], ndigits))); + } + } + else { + for(i= 0; i < QUAT_SIZE; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->quat[i])); + } + } + + return ret; +} + +PyDoc_STRVAR(Quaternion_to_euler_doc, +".. method:: to_euler(order, euler_compat)\n" +"\n" +" Return Euler representation of the quaternion.\n" +"\n" +" :arg order: Optional rotation order argument in\n" +" ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX'].\n" +" :type order: string\n" +" :arg euler_compat: Optional euler argument the new euler will be made\n" +" compatible with (no axis flipping between them).\n" +" Useful for converting a series of matrices to animation curves.\n" +" :type euler_compat: :class:`Euler`\n" +" :return: Euler representation of the quaternion.\n" +" :rtype: :class:`Euler`\n" +); +static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args) +{ + float tquat[4]; + float eul[3]; + const char *order_str= NULL; + short order= EULER_ORDER_XYZ; + EulerObject *eul_compat = NULL; + + if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat)) + return NULL; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(order_str) { + order= euler_order_from_string(order_str, "Matrix.to_euler()"); + + if(order == -1) + return NULL; + } + + normalize_qt_qt(tquat, self->quat); + + if(eul_compat) { + float mat[3][3]; + + if(BaseMath_ReadCallback(eul_compat) == -1) + return NULL; + + quat_to_mat3(mat, tquat); + + if(order == EULER_ORDER_XYZ) mat3_to_compatible_eul(eul, eul_compat->eul, mat); + else mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat); + } + else { + if(order == EULER_ORDER_XYZ) quat_to_eul(eul, tquat); + else quat_to_eulO(eul, order, tquat); + } + + return newEulerObject(eul, order, Py_NEW, NULL); +} +//----------------------------Quaternion.toMatrix()------------------ +PyDoc_STRVAR(Quaternion_to_matrix_doc, +".. method:: to_matrix()\n" +"\n" +" Return a matrix representation of the quaternion.\n" +"\n" +" :return: A 3x3 rotation matrix representation of the quaternion.\n" +" :rtype: :class:`Matrix`\n" +); +static PyObject *Quaternion_to_matrix(QuaternionObject *self) +{ + float mat[9]; /* all values are set */ + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + quat_to_mat3((float (*)[3])mat, self->quat); + return newMatrixObject(mat, 3, 3, Py_NEW, NULL); +} + +//----------------------------Quaternion.cross(other)------------------ +PyDoc_STRVAR(Quaternion_cross_doc, +".. method:: cross(other)\n" +"\n" +" Return the cross product of this quaternion and another.\n" +"\n" +" :arg other: The other quaternion to perform the cross product with.\n" +" :type other: :class:`Quaternion`\n" +" :return: The cross product.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value) +{ + float quat[QUAT_SIZE], tquat[QUAT_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.cross(other), invalid 'other' arg") == -1) + return NULL; + + mul_qt_qtqt(quat, self->quat, tquat); + return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); +} + +//----------------------------Quaternion.dot(other)------------------ +PyDoc_STRVAR(Quaternion_dot_doc, +".. method:: dot(other)\n" +"\n" +" Return the dot product of this quaternion and another.\n" +"\n" +" :arg other: The other quaternion to perform the dot product with.\n" +" :type other: :class:`Quaternion`\n" +" :return: The dot product.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value) +{ + float tquat[QUAT_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.dot(other), invalid 'other' arg") == -1) + return NULL; + + return PyFloat_FromDouble(dot_qtqt(self->quat, tquat)); +} + +PyDoc_STRVAR(Quaternion_rotation_difference_doc, +".. function:: difference(other)\n" +"\n" +" Returns a quaternion representing the rotational difference.\n" +"\n" +" :arg other: second quaternion.\n" +" :type other: :class:`Quaternion`\n" +" :return: the rotational difference between the two quat rotations.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_rotation_difference(QuaternionObject *self, PyObject *value) +{ + float tquat[QUAT_SIZE], quat[QUAT_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.difference(other), invalid 'other' arg") == -1) + return NULL; + + rotation_between_quats_to_quat(quat, self->quat, tquat); + + return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Quaternion_slerp_doc, +".. function:: slerp(other, factor)\n" +"\n" +" Returns the interpolation of two quaternions.\n" +"\n" +" :arg other: value to interpolate with.\n" +" :type other: :class:`Quaternion`\n" +" :arg factor: The interpolation value in [0.0, 1.0].\n" +" :type factor: float\n" +" :return: The interpolated rotation.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args) +{ + PyObject *value; + float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac; + + if(!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) { + PyErr_SetString(PyExc_TypeError, + "quat.slerp(): " + "expected Quaternion types and float"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.slerp(other), invalid 'other' arg") == -1) + return NULL; + + if(fac > 1.0f || fac < 0.0f) { + PyErr_SetString(PyExc_ValueError, + "quat.slerp(): " + "interpolation factor must be between 0.0 and 1.0"); + return NULL; + } + + interp_qt_qtqt(quat, self->quat, tquat, fac); + + return newQuaternionObject(quat, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Quaternion_rotate_doc, +".. method:: rotate(other)\n" +"\n" +" Rotates the quaternion a by another mathutils value.\n" +"\n" +" :arg other: rotation component of mathutils value\n" +" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" +); +static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value) +{ + float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; + float tquat[4], length; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_any_to_rotmat(other_rmat, value, "quaternion.rotate(value)") == -1) + return NULL; + + length= normalize_qt_qt(tquat, self->quat); + quat_to_mat3(self_rmat, tquat); + mul_m3_m3m3(rmat, self_rmat, other_rmat); + + mat3_to_quat(self->quat, rmat); + mul_qt_fl(self->quat, length); /* maintain length after rotating */ + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +//----------------------------Quaternion.normalize()---------------- +//normalize the axis of rotation of [theta, vector] +PyDoc_STRVAR(Quaternion_normalize_doc, +".. function:: normalize()\n" +"\n" +" Normalize the quaternion.\n" +); +static PyObject *Quaternion_normalize(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + normalize_qt(self->quat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +PyDoc_STRVAR(Quaternion_normalized_doc, +".. function:: normalized()\n" +"\n" +" Return a new normalized quaternion.\n" +"\n" +" :return: a normalized copy.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_normalized(QuaternionObject *self) +{ + return quat__apply_to_copy((PyNoArgsFunction)Quaternion_normalize, self); +} + +//----------------------------Quaternion.invert()------------------ +PyDoc_STRVAR(Quaternion_invert_doc, +".. function:: invert()\n" +"\n" +" Set the quaternion to its inverse.\n" +); +static PyObject *Quaternion_invert(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + invert_qt(self->quat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +PyDoc_STRVAR(Quaternion_inverted_doc, +".. function:: inverted()\n" +"\n" +" Return a new, inverted quaternion.\n" +"\n" +" :return: the inverted value.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_inverted(QuaternionObject *self) +{ + return quat__apply_to_copy((PyNoArgsFunction)Quaternion_invert, self); +} + +//----------------------------Quaternion.identity()----------------- +PyDoc_STRVAR(Quaternion_identity_doc, +".. function:: identity()\n" +"\n" +" Set the quaternion to an identity quaternion.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_identity(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + unit_qt(self->quat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +//----------------------------Quaternion.negate()------------------- +PyDoc_STRVAR(Quaternion_negate_doc, +".. function:: negate()\n" +"\n" +" Set the quaternion to its negative.\n" +"\n" +" :return: an instance of itself.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_negate(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + mul_qt_fl(self->quat, -1.0f); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +//----------------------------Quaternion.conjugate()---------------- +PyDoc_STRVAR(Quaternion_conjugate_doc, +".. function:: conjugate()\n" +"\n" +" Set the quaternion to its conjugate (negate x, y, z).\n" +); +static PyObject *Quaternion_conjugate(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + conjugate_qt(self->quat); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +PyDoc_STRVAR(Quaternion_conjugated_doc, +".. function:: conjugated()\n" +"\n" +" Return a new conjugated quaternion.\n" +"\n" +" :return: a new quaternion.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Quaternion_conjugated(QuaternionObject *self) +{ + return quat__apply_to_copy((PyNoArgsFunction)Quaternion_conjugate, self); +} + +//----------------------------Quaternion.copy()---------------- +PyDoc_STRVAR(Quaternion_copy_doc, +".. function:: copy()\n" +"\n" +" Returns a copy of this quaternion.\n" +"\n" +" :return: A copy of the quaternion.\n" +" :rtype: :class:`Quaternion`\n" +"\n" +" .. note:: use this to get a copy of a wrapped quaternion with\n" +" no reference to the original data.\n" +); +static PyObject *Quaternion_copy(QuaternionObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return newQuaternionObject(self->quat, Py_NEW, Py_TYPE(self)); +} + +//----------------------------print object (internal)-------------- +//print the object to screen +static PyObject *Quaternion_repr(QuaternionObject *self) +{ + PyObject *ret, *tuple; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + tuple= Quaternion_to_tuple_ext(self, -1); + + ret= PyUnicode_FromFormat("Quaternion(%R)", tuple); + + Py_DECREF(tuple); + return ret; +} + +static PyObject* Quaternion_richcmpr(PyObject *a, PyObject *b, int op) +{ + PyObject *res; + int ok= -1; /* zero is true */ + + if (QuaternionObject_Check(a) && QuaternionObject_Check(b)) { + QuaternionObject *quatA= (QuaternionObject *)a; + QuaternionObject *quatB= (QuaternionObject *)b; + + if(BaseMath_ReadCallback(quatA) == -1 || BaseMath_ReadCallback(quatB) == -1) + return NULL; + + ok= (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1; + } + + switch (op) { + case Py_NE: + ok = !ok; /* pass through */ + case Py_EQ: + res = ok ? Py_False : Py_True; + break; + + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + res = Py_NotImplemented; + break; + default: + PyErr_BadArgument(); + return NULL; + } + + return Py_INCREF(res), res; +} + +//---------------------SEQUENCE PROTOCOLS------------------------ +//----------------------------len(object)------------------------ +//sequence length +static int Quaternion_len(QuaternionObject *UNUSED(self)) +{ + return QUAT_SIZE; +} +//----------------------------object[]--------------------------- +//sequence accessor (get) +static PyObject *Quaternion_item(QuaternionObject *self, int i) +{ + if(i<0) i= QUAT_SIZE-i; + + if(i < 0 || i >= QUAT_SIZE) { + PyErr_SetString(PyExc_IndexError, + "quaternion[attribute]: " + "array index out of range"); + return NULL; + } + + if(BaseMath_ReadIndexCallback(self, i) == -1) + return NULL; + + return PyFloat_FromDouble(self->quat[i]); + +} +//----------------------------object[]------------------------- +//sequence accessor (set) +static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob) +{ + float scalar= (float)PyFloat_AsDouble(ob); + if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, + "quaternion[index] = x: " + "index argument not a number"); + return -1; + } + + if(i<0) i= QUAT_SIZE-i; + + if(i < 0 || i >= QUAT_SIZE){ + PyErr_SetString(PyExc_IndexError, + "quaternion[attribute] = x: " + "array assignment index out of range"); + return -1; + } + self->quat[i] = scalar; + + if(BaseMath_WriteIndexCallback(self, i) == -1) + return -1; + + return 0; +} +//----------------------------object[z:y]------------------------ +//sequence slice (get) +static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end) +{ + PyObject *tuple; + int count; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + CLAMP(begin, 0, QUAT_SIZE); + if (end<0) end= (QUAT_SIZE + 1) + end; + CLAMP(end, 0, QUAT_SIZE); + begin= MIN2(begin, end); + + tuple= PyTuple_New(end - begin); + for(count= begin; count < end; count++) { + PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->quat[count])); + } + + return tuple; +} +//----------------------------object[z:y]------------------------ +//sequence slice (set) +static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq) +{ + int i, size; + float quat[QUAT_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + CLAMP(begin, 0, QUAT_SIZE); + if (end<0) end= (QUAT_SIZE + 1) + end; + CLAMP(end, 0, QUAT_SIZE); + begin = MIN2(begin, end); + + if((size=mathutils_array_parse(quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1) + return -1; + + if(size != (end - begin)){ + PyErr_SetString(PyExc_ValueError, + "quaternion[begin:end] = []: " + "size mismatch in slice assignment"); + return -1; + } + + /* parsed well - now set in vector */ + for(i= 0; i < size; i++) + self->quat[begin + i] = quat[i]; + + (void)BaseMath_WriteCallback(self); + return 0; +} + + +static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += QUAT_SIZE; + return Quaternion_item(self, i); + } else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Quaternion_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with quaternions"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "quaternion indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + + +static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyObject *value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += QUAT_SIZE; + return Quaternion_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, QUAT_SIZE, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Quaternion_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with quaternion"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "quaternion indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + +//------------------------NUMERIC PROTOCOLS---------------------- +//------------------------obj + obj------------------------------ +//addition +static PyObject *Quaternion_add(PyObject *q1, PyObject *q2) +{ + float quat[QUAT_SIZE]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { + PyErr_SetString(PyExc_TypeError, + "Quaternion addition: " + "arguments not valid for this operation"); + return NULL; + } + quat1 = (QuaternionObject*)q1; + quat2 = (QuaternionObject*)q2; + + if(BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) + return NULL; + + add_qt_qtqt(quat, quat1->quat, quat2->quat, 1.0f); + return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); +} +//------------------------obj - obj------------------------------ +//subtraction +static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2) +{ + int x; + float quat[QUAT_SIZE]; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { + PyErr_SetString(PyExc_TypeError, + "Quaternion addition: " + "arguments not valid for this operation"); + return NULL; + } + + quat1 = (QuaternionObject*)q1; + quat2 = (QuaternionObject*)q2; + + if(BaseMath_ReadCallback(quat1) == -1 || BaseMath_ReadCallback(quat2) == -1) + return NULL; + + for(x = 0; x < QUAT_SIZE; x++) { + quat[x] = quat1->quat[x] - quat2->quat[x]; + } + + return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); +} + +static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar) +{ + float tquat[4]; + copy_qt_qt(tquat, quat->quat); + mul_qt_fl(tquat, scalar); + return newQuaternionObject(tquat, Py_NEW, Py_TYPE(quat)); +} + +//------------------------obj * obj------------------------------ +//mulplication +static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) +{ + float quat[QUAT_SIZE], scalar; + QuaternionObject *quat1 = NULL, *quat2 = NULL; + + if(QuaternionObject_Check(q1)) { + quat1 = (QuaternionObject*)q1; + if(BaseMath_ReadCallback(quat1) == -1) + return NULL; + } + if(QuaternionObject_Check(q2)) { + quat2 = (QuaternionObject*)q2; + if(BaseMath_ReadCallback(quat2) == -1) + return NULL; + } + + if(quat1 && quat2) { /* QUAT*QUAT (cross product) */ + mul_qt_qtqt(quat, quat1->quat, quat2->quat); + return newQuaternionObject(quat, Py_NEW, Py_TYPE(q1)); + } + /* the only case this can happen (for a supported type is "FLOAT*QUAT") */ + else if(quat2) { /* FLOAT*QUAT */ + if(((scalar= PyFloat_AsDouble(q1)) == -1.0f && PyErr_Occurred())==0) { + return quat_mul_float(quat2, scalar); + } + } + else if (quat1) { /* QUAT*FLOAT */ + if((((scalar= PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred())==0)) { + return quat_mul_float(quat1, scalar); + } + } + else { + BLI_assert(!"internal error"); + } + + PyErr_Format(PyExc_TypeError, + "Quaternion multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(q1)->tp_name, Py_TYPE(q2)->tp_name); + return NULL; +} + +/* -obj + returns the negative of this object*/ +static PyObject *Quaternion_neg(QuaternionObject *self) +{ + float tquat[QUAT_SIZE]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + negate_v4_v4(tquat, self->quat); + return newQuaternionObject(tquat, Py_NEW, Py_TYPE(self)); +} + + +//-----------------PROTOCOL DECLARATIONS-------------------------- +static PySequenceMethods Quaternion_SeqMethods = { + (lenfunc) Quaternion_len, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) NULL, /* sq_repeat */ + (ssizeargfunc) Quaternion_item, /* sq_item */ + (ssizessizeargfunc) NULL, /* sq_slice, deprecated */ + (ssizeobjargproc) Quaternion_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc) NULL, /* sq_ass_slice, deprecated */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyMappingMethods Quaternion_AsMapping = { + (lenfunc)Quaternion_len, + (binaryfunc)Quaternion_subscript, + (objobjargproc)Quaternion_ass_subscript +}; + +static PyNumberMethods Quaternion_NumMethods = { + (binaryfunc) Quaternion_add, /*nb_add*/ + (binaryfunc) Quaternion_sub, /*nb_subtract*/ + (binaryfunc) Quaternion_mul, /*nb_multiply*/ + NULL, /*nb_remainder*/ + NULL, /*nb_divmod*/ + NULL, /*nb_power*/ + (unaryfunc) Quaternion_neg, /*nb_negative*/ + (unaryfunc) 0, /*tp_positive*/ + (unaryfunc) 0, /*tp_absolute*/ + (inquiry) 0, /*tp_bool*/ + (unaryfunc) 0, /*nb_invert*/ + NULL, /*nb_lshift*/ + (binaryfunc)0, /*nb_rshift*/ + NULL, /*nb_and*/ + NULL, /*nb_xor*/ + NULL, /*nb_or*/ + NULL, /*nb_int*/ + NULL, /*nb_reserved*/ + NULL, /*nb_float*/ + NULL, /* nb_inplace_add */ + NULL, /* nb_inplace_subtract */ + NULL, /* nb_inplace_multiply */ + NULL, /* nb_inplace_remainder */ + NULL, /* nb_inplace_power */ + NULL, /* nb_inplace_lshift */ + NULL, /* nb_inplace_rshift */ + NULL, /* nb_inplace_and */ + NULL, /* nb_inplace_xor */ + NULL, /* nb_inplace_or */ + NULL, /* nb_floor_divide */ + NULL, /* nb_true_divide */ + NULL, /* nb_inplace_floor_divide */ + NULL, /* nb_inplace_true_divide */ + NULL, /* nb_index */ +}; + +static PyObject *Quaternion_getAxis(QuaternionObject *self, void *type) +{ + return Quaternion_item(self, GET_INT_FROM_POINTER(type)); +} + +static int Quaternion_setAxis(QuaternionObject *self, PyObject *value, void *type) +{ + return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value); +} + +static PyObject *Quaternion_getMagnitude(QuaternionObject *self, void *UNUSED(closure)) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return PyFloat_FromDouble(sqrt(dot_qtqt(self->quat, self->quat))); +} + +static PyObject *Quaternion_getAngle(QuaternionObject *self, void *UNUSED(closure)) +{ + float tquat[4]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + normalize_qt_qt(tquat, self->quat); + return PyFloat_FromDouble(2.0f * (saacos(tquat[0]))); +} + +static int Quaternion_setAngle(QuaternionObject *self, PyObject *value, void *UNUSED(closure)) +{ + float tquat[4]; + float len; + + float axis[3], angle_dummy; + double angle; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + len= normalize_qt_qt(tquat, self->quat); + quat_to_axis_angle(axis, &angle_dummy, tquat); + + angle= PyFloat_AsDouble(value); + + if(angle==-1.0 && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, + "quaternion.angle = value: float expected"); + return -1; + } + + angle= angle_wrap_rad(angle); + + /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */ + if( EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && + EXPP_FloatsAreEqual(axis[1], 0.0f, 10) && + EXPP_FloatsAreEqual(axis[2], 0.0f, 10) + ) { + axis[0] = 1.0f; + } + + axis_angle_to_quat(self->quat, axis, angle); + mul_qt_fl(self->quat, len); + + if(BaseMath_WriteCallback(self) == -1) + return -1; + + return 0; +} + +static PyObject *Quaternion_getAxisVec(QuaternionObject *self, void *UNUSED(closure)) +{ + float tquat[4]; + + float axis[3]; + float angle; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + normalize_qt_qt(tquat, self->quat); + quat_to_axis_angle(axis, &angle, tquat); + + /* If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations */ + if( EXPP_FloatsAreEqual(axis[0], 0.0f, 10) && + EXPP_FloatsAreEqual(axis[1], 0.0f, 10) && + EXPP_FloatsAreEqual(axis[2], 0.0f, 10) + ) { + axis[0] = 1.0f; + } + + return (PyObject *) newVectorObject(axis, 3, Py_NEW, NULL); +} + +static int Quaternion_setAxisVec(QuaternionObject *self, PyObject *value, void *UNUSED(closure)) +{ + float tquat[4]; + float len; + + float axis[3]; + float angle; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + len= normalize_qt_qt(tquat, self->quat); + quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */ + + if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1) + return -1; + + axis_angle_to_quat(self->quat, axis, angle); + mul_qt_fl(self->quat, len); + + if(BaseMath_WriteCallback(self) == -1) + return -1; + + return 0; +} + +//----------------------------------mathutils.Quaternion() -------------- +static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *seq= NULL; + double angle = 0.0f; + float quat[QUAT_SIZE]= {0.0f, 0.0f, 0.0f, 0.0f}; + + if(kwds && PyDict_Size(kwds)) { + PyErr_SetString(PyExc_TypeError, + "mathutils.Quaternion(): " + "takes no keyword args"); + return NULL; + } + + if(!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle)) + return NULL; + + switch(PyTuple_GET_SIZE(args)) { + case 0: + break; + case 1: + if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1) + return NULL; + break; + case 2: + if (mathutils_array_parse(quat, 3, 3, seq, "mathutils.Quaternion()") == -1) + return NULL; + angle= angle_wrap_rad(angle); /* clamp because of precision issues */ + axis_angle_to_quat(quat, quat, angle); + break; + /* PyArg_ParseTuple assures no more then 2 */ + } + return newQuaternionObject(quat, Py_NEW, type); +} + +static PyObject *quat__apply_to_copy(PyNoArgsFunction quat_func, QuaternionObject *self) +{ + PyObject *ret= Quaternion_copy(self); + PyObject *ret_dummy= quat_func(ret); + if(ret_dummy) { + Py_DECREF(ret_dummy); + return (PyObject *)ret; + } + else { /* error */ + Py_DECREF(ret); + return NULL; + } +} + +//-----------------------METHOD DEFINITIONS ---------------------- +static struct PyMethodDef Quaternion_methods[] = { + /* in place only */ + {"identity", (PyCFunction) Quaternion_identity, METH_NOARGS, Quaternion_identity_doc}, + {"negate", (PyCFunction) Quaternion_negate, METH_NOARGS, Quaternion_negate_doc}, + + /* operate on original or copy */ + {"conjugate", (PyCFunction) Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc}, + {"conjugated", (PyCFunction) Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc}, + + {"invert", (PyCFunction) Quaternion_invert, METH_NOARGS, Quaternion_invert_doc}, + {"inverted", (PyCFunction) Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc}, + + {"normalize", (PyCFunction) Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc}, + {"normalized", (PyCFunction) Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc}, + + /* return converted representation */ + {"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc}, + {"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc}, + + /* operation between 2 or more types */ + {"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc}, + {"dot", (PyCFunction) Quaternion_dot, METH_O, Quaternion_dot_doc}, + {"rotation_difference", (PyCFunction) Quaternion_rotation_difference, METH_O, Quaternion_rotation_difference_doc}, + {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc}, + {"rotate", (PyCFunction) Quaternion_rotate, METH_O, Quaternion_rotate_doc}, + + {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, + {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc}, + {NULL, NULL, 0, NULL} +}; + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Quaternion_getseters[] = { + {(char *)"w", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion W value.\n\n:type: float", (void *)0}, + {(char *)"x", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion X axis.\n\n:type: float", (void *)1}, + {(char *)"y", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion Y axis.\n\n:type: float", (void *)2}, + {(char *)"z", (getter)Quaternion_getAxis, (setter)Quaternion_setAxis, (char *)"Quaternion Z axis.\n\n:type: float", (void *)3}, + {(char *)"magnitude", (getter)Quaternion_getMagnitude, (setter)NULL, (char *)"Size of the quaternion (readonly).\n\n:type: float", NULL}, + {(char *)"angle", (getter)Quaternion_getAngle, (setter)Quaternion_setAngle, (char *)"angle of the quaternion.\n\n:type: float", NULL}, + {(char *)"axis",(getter)Quaternion_getAxisVec, (setter)Quaternion_setAxisVec, (char *)"quaternion axis as a vector.\n\n:type: :class:`Vector`", NULL}, + {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL}, + {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL}, + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +//------------------PY_OBECT DEFINITION-------------------------- +PyDoc_STRVAR(quaternion_doc, +"This object gives access to Quaternions in Blender." +); +PyTypeObject quaternion_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "mathutils.Quaternion", //tp_name + sizeof(QuaternionObject), //tp_basicsize + 0, //tp_itemsize + (destructor)BaseMathObject_dealloc, //tp_dealloc + NULL, //tp_print + NULL, //tp_getattr + NULL, //tp_setattr + NULL, //tp_compare + (reprfunc) Quaternion_repr, //tp_repr + &Quaternion_NumMethods, //tp_as_number + &Quaternion_SeqMethods, //tp_as_sequence + &Quaternion_AsMapping, //tp_as_mapping + NULL, //tp_hash + NULL, //tp_call + NULL, //tp_str + NULL, //tp_getattro + NULL, //tp_setattro + NULL, //tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, //tp_flags + quaternion_doc, //tp_doc + (traverseproc)BaseMathObject_traverse, //tp_traverse + (inquiry)BaseMathObject_clear, //tp_clear + (richcmpfunc)Quaternion_richcmpr, //tp_richcompare + 0, //tp_weaklistoffset + NULL, //tp_iter + NULL, //tp_iternext + Quaternion_methods, //tp_methods + NULL, //tp_members + Quaternion_getseters, //tp_getset + NULL, //tp_base + NULL, //tp_dict + NULL, //tp_descr_get + NULL, //tp_descr_set + 0, //tp_dictoffset + NULL, //tp_init + NULL, //tp_alloc + Quaternion_new, //tp_new + NULL, //tp_free + NULL, //tp_is_gc + NULL, //tp_bases + NULL, //tp_mro + NULL, //tp_cache + NULL, //tp_subclasses + NULL, //tp_weaklist + NULL, //tp_del +}; +//------------------------newQuaternionObject (internal)------------- +//creates a new quaternion object +/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type) +{ + QuaternionObject *self; + + self= base_type ? (QuaternionObject *)base_type->tp_alloc(base_type, 0) : + (QuaternionObject *)PyObject_GC_New(QuaternionObject, &quaternion_Type); + + if(self) { + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP){ + self->quat = quat; + self->wrapped = Py_WRAP; + } + else if (type == Py_NEW){ + self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float)); + if(!quat) { //new empty + unit_qt(self->quat); + } + else { + QUATCOPY(self->quat, quat); + } + self->wrapped = Py_NEW; + } + else { + Py_FatalError("Quaternion(): invalid type!"); + } + } + return (PyObject *) self; +} + +PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype) +{ + QuaternionObject *self= (QuaternionObject *)newQuaternionObject(NULL, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + PyObject_GC_Track(self); + } + + return (PyObject *)self; +} + diff --git a/source/blender/python/mathutils/mathutils_Quaternion.h b/source/blender/python/mathutils/mathutils_Quaternion.h new file mode 100644 index 00000000000..d606621390a --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Quaternion.h @@ -0,0 +1,55 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/python/generic/mathutils_Quaternion.h + * \ingroup pygen + */ + + +#ifndef MATHUTILS_QUAT_H +#define MATHUTILS_QUAT_H + +extern PyTypeObject quaternion_Type; +#define QuaternionObject_Check(_v) PyObject_TypeCheck((_v), &quaternion_Type) + +typedef struct { + BASE_MATH_MEMBERS(quat) +} QuaternionObject; + +/*struct data contains a pointer to the actual data that the +object uses. It can use either PyMem allocated data (which will +be stored in py_data) or be a wrapper for data allocated through +blender (stored in blend_data). This is an either/or struct not both*/ + +//prototypes +PyObject *newQuaternionObject( float *quat, int type, PyTypeObject *base_type); +PyObject *newQuaternionObject_cb(PyObject *cb_user, int cb_type, int cb_subtype); + +#endif /* MATHUTILS_QUAT_H */ diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c new file mode 100644 index 00000000000..e2c958adaa5 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -0,0 +1,2410 @@ +/* + * $Id$ + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * + * Contributor(s): Willian P. Germano, Joseph Gilbert, Ken Hughes, Alex Fraser, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils_Vector.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils.h" + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#define MAX_DIMENSIONS 4 + +/* Swizzle axes get packed into a single value that is used as a closure. Each + axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is + used as a sentinel: if it is unset, the axis is not valid. */ +#define SWIZZLE_BITS_PER_AXIS 3 +#define SWIZZLE_VALID_AXIS 0x4 +#define SWIZZLE_AXIS 0x3 + +static PyObject *Vector_copy(VectorObject *self); +static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits); + +/* 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 *UNUSED(kwds)) +{ + float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f}; + int size= 3; /* default to a 3D vector */ + + switch(PyTuple_GET_SIZE(args)) { + case 0: + break; + case 1: + if((size=mathutils_array_parse(vec, 2, 4, PyTuple_GET_ITEM(args, 0), "mathutils.Vector()")) == -1) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, + "mathutils.Vector(): " + "more then a single arg given"); + return NULL; + } + return newVectorObject(vec, size, Py_NEW, type); +} + +static PyObject *vec__apply_to_copy(PyNoArgsFunction vec_func, VectorObject *self) +{ + PyObject *ret= Vector_copy(self); + PyObject *ret_dummy= vec_func(ret); + if(ret_dummy) { + Py_DECREF(ret_dummy); + return (PyObject *)ret; + } + else { /* error */ + Py_DECREF(ret); + return NULL; + } +} + +/*-----------------------------METHODS---------------------------- */ +PyDoc_STRVAR(Vector_zero_doc, +".. method:: zero()\n" +"\n" +" Set all values to zero.\n" +); +static PyObject *Vector_zero(VectorObject *self) +{ + fill_vn(self->vec, self->size, 0.0f); + + if(BaseMath_WriteCallback(self) == -1) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Vector_normalize_doc, +".. method:: normalize()\n" +"\n" +" Normalize the vector, making the length of the vector always 1.0.\n" +"\n" +" .. warning:: Normalizing a vector where all values are zero results\n" +" in all axis having a nan value (not a number).\n" +"\n" +" .. note:: Normalize works for vectors of all sizes,\n" +" however 4D Vectors w axis is left untouched.\n" +); +static PyObject *Vector_normalize(VectorObject *self) +{ + int i; + float norm = 0.0f; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + for(i = 0; i < self->size; i++) { + norm += self->vec[i] * self->vec[i]; + } + norm = (float) sqrt(norm); + for(i = 0; i < self->size; i++) { + self->vec[i] /= norm; + } + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} +PyDoc_STRVAR(Vector_normalized_doc, +".. method:: normalized()\n" +"\n" +" Return a new, normalized vector.\n" +"\n" +" :return: a normalized copy of the vector\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_normalized(VectorObject *self) +{ + return vec__apply_to_copy((PyNoArgsFunction)Vector_normalize, self); +} + +PyDoc_STRVAR(Vector_resize_2d_doc, +".. method:: resize_2d()\n" +"\n" +" Resize the vector to 2D (x, y).\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_resize_2d(VectorObject *self) +{ + if(self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_2d(): " + "cannot resize wrapped data - only python vectors"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_2d(): " + "cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, + "vector.resize_2d(): " + "problem allocating pointer space"); + return NULL; + } + + self->size = 2; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Vector_resize_3d_doc, +".. method:: resize_3d()\n" +"\n" +" Resize the vector to 3D (x, y, z).\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_resize_3d(VectorObject *self) +{ + if (self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_3d(): " + "cannot resize wrapped data - only python vectors"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_3d(): " + "cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, + "vector.resize_3d(): " + "problem allocating pointer space"); + return NULL; + } + + if(self->size == 2) + self->vec[2] = 0.0f; + + self->size = 3; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Vector_resize_4d_doc, +".. method:: resize_4d()\n" +"\n" +" Resize the vector to 4D (x, y, z, w).\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_resize_4d(VectorObject *self) +{ + if(self->wrapped==Py_WRAP) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_4d(): " + "cannot resize wrapped data - only python vectors"); + return NULL; + } + if(self->cb_user) { + PyErr_SetString(PyExc_TypeError, + "vector.resize_4d(): " + "cannot resize a vector that has an owner"); + return NULL; + } + + self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4)); + if(self->vec == NULL) { + PyErr_SetString(PyExc_MemoryError, + "vector.resize_4d(): " + "problem allocating pointer space"); + return NULL; + } + + if(self->size == 2){ + self->vec[2] = 0.0f; + self->vec[3] = 1.0f; + } + else if(self->size == 3){ + self->vec[3] = 1.0f; + } + self->size = 4; + Py_RETURN_NONE; +} +PyDoc_STRVAR(Vector_to_2d_doc, +".. method:: to_2d()\n" +"\n" +" Return a 2d copy of the vector.\n" +"\n" +" :return: a new vector\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_to_2d(VectorObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return newVectorObject(self->vec, 2, Py_NEW, Py_TYPE(self)); +} +PyDoc_STRVAR(Vector_to_3d_doc, +".. method:: to_3d()\n" +"\n" +" Return a 3d copy of the vector.\n" +"\n" +" :return: a new vector\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_to_3d(VectorObject *self) +{ + float tvec[3]= {0.0f}; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 3)); + return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(self)); +} +PyDoc_STRVAR(Vector_to_4d_doc, +".. method:: to_4d()\n" +"\n" +" Return a 4d copy of the vector.\n" +"\n" +" :return: a new vector\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_to_4d(VectorObject *self) +{ + float tvec[4]= {0.0f, 0.0f, 0.0f, 1.0f}; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 4)); + return newVectorObject(tvec, 4, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Vector_to_tuple_doc, +".. method:: to_tuple(precision=-1)\n" +"\n" +" Return this vector as a tuple with.\n" +"\n" +" :arg precision: The number to round the value to in [-1, 21].\n" +" :type precision: int\n" +" :return: the values of the vector rounded by *precision*\n" +" :rtype: tuple\n" +); +/* note: BaseMath_ReadCallback must be called beforehand */ +static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits) +{ + PyObject *ret; + int i; + + ret= PyTuple_New(self->size); + + if(ndigits >= 0) { + for(i = 0; i < self->size; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(double_round((double)self->vec[i], ndigits))); + } + } + else { + for(i = 0; i < self->size; i++) { + PyTuple_SET_ITEM(ret, i, PyFloat_FromDouble(self->vec[i])); + } + } + + return ret; +} + +static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args) +{ + int ndigits= 0; + + if(!PyArg_ParseTuple(args, "|i:to_tuple", &ndigits)) + return NULL; + + if(ndigits > 22 || ndigits < 0) { + PyErr_SetString(PyExc_ValueError, + "vector.to_tuple(ndigits): " + "ndigits must be between 0 and 21"); + return NULL; + } + + if(PyTuple_GET_SIZE(args)==0) + ndigits= -1; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return Vector_to_tuple_ext(self, ndigits); +} + +PyDoc_STRVAR(Vector_to_track_quat_doc, +".. method:: to_track_quat(track, up)\n" +"\n" +" Return a quaternion rotation from the vector and the track and up axis.\n" +"\n" +" :arg track: Track axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z'].\n" +" :type track: string\n" +" :arg up: Up axis in ['X', 'Y', 'Z'].\n" +" :type up: string\n" +" :return: rotation from the vector and the track and up axis.\n" +" :rtype: :class:`Quaternion`\n" +); +static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args) +{ + float vec[3], quat[4]; + const char *strack, *sup; + short track = 2, up = 1; + + if(!PyArg_ParseTuple(args, "|ss:to_track_quat", &strack, &sup)) + return NULL; + + if (self->size != 3) { + PyErr_SetString(PyExc_TypeError, + "vector.to_track_quat(): " + "only for 3D vectors"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if (strack) { + const char *axis_err_msg= "only X, -X, Y, -Y, Z or -Z for track axis"; + + if (strlen(strack) == 2) { + if (strack[0] == '-') { + switch(strack[1]) { + case 'X': + track = 3; + break; + case 'Y': + track = 4; + break; + case 'Z': + track = 5; + break; + default: + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + else { + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + else if (strlen(strack) == 1) { + switch(strack[0]) { + case '-': + case 'X': + track = 0; + break; + case 'Y': + track = 1; + break; + case 'Z': + track = 2; + break; + default: + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + else { + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + + if (sup) { + const char *axis_err_msg= "only X, Y or Z for up axis"; + if (strlen(sup) == 1) { + switch(*sup) { + case 'X': + up = 0; + break; + case 'Y': + up = 1; + break; + case 'Z': + up = 2; + break; + default: + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + else { + PyErr_SetString(PyExc_ValueError, axis_err_msg); + return NULL; + } + } + + if (track == up) { + PyErr_SetString(PyExc_ValueError, + "Can't have the same axis for track and up"); + return NULL; + } + + /* + flip vector around, since vectoquat expect a vector from target to tracking object + and the python function expects the inverse (a vector to the target). + */ + negate_v3_v3(vec, self->vec); + + vec_to_quat(quat, vec, track, up); + + return newQuaternionObject(quat, Py_NEW, NULL); +} + +/* + * Vector.reflect(mirror): return a reflected vector on the mirror normal + * vec - ((2 * DotVecs(vec, mirror)) * mirror) + */ +PyDoc_STRVAR(Vector_reflect_doc, +".. method:: reflect(mirror)\n" +"\n" +" Return the reflection vector from the *mirror* argument.\n" +"\n" +" :arg mirror: This vector could be a normal from the reflecting surface.\n" +" :type mirror: :class:`Vector`\n" +" :return: The reflected vector matching the size of this vector.\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_reflect(VectorObject *self, PyObject *value) +{ + int value_size; + float mirror[3], vec[3]; + float reflect[3] = {0.0f}; + float tvec[MAX_DIMENSIONS]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if((value_size= mathutils_array_parse(tvec, 2, 4, value, "vector.reflect(other), invalid 'other' arg")) == -1) + return NULL; + + mirror[0] = tvec[0]; + mirror[1] = tvec[1]; + if (value_size > 2) mirror[2] = tvec[2]; + else mirror[2] = 0.0; + + vec[0] = self->vec[0]; + vec[1] = self->vec[1]; + if (self->size > 2) vec[2] = self->vec[2]; + else vec[2] = 0.0; + + normalize_v3(mirror); + reflect_v3_v3v3(reflect, vec, mirror); + + return newVectorObject(reflect, self->size, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Vector_cross_doc, +".. method:: cross(other)\n" +"\n" +" Return the cross product of this vector and another.\n" +"\n" +" :arg other: The other vector to perform the cross product with.\n" +" :type other: :class:`Vector`\n" +" :return: The cross product.\n" +" :rtype: :class:`Vector`\n" +"\n" +" .. note:: both vectors must be 3D\n" +); +static PyObject *Vector_cross(VectorObject *self, PyObject *value) +{ + VectorObject *ret; + float tvec[MAX_DIMENSIONS]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tvec, self->size, self->size, value, "vector.cross(other), invalid 'other' arg") == -1) + return NULL; + + ret= (VectorObject *)newVectorObject(NULL, 3, Py_NEW, Py_TYPE(self)); + cross_v3_v3v3(ret->vec, self->vec, tvec); + return (PyObject *)ret; +} + +PyDoc_STRVAR(Vector_dot_doc, +".. method:: dot(other)\n" +"\n" +" Return the dot product of this vector and another.\n" +"\n" +" :arg other: The other vector to perform the dot product with.\n" +" :type other: :class:`Vector`\n" +" :return: The dot product.\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_dot(VectorObject *self, PyObject *value) +{ + float tvec[MAX_DIMENSIONS]; + double dot = 0.0; + int x; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tvec, self->size, self->size, value, "vector.dot(other), invalid 'other' arg") == -1) + return NULL; + + for(x = 0; x < self->size; x++) { + dot += (double)(self->vec[x] * tvec[x]); + } + + return PyFloat_FromDouble(dot); +} + +PyDoc_STRVAR(Vector_angle_doc, +".. function:: angle(other, fallback)\n" +"\n" +" Return the angle between two vectors.\n" +"\n" +" :arg other: another vector to compare the angle with\n" +" :type other: :class:`Vector`\n" +" :arg fallback: return this value when the angle cant be calculated\n" +" (zero length vector)\n" +" :type fallback: any\n" +" :return: angle in radians or fallback when given\n" +" :rtype: float\n" +"\n" +" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n" +); +static PyObject *Vector_angle(VectorObject *self, PyObject *args) +{ + const int size= self->size; + float tvec[MAX_DIMENSIONS]; + PyObject *value; + double dot = 0.0f, test_v1 = 0.0f, test_v2 = 0.0f; + int x; + PyObject *fallback= NULL; + + if(!PyArg_ParseTuple(args, "O|O:angle", &value, &fallback)) + return NULL; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tvec, size, size, value, "vector.angle(other), invalid 'other' arg") == -1) + return NULL; + + for(x = 0; x < size; x++) { + test_v1 += (double)(self->vec[x] * self->vec[x]); + test_v2 += (double)(tvec[x] * tvec[x]); + } + if (!test_v1 || !test_v2){ + /* avoid exception */ + if(fallback) { + Py_INCREF(fallback); + return fallback; + } + else { + PyErr_SetString(PyExc_ValueError, + "vector.angle(other): " + "zero length vectors have no valid angle"); + return NULL; + } + } + + //dot product + for(x = 0; x < self->size; x++) { + dot += (double)(self->vec[x] * tvec[x]); + } + dot /= (sqrt(test_v1) * sqrt(test_v2)); + + return PyFloat_FromDouble(saacos(dot)); +} + +PyDoc_STRVAR(Vector_rotation_difference_doc, +".. function:: difference(other)\n" +"\n" +" Returns a quaternion representing the rotational difference between this\n" +" vector and another.\n" +"\n" +" :arg other: second vector.\n" +" :type other: :class:`Vector`\n" +" :return: the rotational difference between the two vectors.\n" +" :rtype: :class:`Quaternion`\n" +"\n" +" .. note:: 2D vectors raise an :exc:`AttributeError`.\n" +); +static PyObject *Vector_rotation_difference(VectorObject *self, PyObject *value) +{ + float quat[4], vec_a[3], vec_b[3]; + + if(self->size < 3) { + PyErr_SetString(PyExc_ValueError, + "vec.difference(value): " + "expects both vectors to be size 3 or 4"); + return NULL; + } + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(vec_b, 3, MAX_DIMENSIONS, value, "vector.difference(other), invalid 'other' arg") == -1) + return NULL; + + normalize_v3_v3(vec_a, self->vec); + normalize_v3(vec_b); + + rotation_between_vecs_to_quat(quat, vec_a, vec_b); + + return newQuaternionObject(quat, Py_NEW, NULL); +} + +PyDoc_STRVAR(Vector_project_doc, +".. function:: project(other)\n" +"\n" +" Return the projection of this vector onto the *other*.\n" +"\n" +" :arg other: second vector.\n" +" :type other: :class:`Vector`\n" +" :return: the parallel projection vector\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_project(VectorObject *self, PyObject *value) +{ + const int size= self->size; + float tvec[MAX_DIMENSIONS]; + float vec[MAX_DIMENSIONS]; + double dot = 0.0f, dot2 = 0.0f; + int x; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_array_parse(tvec, size, size, value, "vector.project(other), invalid 'other' arg") == -1) + return NULL; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + //get dot products + for(x = 0; x < size; x++) { + dot += (double)(self->vec[x] * tvec[x]); + dot2 += (double)(tvec[x] * tvec[x]); + } + //projection + dot /= dot2; + for(x = 0; x < size; x++) { + vec[x] = (float)dot * tvec[x]; + } + return newVectorObject(vec, size, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Vector_lerp_doc, +".. function:: lerp(other, factor)\n" +"\n" +" Returns the interpolation of two vectors.\n" +"\n" +" :arg other: value to interpolate with.\n" +" :type other: :class:`Vector`\n" +" :arg factor: The interpolation value in [0.0, 1.0].\n" +" :type factor: float\n" +" :return: The interpolated rotation.\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_lerp(VectorObject *self, PyObject *args) +{ + const int size= self->size; + PyObject *value= NULL; + float fac, ifac; + float tvec[MAX_DIMENSIONS], vec[MAX_DIMENSIONS]; + int x; + + if(!PyArg_ParseTuple(args, "Of:lerp", &value, &fac)) + return NULL; + + if(mathutils_array_parse(tvec, size, size, value, "vector.lerp(other), invalid 'other' arg") == -1) + return NULL; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + ifac= 1.0f - fac; + + for(x = 0; x < size; x++) { + vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]); + } + return newVectorObject(vec, size, Py_NEW, Py_TYPE(self)); +} + +PyDoc_STRVAR(Vector_rotate_doc, +".. function:: rotate(other)\n" +"\n" +" Return vector by a rotation value.\n" +"\n" +" :arg other: rotation component of mathutils value\n" +" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n" +); +static PyObject *Vector_rotate(VectorObject *self, PyObject *value) +{ + float other_rmat[3][3]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + if(mathutils_any_to_rotmat(other_rmat, value, "vector.rotate(value)") == -1) + return NULL; + + if(self->size < 3) { + PyErr_SetString(PyExc_ValueError, + "Vector must be 3D or 4D"); + return NULL; + } + + mul_m3_v3(other_rmat, self->vec); + + (void)BaseMath_WriteCallback(self); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Vector_copy_doc, +".. function:: copy()\n" +"\n" +" Returns a copy of this vector.\n" +"\n" +" :return: A copy of the vector.\n" +" :rtype: :class:`Vector`\n" +"\n" +" .. note:: use this to get a copy of a wrapped vector with\n" +" no reference to the original data.\n" +); +static PyObject *Vector_copy(VectorObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self)); +} + +static PyObject *Vector_repr(VectorObject *self) +{ + PyObject *ret, *tuple; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + tuple= Vector_to_tuple_ext(self, -1); + ret= PyUnicode_FromFormat("Vector(%R)", tuple); + Py_DECREF(tuple); + return ret; +} + +/* Sequence Protocol */ +/* sequence length len(vector) */ +static int Vector_len(VectorObject *self) +{ + return self->size; +} +/* sequence accessor (get): vector[index] */ +static PyObject *vector_item_internal(VectorObject *self, int i, const int is_attr) +{ + if(i<0) i= self->size-i; + + if(i < 0 || i >= self->size) { + if(is_attr) { + PyErr_Format(PyExc_AttributeError, + "vector.%c: unavailable on %dd vector", + *(((char *)"xyzw") + i), self->size); + } + else { + PyErr_SetString(PyExc_IndexError, + "vector[index]: out of range"); + } + return NULL; + } + + if(BaseMath_ReadIndexCallback(self, i) == -1) + return NULL; + + return PyFloat_FromDouble(self->vec[i]); +} + +static PyObject *Vector_item(VectorObject *self, int i) +{ + return vector_item_internal(self, i, FALSE); +} +/* sequence accessor (set): vector[index] = value */ +static int vector_ass_item_internal(VectorObject *self, int i, PyObject *value, const int is_attr) +{ + float scalar; + if((scalar=PyFloat_AsDouble(value))==-1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, + "vector[index] = x: " + "index argument not a number"); + return -1; + } + + if(i<0) i= self->size-i; + + if(i < 0 || i >= self->size){ + if(is_attr) { + PyErr_Format(PyExc_AttributeError, + "vector.%c = x: unavailable on %dd vector", + *(((char *)"xyzw") + i), self->size); + } + else { + PyErr_SetString(PyExc_IndexError, + "vector[index] = x: " + "assignment index out of range"); + } + return -1; + } + self->vec[i] = scalar; + + if(BaseMath_WriteIndexCallback(self, i) == -1) + return -1; + return 0; +} + +static int Vector_ass_item(VectorObject *self, int i, PyObject *value) +{ + return vector_ass_item_internal(self, i, value, FALSE); +} + +/* sequence slice (get): vector[a:b] */ +static PyObject *Vector_slice(VectorObject *self, int begin, int end) +{ + PyObject *tuple; + int count; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + CLAMP(begin, 0, self->size); + if (end<0) end= self->size+end+1; + CLAMP(end, 0, self->size); + begin= MIN2(begin, end); + + tuple= PyTuple_New(end - begin); + for(count = begin; count < end; count++) { + PyTuple_SET_ITEM(tuple, count - begin, PyFloat_FromDouble(self->vec[count])); + } + + return tuple; +} +/* sequence slice (set): vector[a:b] = value */ +static int Vector_ass_slice(VectorObject *self, int begin, int end, PyObject *seq) +{ + int y, size = 0; + float vec[MAX_DIMENSIONS]; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + CLAMP(begin, 0, self->size); + CLAMP(end, 0, self->size); + begin = MIN2(begin, end); + + size = (end - begin); + if(mathutils_array_parse(vec, size, size, seq, "vector[begin:end] = [...]") == -1) + return -1; + + /*parsed well - now set in vector*/ + for(y = 0; y < size; y++){ + self->vec[begin + y] = vec[y]; + } + + if(BaseMath_WriteCallback(self) == -1) + return -1; + + return 0; +} + +/* Numeric Protocols */ +/* addition: obj + obj */ +static PyObject *Vector_add(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[MAX_DIMENSIONS]; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, + "Vector addition: " + "arguments not valid for this operation"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + return NULL; + + /*VECTOR + VECTOR*/ + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, + "Vector addition: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + add_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size); + + return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1)); +} + +/* addition in-place: obj += obj */ +static PyObject *Vector_iadd(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, + "Vector addition: " + "arguments not valid for this operation"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, + "Vector addition: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + return NULL; + + add_vn_vn(vec1->vec, vec2->vec, vec1->size); + + (void)BaseMath_WriteCallback(vec1); + Py_INCREF(v1); + return v1; +} + +/* subtraction: obj - obj */ +static PyObject *Vector_sub(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float vec[MAX_DIMENSIONS]; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, + "Vector subtraction: " + "arguments not valid for this operation"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + return NULL; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, + "Vector subtraction: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + sub_vn_vnvn(vec, vec1->vec, vec2->vec, vec1->size); + + return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1)); +} + +/* subtraction in-place: obj -= obj */ +static PyObject *Vector_isub(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1= NULL, *vec2= NULL; + + if (!VectorObject_Check(v1) || !VectorObject_Check(v2)) { + PyErr_SetString(PyExc_AttributeError, + "Vector subtraction: " + "arguments not valid for this operation"); + return NULL; + } + vec1 = (VectorObject*)v1; + vec2 = (VectorObject*)v2; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_AttributeError, + "Vector subtraction: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1) + return NULL; + + sub_vn_vn(vec1->vec, vec2->vec, vec1->size); + + (void)BaseMath_WriteCallback(vec1); + Py_INCREF(v1); + return v1; +} + +/*------------------------obj * obj------------------------------ + mulplication*/ + + +/* COLUMN VECTOR Multiplication (Vector X Matrix) + * [a] * [1][4][7] + * [b] * [2][5][8] + * [c] * [3][6][9] + * + * note: vector/matrix multiplication IS NOT COMMUTATIVE!!!! + * note: assume read callbacks have been done first. + */ +static int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject* vec, MatrixObject * mat) +{ + float vec_cpy[MAX_DIMENSIONS]; + double dot = 0.0f; + int x, y, z = 0; + + if(mat->row_size != vec->size){ + if(mat->row_size == 4 && vec->size == 3) { + vec_cpy[3] = 1.0f; + } + else { + PyErr_SetString(PyExc_TypeError, + "matrix * vector: " + "matrix.row_size and len(vector) must be the same, " + "except for 3D vector * 4x4 matrix."); + return -1; + } + } + + memcpy(vec_cpy, vec->vec, vec->size * sizeof(float)); + + rvec[3] = 1.0f; + + for(x = 0; x < mat->col_size; x++) { + for(y = 0; y < mat->row_size; y++) { + dot += (double)(mat->matrix[y][x] * vec_cpy[y]); + } + rvec[z++] = (float)dot; + dot = 0.0f; + } + + return 0; +} + +static PyObject *vector_mul_float(VectorObject *vec, const float scalar) +{ + float tvec[MAX_DIMENSIONS]; + mul_vn_vn_fl(tvec, vec->vec, vec->size, scalar); + return newVectorObject(tvec, vec->size, Py_NEW, Py_TYPE(vec)); +} + +static PyObject *Vector_mul(PyObject *v1, PyObject *v2) +{ + VectorObject *vec1 = NULL, *vec2 = NULL; + float scalar; + + if VectorObject_Check(v1) { + vec1= (VectorObject *)v1; + if(BaseMath_ReadCallback(vec1) == -1) + return NULL; + } + if VectorObject_Check(v2) { + vec2= (VectorObject *)v2; + if(BaseMath_ReadCallback(vec2) == -1) + return NULL; + } + + + /* make sure v1 is always the vector */ + if (vec1 && vec2) { + int i; + double dot = 0.0f; + + if(vec1->size != vec2->size) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "vectors must have the same dimensions for this operation"); + return NULL; + } + + /*dot product*/ + for(i = 0; i < vec1->size; i++) { + dot += (double)(vec1->vec[i] * vec2->vec[i]); + } + return PyFloat_FromDouble(dot); + } + else if (vec1) { + if (MatrixObject_Check(v2)) { + /* VEC * MATRIX */ + float tvec[MAX_DIMENSIONS]; + if(BaseMath_ReadCallback((MatrixObject *)v2) == -1) + return NULL; + if(column_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) { + return NULL; + } + + return newVectorObject(tvec, vec1->size, Py_NEW, Py_TYPE(vec1)); + } + else if (QuaternionObject_Check(v2)) { + /* VEC * QUAT */ + QuaternionObject *quat2 = (QuaternionObject*)v2; + float tvec[3]; + + if(vec1->size != 3) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "only 3D vector rotations (with quats) currently supported"); + return NULL; + } + if(BaseMath_ReadCallback(quat2) == -1) { + return NULL; + } + copy_v3_v3(tvec, vec1->vec); + mul_qt_v3(quat2->quat, tvec); + return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec1)); + } + else if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* VEC * FLOAT */ + return vector_mul_float(vec1, scalar); + } + } + else if (vec2) { + if (((scalar= PyFloat_AsDouble(v1)) == -1.0f && PyErr_Occurred())==0) { /* FLOAT * VEC */ + return vector_mul_float(vec2, scalar); + } + } + else { + BLI_assert(!"internal error"); + } + + PyErr_Format(PyExc_TypeError, + "Vector multiplication: " + "not supported between '%.200s' and '%.200s' types", + Py_TYPE(v1)->tp_name, Py_TYPE(v2)->tp_name); + return NULL; +} + +/* mulplication in-place: obj *= obj */ +static PyObject *Vector_imul(PyObject *v1, PyObject *v2) +{ + VectorObject *vec = (VectorObject *)v1; + float scalar; + + if(BaseMath_ReadCallback(vec) == -1) + return NULL; + + /* only support vec*=float and vec*=mat + vec*=vec result is a float so that wont work */ + if (MatrixObject_Check(v2)) { + float rvec[MAX_DIMENSIONS]; + if(BaseMath_ReadCallback((MatrixObject *)v2) == -1) + return NULL; + + if(column_vector_multiplication(rvec, vec, (MatrixObject*)v2) == -1) + return NULL; + + memcpy(vec->vec, rvec, sizeof(float) * vec->size); + } + else if (QuaternionObject_Check(v2)) { + /* VEC *= QUAT */ + QuaternionObject *quat2 = (QuaternionObject*)v2; + + if(vec->size != 3) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "only 3D vector rotations (with quats) currently supported"); + return NULL; + } + + if(BaseMath_ReadCallback(quat2) == -1) { + return NULL; + } + mul_qt_v3(quat2->quat, vec->vec); + } + else if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* VEC *= FLOAT */ + mul_vn_fl(vec->vec, vec->size, scalar); + } + else { + PyErr_SetString(PyExc_TypeError, + "Vector multiplication: " + "arguments not acceptable for this operation"); + return NULL; + } + + (void)BaseMath_WriteCallback(vec); + Py_INCREF(v1); + return v1; +} + +/* divid: obj / obj */ +static PyObject *Vector_div(PyObject *v1, PyObject *v2) +{ + int i; + float vec[4], scalar; + VectorObject *vec1 = NULL; + + if(!VectorObject_Check(v1)) { /* not a vector */ + PyErr_SetString(PyExc_TypeError, + "Vector division: " + "Vector must be divided by a float"); + return NULL; + } + vec1 = (VectorObject*)v1; /* vector */ + + if(BaseMath_ReadCallback(vec1) == -1) + return NULL; + + if((scalar=PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, + "Vector division: " + "Vector must be divided by a float"); + return NULL; + } + + if(scalar==0.0f) { + PyErr_SetString(PyExc_ZeroDivisionError, + "Vector division: " + "divide by zero error"); + return NULL; + } + + for(i = 0; i < vec1->size; i++) { + vec[i] = vec1->vec[i] / scalar; + } + return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1)); +} + +/* divide in-place: obj /= obj */ +static PyObject *Vector_idiv(PyObject *v1, PyObject *v2) +{ + int i; + float scalar; + VectorObject *vec1 = (VectorObject*)v1; + + if(BaseMath_ReadCallback(vec1) == -1) + return NULL; + + if((scalar=PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred()) { /* parsed item not a number */ + PyErr_SetString(PyExc_TypeError, + "Vector division: " + "Vector must be divided by a float"); + return NULL; + } + + if(scalar==0.0f) { + PyErr_SetString(PyExc_ZeroDivisionError, + "Vector division: " + "divide by zero error"); + return NULL; + } + for(i = 0; i < vec1->size; i++) { + vec1->vec[i] /= scalar; + } + + (void)BaseMath_WriteCallback(vec1); + + Py_INCREF(v1); + return v1; +} + +/* -obj + returns the negative of this object*/ +static PyObject *Vector_neg(VectorObject *self) +{ + float tvec[MAX_DIMENSIONS]; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + negate_vn_vn(tvec, self->vec, self->size); + return newVectorObject(tvec, self->size, Py_NEW, Py_TYPE(self)); +} + +/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */ +static double vec_magnitude_nosqrt(float *data, int size) +{ + double dot = 0.0f; + int i; + + for(i=0; i<size; i++){ + dot += (double)data[i]; + } + /*return (double)sqrt(dot);*/ + /* warning, line above removed because we are not using the length, + rather the comparing the sizes and for this we do not need the sqrt + for the actual length, the dot must be sqrt'd */ + return dot; +} + + +/*------------------------tp_richcmpr + returns -1 execption, 0 false, 1 true */ +static PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type) +{ + VectorObject *vecA = NULL, *vecB = NULL; + int result = 0; + double epsilon = .000001f; + double lenA, lenB; + + if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } + } + vecA = (VectorObject*)objectA; + vecB = (VectorObject*)objectB; + + if(BaseMath_ReadCallback(vecA) == -1 || BaseMath_ReadCallback(vecB) == -1) + return NULL; + + if (vecA->size != vecB->size){ + if (comparison_type == Py_NE){ + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } + } + + switch (comparison_type){ + case Py_LT: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if(lenA < lenB){ + result = 1; + } + break; + case Py_LE: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if(lenA < lenB){ + result = 1; + } + else { + result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); + } + break; + case Py_EQ: + result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); + break; + case Py_NE: + result = !EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1); + break; + case Py_GT: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if(lenA > lenB){ + result = 1; + } + break; + case Py_GE: + lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size); + lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size); + if(lenA > lenB){ + result = 1; + } + else { + result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB)); + } + break; + default: + printf("The result of the comparison could not be evaluated"); + break; + } + if (result == 1){ + Py_RETURN_TRUE; + } + else { + Py_RETURN_FALSE; + } +} + +/*-----------------PROTCOL DECLARATIONS--------------------------*/ +static PySequenceMethods Vector_SeqMethods = { + (lenfunc) Vector_len, /* sq_length */ + (binaryfunc) NULL, /* sq_concat */ + (ssizeargfunc) NULL, /* sq_repeat */ + (ssizeargfunc) Vector_item, /* sq_item */ + NULL, /* py3 deprecated slice func */ + (ssizeobjargproc) Vector_ass_item, /* sq_ass_item */ + NULL, /* py3 deprecated slice assign func */ + (objobjproc) NULL, /* sq_contains */ + (binaryfunc) NULL, /* sq_inplace_concat */ + (ssizeargfunc) NULL, /* sq_inplace_repeat */ +}; + +static PyObject *Vector_subscript(VectorObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->size; + return Vector_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, self->size, &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Vector_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with vectors"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + +static int Vector_ass_subscript(VectorObject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->size; + return Vector_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, self->size, &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Vector_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with vectors"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "vector indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + +static PyMappingMethods Vector_AsMapping = { + (lenfunc)Vector_len, + (binaryfunc)Vector_subscript, + (objobjargproc)Vector_ass_subscript +}; + + +static PyNumberMethods Vector_NumMethods = { + (binaryfunc) Vector_add, /*nb_add*/ + (binaryfunc) Vector_sub, /*nb_subtract*/ + (binaryfunc) Vector_mul, /*nb_multiply*/ + NULL, /*nb_remainder*/ + NULL, /*nb_divmod*/ + NULL, /*nb_power*/ + (unaryfunc) Vector_neg, /*nb_negative*/ + (unaryfunc) NULL, /*tp_positive*/ + (unaryfunc) NULL, /*tp_absolute*/ + (inquiry) NULL, /*tp_bool*/ + (unaryfunc) NULL, /*nb_invert*/ + NULL, /*nb_lshift*/ + (binaryfunc)NULL, /*nb_rshift*/ + NULL, /*nb_and*/ + NULL, /*nb_xor*/ + NULL, /*nb_or*/ + NULL, /*nb_int*/ + NULL, /*nb_reserved*/ + NULL, /*nb_float*/ + Vector_iadd, /* nb_inplace_add */ + Vector_isub, /* nb_inplace_subtract */ + Vector_imul, /* nb_inplace_multiply */ + NULL, /* nb_inplace_remainder */ + NULL, /* nb_inplace_power */ + NULL, /* nb_inplace_lshift */ + NULL, /* nb_inplace_rshift */ + NULL, /* nb_inplace_and */ + NULL, /* nb_inplace_xor */ + NULL, /* nb_inplace_or */ + NULL, /* nb_floor_divide */ + Vector_div, /* nb_true_divide */ + NULL, /* nb_inplace_floor_divide */ + Vector_idiv, /* nb_inplace_true_divide */ + NULL, /* nb_index */ +}; + +/*------------------PY_OBECT DEFINITION--------------------------*/ + +/* + * vector axis, vector.x/y/z/w + */ + +static PyObject *Vector_getAxis(VectorObject *self, void *type) +{ + return vector_item_internal(self, GET_INT_FROM_POINTER(type), TRUE); +} + +static int Vector_setAxis(VectorObject *self, PyObject *value, void *type) +{ + return vector_ass_item_internal(self, GET_INT_FROM_POINTER(type), value, TRUE); +} + +/* vector.length */ +static PyObject *Vector_getLength(VectorObject *self, void *UNUSED(closure)) +{ + double dot = 0.0f; + int i; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + for(i = 0; i < self->size; i++){ + dot += (double)(self->vec[i] * self->vec[i]); + } + return PyFloat_FromDouble(sqrt(dot)); +} + +static int Vector_setLength(VectorObject *self, PyObject *value) +{ + double dot = 0.0f, param; + int i; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + if((param=PyFloat_AsDouble(value)) == -1.0 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "length must be set to a number"); + return -1; + } + + if (param < 0.0) { + PyErr_SetString(PyExc_ValueError, + "cannot set a vectors length to a negative value"); + return -1; + } + if (param == 0.0) { + fill_vn(self->vec, self->size, 0.0f); + return 0; + } + + for(i = 0; i < self->size; i++){ + dot += (double)(self->vec[i] * self->vec[i]); + } + + if (!dot) /* cant sqrt zero */ + return 0; + + dot = sqrt(dot); + + if (dot==param) + return 0; + + dot= dot/param; + + for(i = 0; i < self->size; i++){ + self->vec[i]= self->vec[i] / (float)dot; + } + + (void)BaseMath_WriteCallback(self); /* checked already */ + + return 0; +} + +/* 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. */ +static PyObject *Vector_getSwizzle(VectorObject *self, void *closure) +{ + size_t axis_to; + size_t axis_from; + float vec[MAX_DIMENSIONS]; + unsigned int swizzleClosure; + + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + /* Unpack the axes from the closure into an array. */ + axis_to = 0; + swizzleClosure = GET_INT_FROM_POINTER(closure); + while (swizzleClosure & SWIZZLE_VALID_AXIS) + { + axis_from = swizzleClosure & SWIZZLE_AXIS; + if(axis_from >= self->size) { + PyErr_SetString(PyExc_AttributeError, + "Vector swizzle: " + "specified axis not present"); + return NULL; + } + + vec[axis_to] = self->vec[axis_from]; + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axis_to++; + } + + return newVectorObject(vec, axis_to, Py_NEW, Py_TYPE(self)); +} + +/* 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. + - If the value is scalar, it is copied to all axes listed in the swizzle. + - 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. */ +static int Vector_setSwizzle(VectorObject *self, PyObject *value, void *closure) +{ + size_t size_from; + float scalarVal; + + size_t axis_from; + size_t axis_to; + + unsigned int swizzleClosure; + + float tvec[MAX_DIMENSIONS]; + float vec_assign[MAX_DIMENSIONS]; + + if(BaseMath_ReadCallback(self) == -1) + return -1; + + /* Check that the closure can be used with this vector: even 2D vectors have + swizzles defined for axes z and w, but they would be invalid. */ + swizzleClosure = GET_INT_FROM_POINTER(closure); + axis_from= 0; + while (swizzleClosure & SWIZZLE_VALID_AXIS) { + axis_to = swizzleClosure & SWIZZLE_AXIS; + if (axis_to >= self->size) + { + PyErr_SetString(PyExc_AttributeError, + "Vector swizzle: " + "specified axis not present"); + return -1; + } + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axis_from++; + } + + if (((scalarVal=PyFloat_AsDouble(value)) == -1 && PyErr_Occurred())==0) { + int i; + for(i=0; i < MAX_DIMENSIONS; i++) + vec_assign[i]= scalarVal; + + size_from= axis_from; + } + else if(PyErr_Clear(), (size_from=mathutils_array_parse(vec_assign, 2, 4, value, "mathutils.Vector.**** = swizzle assignment")) == -1) { + return -1; + } + + if(axis_from != size_from) { + PyErr_SetString(PyExc_AttributeError, + "Vector swizzle: size does not match swizzle"); + return -1; + } + + /* Copy vector contents onto swizzled axes. */ + axis_from = 0; + swizzleClosure = GET_INT_FROM_POINTER(closure); + while (swizzleClosure & SWIZZLE_VALID_AXIS) + { + axis_to = swizzleClosure & SWIZZLE_AXIS; + tvec[axis_to] = vec_assign[axis_from]; + swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS; + axis_from++; + } + + memcpy(self->vec, tvec, axis_from * sizeof(float)); + /* continue with BaseMathObject_WriteCallback at the end */ + + if(BaseMath_WriteCallback(self) == -1) + return -1; + else + return 0; +} + +/*****************************************************************************/ +/* Python attributes get/set structure: */ +/*****************************************************************************/ +static PyGetSetDef Vector_getseters[] = { + {(char *)"x", (getter)Vector_getAxis, (setter)Vector_setAxis, (char *)"Vector X axis.\n\n:type: float", (void *)0}, + {(char *)"y", (getter)Vector_getAxis, (setter)Vector_setAxis, (char *)"Vector Y axis.\n\n:type: float", (void *)1}, + {(char *)"z", (getter)Vector_getAxis, (setter)Vector_setAxis, (char *)"Vector Z axis (3D Vectors only).\n\n:type: float", (void *)2}, + {(char *)"w", (getter)Vector_getAxis, (setter)Vector_setAxis, (char *)"Vector W axis (4D Vectors only).\n\n:type: float", (void *)3}, + {(char *)"length", (getter)Vector_getLength, (setter)Vector_setLength, (char *)"Vector Length.\n\n:type: float", NULL}, + {(char *)"magnitude", (getter)Vector_getLength, (setter)Vector_setLength, (char *)"Vector Length.\n\n:type: float", NULL}, + {(char *)"is_wrapped", (getter)BaseMathObject_getWrapped, (setter)NULL, (char *)BaseMathObject_Wrapped_doc, NULL}, + {(char *)"owner", (getter)BaseMathObject_getOwner, (setter)NULL, (char *)BaseMathObject_Owner_doc, NULL}, + + /* autogenerated swizzle attrs, see python script below */ + {(char *)"xx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 36 + {(char *)"xxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 292 + {(char *)"xxxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2340 + {(char *)"xxxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2852 + {(char *)"xxxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3364 + {(char *)"xxxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3876 + {(char *)"xxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 356 + {(char *)"xxyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2404 + {(char *)"xxyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2916 + {(char *)"xxyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3428 + {(char *)"xxyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3940 + {(char *)"xxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 420 + {(char *)"xxzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2468 + {(char *)"xxzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2980 + {(char *)"xxzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3492 + {(char *)"xxzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4004 + {(char *)"xxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 484 + {(char *)"xxwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2532 + {(char *)"xxwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3044 + {(char *)"xxwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3556 + {(char *)"xxww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4068 + {(char *)"xy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 44 + {(char *)"xyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 300 + {(char *)"xyxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2348 + {(char *)"xyxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2860 + {(char *)"xyxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3372 + {(char *)"xyxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3884 + {(char *)"xyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 364 + {(char *)"xyyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2412 + {(char *)"xyyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2924 + {(char *)"xyyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3436 + {(char *)"xyyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3948 + {(char *)"xyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 428 + {(char *)"xyzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2476 + {(char *)"xyzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2988 + {(char *)"xyzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3500 + {(char *)"xyzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4012 + {(char *)"xyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 492 + {(char *)"xywx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2540 + {(char *)"xywy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3052 + {(char *)"xywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3564 + {(char *)"xyww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4076 + {(char *)"xz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 52 + {(char *)"xzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 308 + {(char *)"xzxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2356 + {(char *)"xzxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2868 + {(char *)"xzxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3380 + {(char *)"xzxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3892 + {(char *)"xzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 372 + {(char *)"xzyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2420 + {(char *)"xzyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2932 + {(char *)"xzyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3444 + {(char *)"xzyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3956 + {(char *)"xzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 436 + {(char *)"xzzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2484 + {(char *)"xzzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2996 + {(char *)"xzzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3508 + {(char *)"xzzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4020 + {(char *)"xzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 500 + {(char *)"xzwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2548 + {(char *)"xzwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3060 + {(char *)"xzwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3572 + {(char *)"xzww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4084 + {(char *)"xw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 60 + {(char *)"xwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 316 + {(char *)"xwxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2364 + {(char *)"xwxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2876 + {(char *)"xwxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3388 + {(char *)"xwxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3900 + {(char *)"xwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 380 + {(char *)"xwyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2428 + {(char *)"xwyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2940 + {(char *)"xwyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3452 + {(char *)"xwyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3964 + {(char *)"xwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 444 + {(char *)"xwzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2492 + {(char *)"xwzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3004 + {(char *)"xwzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3516 + {(char *)"xwzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4028 + {(char *)"xww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 508 + {(char *)"xwwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2556 + {(char *)"xwwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3068 + {(char *)"xwwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3580 + {(char *)"xwww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((0|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4092 + {(char *)"yx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 37 + {(char *)"yxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 293 + {(char *)"yxxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2341 + {(char *)"yxxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2853 + {(char *)"yxxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3365 + {(char *)"yxxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3877 + {(char *)"yxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 357 + {(char *)"yxyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2405 + {(char *)"yxyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2917 + {(char *)"yxyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3429 + {(char *)"yxyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3941 + {(char *)"yxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 421 + {(char *)"yxzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2469 + {(char *)"yxzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2981 + {(char *)"yxzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3493 + {(char *)"yxzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4005 + {(char *)"yxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 485 + {(char *)"yxwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2533 + {(char *)"yxwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3045 + {(char *)"yxwz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3557 + {(char *)"yxww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4069 + {(char *)"yy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 45 + {(char *)"yyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 301 + {(char *)"yyxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2349 + {(char *)"yyxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2861 + {(char *)"yyxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3373 + {(char *)"yyxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3885 + {(char *)"yyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 365 + {(char *)"yyyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2413 + {(char *)"yyyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2925 + {(char *)"yyyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3437 + {(char *)"yyyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3949 + {(char *)"yyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 429 + {(char *)"yyzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2477 + {(char *)"yyzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2989 + {(char *)"yyzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3501 + {(char *)"yyzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4013 + {(char *)"yyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 493 + {(char *)"yywx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2541 + {(char *)"yywy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3053 + {(char *)"yywz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3565 + {(char *)"yyww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4077 + {(char *)"yz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 53 + {(char *)"yzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 309 + {(char *)"yzxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2357 + {(char *)"yzxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2869 + {(char *)"yzxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3381 + {(char *)"yzxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3893 + {(char *)"yzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 373 + {(char *)"yzyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2421 + {(char *)"yzyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2933 + {(char *)"yzyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3445 + {(char *)"yzyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3957 + {(char *)"yzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 437 + {(char *)"yzzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2485 + {(char *)"yzzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2997 + {(char *)"yzzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3509 + {(char *)"yzzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4021 + {(char *)"yzw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 501 + {(char *)"yzwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2549 + {(char *)"yzwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3061 + {(char *)"yzwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3573 + {(char *)"yzww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4085 + {(char *)"yw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 61 + {(char *)"ywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 317 + {(char *)"ywxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2365 + {(char *)"ywxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2877 + {(char *)"ywxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3389 + {(char *)"ywxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3901 + {(char *)"ywy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 381 + {(char *)"ywyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2429 + {(char *)"ywyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2941 + {(char *)"ywyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3453 + {(char *)"ywyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3965 + {(char *)"ywz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 445 + {(char *)"ywzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2493 + {(char *)"ywzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3005 + {(char *)"ywzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3517 + {(char *)"ywzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4029 + {(char *)"yww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 509 + {(char *)"ywwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2557 + {(char *)"ywwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3069 + {(char *)"ywwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3581 + {(char *)"ywww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((1|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4093 + {(char *)"zx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 38 + {(char *)"zxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 294 + {(char *)"zxxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2342 + {(char *)"zxxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2854 + {(char *)"zxxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3366 + {(char *)"zxxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3878 + {(char *)"zxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 358 + {(char *)"zxyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2406 + {(char *)"zxyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2918 + {(char *)"zxyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3430 + {(char *)"zxyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3942 + {(char *)"zxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 422 + {(char *)"zxzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2470 + {(char *)"zxzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2982 + {(char *)"zxzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3494 + {(char *)"zxzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4006 + {(char *)"zxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 486 + {(char *)"zxwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2534 + {(char *)"zxwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3046 + {(char *)"zxwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3558 + {(char *)"zxww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4070 + {(char *)"zy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 46 + {(char *)"zyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 302 + {(char *)"zyxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2350 + {(char *)"zyxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2862 + {(char *)"zyxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3374 + {(char *)"zyxw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3886 + {(char *)"zyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 366 + {(char *)"zyyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2414 + {(char *)"zyyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2926 + {(char *)"zyyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3438 + {(char *)"zyyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3950 + {(char *)"zyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 430 + {(char *)"zyzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2478 + {(char *)"zyzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2990 + {(char *)"zyzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3502 + {(char *)"zyzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4014 + {(char *)"zyw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 494 + {(char *)"zywx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2542 + {(char *)"zywy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3054 + {(char *)"zywz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3566 + {(char *)"zyww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4078 + {(char *)"zz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 54 + {(char *)"zzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 310 + {(char *)"zzxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2358 + {(char *)"zzxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2870 + {(char *)"zzxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3382 + {(char *)"zzxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3894 + {(char *)"zzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 374 + {(char *)"zzyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2422 + {(char *)"zzyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2934 + {(char *)"zzyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3446 + {(char *)"zzyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3958 + {(char *)"zzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 438 + {(char *)"zzzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2486 + {(char *)"zzzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2998 + {(char *)"zzzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3510 + {(char *)"zzzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4022 + {(char *)"zzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 502 + {(char *)"zzwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2550 + {(char *)"zzwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3062 + {(char *)"zzwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3574 + {(char *)"zzww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4086 + {(char *)"zw", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 62 + {(char *)"zwx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 318 + {(char *)"zwxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2366 + {(char *)"zwxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2878 + {(char *)"zwxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3390 + {(char *)"zwxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3902 + {(char *)"zwy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 382 + {(char *)"zwyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2430 + {(char *)"zwyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2942 + {(char *)"zwyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3454 + {(char *)"zwyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3966 + {(char *)"zwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 446 + {(char *)"zwzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2494 + {(char *)"zwzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3006 + {(char *)"zwzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3518 + {(char *)"zwzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4030 + {(char *)"zww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 510 + {(char *)"zwwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2558 + {(char *)"zwwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3070 + {(char *)"zwwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3582 + {(char *)"zwww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((2|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4094 + {(char *)"wx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 39 + {(char *)"wxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 295 + {(char *)"wxxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2343 + {(char *)"wxxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2855 + {(char *)"wxxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3367 + {(char *)"wxxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3879 + {(char *)"wxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 359 + {(char *)"wxyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2407 + {(char *)"wxyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2919 + {(char *)"wxyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3431 + {(char *)"wxyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3943 + {(char *)"wxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 423 + {(char *)"wxzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2471 + {(char *)"wxzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2983 + {(char *)"wxzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3495 + {(char *)"wxzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4007 + {(char *)"wxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 487 + {(char *)"wxwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2535 + {(char *)"wxwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3047 + {(char *)"wxwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3559 + {(char *)"wxww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4071 + {(char *)"wy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 47 + {(char *)"wyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 303 + {(char *)"wyxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2351 + {(char *)"wyxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2863 + {(char *)"wyxz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3375 + {(char *)"wyxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3887 + {(char *)"wyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 367 + {(char *)"wyyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2415 + {(char *)"wyyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2927 + {(char *)"wyyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3439 + {(char *)"wyyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3951 + {(char *)"wyz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 431 + {(char *)"wyzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2479 + {(char *)"wyzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2991 + {(char *)"wyzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3503 + {(char *)"wyzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4015 + {(char *)"wyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 495 + {(char *)"wywx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2543 + {(char *)"wywy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3055 + {(char *)"wywz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3567 + {(char *)"wyww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4079 + {(char *)"wz", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 55 + {(char *)"wzx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 311 + {(char *)"wzxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2359 + {(char *)"wzxy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2871 + {(char *)"wzxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3383 + {(char *)"wzxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3895 + {(char *)"wzy", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 375 + {(char *)"wzyx", (getter)Vector_getSwizzle, (setter)Vector_setSwizzle, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2423 + {(char *)"wzyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2935 + {(char *)"wzyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3447 + {(char *)"wzyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3959 + {(char *)"wzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 439 + {(char *)"wzzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2487 + {(char *)"wzzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2999 + {(char *)"wzzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3511 + {(char *)"wzzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4023 + {(char *)"wzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 503 + {(char *)"wzwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2551 + {(char *)"wzwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3063 + {(char *)"wzwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3575 + {(char *)"wzww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4087 + {(char *)"ww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS)))}, // 63 + {(char *)"wwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 319 + {(char *)"wwxx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2367 + {(char *)"wwxy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2879 + {(char *)"wwxz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3391 + {(char *)"wwxw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3903 + {(char *)"wwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 383 + {(char *)"wwyx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2431 + {(char *)"wwyy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2943 + {(char *)"wwyz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3455 + {(char *)"wwyw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3967 + {(char *)"wwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 447 + {(char *)"wwzx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2495 + {(char *)"wwzy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3007 + {(char *)"wwzz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3519 + {(char *)"wwzw", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4031 + {(char *)"www", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2))))}, // 511 + {(char *)"wwwx", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((0|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 2559 + {(char *)"wwwy", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((1|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3071 + {(char *)"wwwz", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((2|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 3583 + {(char *)"wwww", (getter)Vector_getSwizzle, (setter)NULL, NULL, SET_INT_IN_POINTER(((3|SWIZZLE_VALID_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<SWIZZLE_BITS_PER_AXIS) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*2)) | ((3|SWIZZLE_VALID_AXIS)<<(SWIZZLE_BITS_PER_AXIS*3))) )}, // 4095 + {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ +}; + +/* Python script used to make swizzle array */ +/* +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 = 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_setSwizzle' if (len(set(key)) == len(key)) else 'NULL' + print '\t{"%s", %s(getter)Vector_getSwizzle, (setter)%s, NULL, SET_INT_IN_POINTER(%s)}, // %s' % (key, (' '*(4-len(key))), set_str, axis_dict[key], num) + unique.add(num) + +if len(unique) != len(items): + print "ERROR" +*/ + +#if 0 +//ROW VECTOR Multiplication - Vector X Matrix +//[x][y][z] * [1][4][7] +// [2][5][8] +// [3][6][9] +//vector/matrix multiplication IS NOT COMMUTATIVE!!!! +static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObject * mat) +{ + float vec_cpy[4]; + double dot = 0.0f; + int x, y, z = 0, vec_size = vec->size; + + if(mat->colSize != vec_size){ + if(mat->colSize == 4 && vec_size != 3){ + PyErr_SetString(PyExc_ValueError, + "vector * matrix: matrix column size " + "and the vector size must be the same"); + return -1; + } + else { + vec_cpy[3] = 1.0f; + } + } + + if(BaseMath_ReadCallback(vec) == -1 || BaseMath_ReadCallback(mat) == -1) + return -1; + + memcpy(vec_cpy, vec->vec, vec_size * sizeof(float)); + + rvec[3] = 1.0f; + //muliplication + for(x = 0; x < mat->rowSize; x++) { + for(y = 0; y < mat->colSize; y++) { + dot += mat->matrix[x][y] * vec_cpy[y]; + } + rvec[z++] = (float)dot; + dot = 0.0f; + } + return 0; +} +#endif + +/*----------------------------Vector.negate() -------------------- */ +PyDoc_STRVAR(Vector_negate_doc, +".. method:: negate()\n" +"\n" +" Set all values to their negative.\n" +"\n" +" :return: an instance of itself\n" +" :rtype: :class:`Vector`\n" +); +static PyObject *Vector_negate(VectorObject *self) +{ + if(BaseMath_ReadCallback(self) == -1) + return NULL; + + negate_vn(self->vec, self->size); + + (void)BaseMath_WriteCallback(self); // already checked for error + Py_RETURN_NONE; +} + +static struct PyMethodDef Vector_methods[] = { + /* in place only */ + {"zero", (PyCFunction) Vector_zero, METH_NOARGS, Vector_zero_doc}, + {"negate", (PyCFunction) Vector_negate, METH_NOARGS, Vector_negate_doc}, + + /* operate on original or copy */ + {"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc}, + {"normalized", (PyCFunction) Vector_normalized, METH_NOARGS, Vector_normalized_doc}, + + {"to_2d", (PyCFunction) Vector_to_2d, METH_NOARGS, Vector_to_2d_doc}, + {"resize_2d", (PyCFunction) Vector_resize_2d, METH_NOARGS, Vector_resize_2d_doc}, + {"to_3d", (PyCFunction) Vector_to_3d, METH_NOARGS, Vector_to_3d_doc}, + {"resize_3d", (PyCFunction) Vector_resize_3d, METH_NOARGS, Vector_resize_3d_doc}, + {"to_4d", (PyCFunction) Vector_to_4d, METH_NOARGS, Vector_to_4d_doc}, + {"resize_4d", (PyCFunction) Vector_resize_4d, METH_NOARGS, Vector_resize_4d_doc}, + {"to_tuple", (PyCFunction) Vector_to_tuple, METH_VARARGS, Vector_to_tuple_doc}, + {"to_track_quat", (PyCFunction) Vector_to_track_quat, METH_VARARGS, Vector_to_track_quat_doc}, + + /* operation between 2 or more types */ + {"reflect", (PyCFunction) Vector_reflect, METH_O, Vector_reflect_doc}, + {"cross", (PyCFunction) Vector_cross, METH_O, Vector_cross_doc}, + {"dot", (PyCFunction) Vector_dot, METH_O, Vector_dot_doc}, + {"angle", (PyCFunction) Vector_angle, METH_VARARGS, Vector_angle_doc}, + {"rotation_difference", (PyCFunction) Vector_rotation_difference, METH_O, Vector_rotation_difference_doc}, + {"project", (PyCFunction) Vector_project, METH_O, Vector_project_doc}, + {"lerp", (PyCFunction) Vector_lerp, METH_VARARGS, Vector_lerp_doc}, + {"rotate", (PyCFunction) Vector_rotate, METH_O, Vector_rotate_doc}, + + {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc}, + {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} +}; + + +/* 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 neesd to sort out the order +*/ + +PyDoc_STRVAR(vector_doc, +"This object gives access to Vectors in Blender." +); +PyTypeObject vector_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + /* For printing, in format "<module>.<name>" */ + "mathutils.Vector", /* char *tp_name; */ + sizeof(VectorObject), /* int tp_basicsize; */ + 0, /* tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + (destructor) BaseMathObject_dealloc,/* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + (reprfunc)Vector_repr, /* reprfunc tp_repr; */ + + /* Method suites for standard classes */ + + &Vector_NumMethods, /* PyNumberMethods *tp_as_number; */ + &Vector_SeqMethods, /* PySequenceMethods *tp_as_sequence; */ + &Vector_AsMapping, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + vector_doc, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + + /* call function for all accessible objects */ + (traverseproc)BaseMathObject_traverse, //tp_traverse + + /* delete references to contained objects */ + (inquiry)BaseMathObject_clear, //tp_clear + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons ***/ + (richcmpfunc)Vector_richcmpr, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, /* long tp_weaklistoffset; */ + + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + Vector_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + Vector_getseters, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + Vector_new, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL +}; + +/*------------------------newVectorObject (internal)------------- + creates a new vector object + pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER + (i.e. it was allocated elsewhere by MEM_mallocN()) + pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON + (i.e. it must be created here with PyMEM_malloc())*/ +PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObject *base_type) +{ + VectorObject *self; + + if(size > 4 || size < 2) { + PyErr_SetString(PyExc_RuntimeError, + "Vector(): invalid size"); + return NULL; + } + + self= base_type ? (VectorObject *)base_type->tp_alloc(base_type, 0) : + (VectorObject *)PyObject_GC_New(VectorObject, &vector_Type); + + if(self) { + self->size = size; + + /* init callbacks as NULL */ + self->cb_user= NULL; + self->cb_type= self->cb_subtype= 0; + + if(type == Py_WRAP) { + self->vec = vec; + self->wrapped = Py_WRAP; + } + else if (type == Py_NEW) { + self->vec= PyMem_Malloc(size * sizeof(float)); + if(vec) { + memcpy(self->vec, vec, size * sizeof(float)); + } + else { /* new empty */ + fill_vn(self->vec, size, 0.0f); + if(size == 4) { /* do the homogenous thing */ + self->vec[3] = 1.0f; + } + } + self->wrapped = Py_NEW; + } + else { + Py_FatalError("Vector(): invalid type!"); + } + } + return (PyObject *) self; +} + +PyObject *newVectorObject_cb(PyObject *cb_user, int size, int cb_type, int cb_subtype) +{ + float dummy[4] = {0.0, 0.0, 0.0, 0.0}; /* dummy init vector, callbacks will be used on access */ + VectorObject *self= (VectorObject *)newVectorObject(dummy, size, Py_NEW, NULL); + if(self) { + Py_INCREF(cb_user); + self->cb_user= cb_user; + self->cb_type= (unsigned char)cb_type; + self->cb_subtype= (unsigned char)cb_subtype; + PyObject_GC_Track(self); + } + + return (PyObject *)self; +} diff --git a/source/blender/python/mathutils/mathutils_Vector.h b/source/blender/python/mathutils/mathutils_Vector.h new file mode 100644 index 00000000000..0ede836ce44 --- /dev/null +++ b/source/blender/python/mathutils/mathutils_Vector.h @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Willian P. Germano & Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/python/generic/mathutils_Vector.h + * \ingroup pygen + */ + + +#ifndef MATHUTILS_VECTOR_H +#define MATHUTILS_VECTOR_H + +extern PyTypeObject vector_Type; +#define VectorObject_Check(_v) PyObject_TypeCheck((_v), &vector_Type) + +typedef struct { + BASE_MATH_MEMBERS(vec) + + unsigned char size; /* vec size 2,3 or 4 */ +} VectorObject; + +/*prototypes*/ +PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObject *base_type); +PyObject *newVectorObject_cb(PyObject *user, int size, int callback_type, int subtype); + +#endif /* MATHUTILS_VECTOR_H */ diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c new file mode 100644 index 00000000000..bcdfe020e1a --- /dev/null +++ b/source/blender/python/mathutils/mathutils_geometry.c @@ -0,0 +1,1135 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/generic/mathutils_geometry.c + * \ingroup pygen + */ + + +#include <Python.h> + +#include "mathutils_geometry.h" + +/* Used for PolyFill */ +#ifndef MATH_STANDALONE /* define when building outside blender */ +# include "MEM_guardedalloc.h" +# include "BLI_blenlib.h" +# include "BLI_boxpack2d.h" +# include "BKE_displist.h" +# include "BKE_curve.h" +#endif + +#include "BLI_math.h" +#include "BLI_utildefines.h" + +#define SWAP_FLOAT(a, b, tmp) tmp=a; a=b; b=tmp +#define eps 0.000001 + + +/*-------------------------DOC STRINGS ---------------------------*/ +PyDoc_STRVAR(M_Geometry_doc, +"The Blender geometry module" +); + +//---------------------------------INTERSECTION FUNCTIONS-------------------- + +PyDoc_STRVAR(M_Geometry_intersect_ray_tri_doc, +".. function:: intersect_ray_tri(v1, v2, v3, ray, orig, clip=True)\n" +"\n" +" Returns the intersection between a ray and a triangle, if possible, returns None otherwise.\n" +"\n" +" :arg v1: Point1\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg v2: Point2\n" +" :type v2: :class:`mathutils.Vector`\n" +" :arg v3: Point3\n" +" :type v3: :class:`mathutils.Vector`\n" +" :arg ray: Direction of the projection\n" +" :type ray: :class:`mathutils.Vector`\n" +" :arg orig: Origin\n" +" :type orig: :class:`mathutils.Vector`\n" +" :arg clip: When False, don't restrict the intersection to the area of the triangle, use the infinite plane defined by the triangle.\n" +" :type clip: boolean\n" +" :return: The point of intersection or None if no intersection is found\n" +" :rtype: :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *ray, *ray_off, *vec1, *vec2, *vec3; + float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3]; + float det, inv_det, u, v, t; + int clip= 1; + + if(!PyArg_ParseTuple(args, "O!O!O!O!O!|i:intersect_ray_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip)) { + return NULL; + } + if(vec1->size != 3 || vec2->size != 3 || vec3->size != 3 || ray->size != 3 || ray_off->size != 3) { + PyErr_SetString(PyExc_ValueError, + "only 3D vectors for all parameters"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1 || BaseMath_ReadCallback(ray) == -1 || BaseMath_ReadCallback(ray_off) == -1) + return NULL; + + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + + VECCOPY(dir, ray->vec); + normalize_v3(dir); + + VECCOPY(orig, ray_off->vec); + + /* find vectors for two edges sharing v1 */ + sub_v3_v3v3(e1, v2, v1); + sub_v3_v3v3(e2, v3, v1); + + /* begin calculating determinant - also used to calculated U parameter */ + cross_v3_v3v3(pvec, dir, e2); + + /* if determinant is near zero, ray lies in plane of triangle */ + det= dot_v3v3(e1, pvec); + + if (det > -0.000001f && det < 0.000001f) { + Py_RETURN_NONE; + } + + inv_det= 1.0f / det; + + /* calculate distance from v1 to ray origin */ + sub_v3_v3v3(tvec, orig, v1); + + /* calculate U parameter and test bounds */ + u= dot_v3v3(tvec, pvec) * inv_det; + if (clip && (u < 0.0f || u > 1.0f)) { + Py_RETURN_NONE; + } + + /* prepare to test the V parameter */ + cross_v3_v3v3(qvec, tvec, e1); + + /* calculate V parameter and test bounds */ + v= dot_v3v3(dir, qvec) * inv_det; + + if (clip && (v < 0.0f || u + v > 1.0f)) { + Py_RETURN_NONE; + } + + /* calculate t, ray intersects triangle */ + t= dot_v3v3(e2, qvec) * inv_det; + + mul_v3_fl(dir, t); + add_v3_v3v3(pvec, orig, dir); + + return newVectorObject(pvec, 3, Py_NEW, NULL); +} + +/* Line-Line intersection using algorithm from mathworld.wolfram.com */ + +PyDoc_STRVAR(M_Geometry_intersect_line_line_doc, +".. function:: intersect_line_line(v1, v2, v3, v4)\n" +"\n" +" Returns a tuple with the points on each line respectively closest to the other.\n" +"\n" +" :arg v1: First point of the first line\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg v2: Second point of the first line\n" +" :type v2: :class:`mathutils.Vector`\n" +" :arg v3: First point of the second line\n" +" :type v3: :class:`mathutils.Vector`\n" +" :arg v4: Second point of the second line\n" +" :type v4: :class:`mathutils.Vector`\n" +" :rtype: tuple of :class:`mathutils.Vector`'s\n" +); +static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject *args) +{ + PyObject *tuple; + VectorObject *vec1, *vec2, *vec3, *vec4; + float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3]; + + if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4)) { + return NULL; + } + if(vec1->size != vec2->size || vec1->size != vec3->size || vec3->size != vec2->size) { + PyErr_SetString(PyExc_ValueError, + "vectors must be of the same size"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1 || BaseMath_ReadCallback(vec4) == -1) + return NULL; + + if(vec1->size == 3 || vec1->size == 2) { + int result; + + if (vec1->size == 3) { + VECCOPY(v1, vec1->vec); + VECCOPY(v2, vec2->vec); + VECCOPY(v3, vec3->vec); + VECCOPY(v4, vec4->vec); + } + else { + v1[0]= vec1->vec[0]; + v1[1]= vec1->vec[1]; + v1[2]= 0.0f; + + v2[0]= vec2->vec[0]; + v2[1]= vec2->vec[1]; + v2[2]= 0.0f; + + v3[0]= vec3->vec[0]; + v3[1]= vec3->vec[1]; + v3[2]= 0.0f; + + v4[0]= vec4->vec[0]; + v4[1]= vec4->vec[1]; + v4[2]= 0.0f; + } + + result= isect_line_line_v3(v1, v2, v3, v4, i1, i2); + + if (result == 0) { + /* colinear */ + Py_RETURN_NONE; + } + else { + tuple= PyTuple_New(2); + PyTuple_SET_ITEM(tuple, 0, newVectorObject(i1, vec1->size, Py_NEW, NULL)); + PyTuple_SET_ITEM(tuple, 1, newVectorObject(i2, vec1->size, Py_NEW, NULL)); + return tuple; + } + } + else { + PyErr_SetString(PyExc_ValueError, + "2D/3D vectors only"); + return NULL; + } +} + + + + +//----------------------------geometry.normal() ------------------- +PyDoc_STRVAR(M_Geometry_normal_doc, +".. function:: normal(v1, v2, v3, v4=None)\n" +"\n" +" Returns the normal of the 3D tri or quad.\n" +"\n" +" :arg v1: Point1\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg v2: Point2\n" +" :type v2: :class:`mathutils.Vector`\n" +" :arg v3: Point3\n" +" :type v3: :class:`mathutils.Vector`\n" +" :arg v4: Point4 (optional)\n" +" :type v4: :class:`mathutils.Vector`\n" +" :rtype: :class:`mathutils.Vector`\n" +); +static PyObject *M_Geometry_normal(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *vec1, *vec2, *vec3, *vec4; + float n[3]; + + if(PyTuple_GET_SIZE(args) == 3) { + if(!PyArg_ParseTuple(args, "O!O!O!:normal", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3)) { + return NULL; + } + if(vec1->size != vec2->size || vec1->size != vec3->size) { + PyErr_SetString(PyExc_ValueError, + "vectors must be of the same size"); + return NULL; + } + if(vec1->size < 3) { + PyErr_SetString(PyExc_ValueError, + "2D vectors unsupported"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1) + return NULL; + + normal_tri_v3(n, vec1->vec, vec2->vec, vec3->vec); + } + else { + if(!PyArg_ParseTuple(args, "O!O!O!O!:normal", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3, &vector_Type, &vec4)) { + return NULL; + } + if(vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size) { + PyErr_SetString(PyExc_ValueError, + "vectors must be of the same size"); + return NULL; + } + if(vec1->size < 3) { + PyErr_SetString(PyExc_ValueError, + "2D vectors unsupported"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1 || BaseMath_ReadCallback(vec4) == -1) + return NULL; + + normal_quad_v3(n, vec1->vec, vec2->vec, vec3->vec, vec4->vec); + } + + return newVectorObject(n, 3, Py_NEW, NULL); +} + +//--------------------------------- AREA FUNCTIONS-------------------- + +PyDoc_STRVAR(M_Geometry_area_tri_doc, +".. function:: area_tri(v1, v2, v3)\n" +"\n" +" Returns the area size of the 2D or 3D triangle defined.\n" +"\n" +" :arg v1: Point1\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg v2: Point2\n" +" :type v2: :class:`mathutils.Vector`\n" +" :arg v3: Point3\n" +" :type v3: :class:`mathutils.Vector`\n" +" :rtype: float\n" +); +static PyObject *M_Geometry_area_tri(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *vec1, *vec2, *vec3; + + if(!PyArg_ParseTuple(args, "O!O!O!:area_tri", &vector_Type, &vec1, &vector_Type, &vec2, &vector_Type, &vec3)) { + return NULL; + } + + if(vec1->size != vec2->size || vec1->size != vec3->size) { + PyErr_SetString(PyExc_ValueError, + "vectors must be of the same size"); + return NULL; + } + + if(BaseMath_ReadCallback(vec1) == -1 || BaseMath_ReadCallback(vec2) == -1 || BaseMath_ReadCallback(vec3) == -1) + return NULL; + + if (vec1->size == 3) { + return PyFloat_FromDouble(area_tri_v3(vec1->vec, vec2->vec, vec3->vec)); + } + else if (vec1->size == 2) { + return PyFloat_FromDouble(area_tri_v2(vec1->vec, vec2->vec, vec3->vec)); + } + else { + PyErr_SetString(PyExc_ValueError, + "only 2D,3D vectors are supported"); + return NULL; + } +} + + +PyDoc_STRVAR(M_Geometry_intersect_line_line_2d_doc, +".. function:: intersect_line_line_2d(lineA_p1, lineA_p2, lineB_p1, lineB_p2)\n" +"\n" +" Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n" +"\n" +" :arg lineA_p1: First point of the first line\n" +" :type lineA_p1: :class:`mathutils.Vector`\n" +" :arg lineA_p2: Second point of the first line\n" +" :type lineA_p2: :class:`mathutils.Vector`\n" +" :arg lineB_p1: First point of the second line\n" +" :type lineB_p1: :class:`mathutils.Vector`\n" +" :arg lineB_p2: Second point of the second line\n" +" :type lineB_p2: :class:`mathutils.Vector`\n" +" :return: The point of intersection or None when not found\n" +" :rtype: :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_line_line_2d(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *line_a1, *line_a2, *line_b1, *line_b2; + float vi[2]; + if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_line_line_2d", + &vector_Type, &line_a1, + &vector_Type, &line_a2, + &vector_Type, &line_b1, + &vector_Type, &line_b2) + ) { + return NULL; + } + + if(BaseMath_ReadCallback(line_a1) == -1 || BaseMath_ReadCallback(line_a2) == -1 || BaseMath_ReadCallback(line_b1) == -1 || BaseMath_ReadCallback(line_b2) == -1) + return NULL; + + if(isect_seg_seg_v2_point(line_a1->vec, line_a2->vec, line_b1->vec, line_b2->vec, vi) == 1) { + return newVectorObject(vi, 2, Py_NEW, NULL); + } + else { + Py_RETURN_NONE; + } +} + + +PyDoc_STRVAR(M_Geometry_intersect_line_plane_doc, +".. function:: intersect_line_plane(line_a, line_b, plane_co, plane_no, no_flip=False)\n" +"\n" +" Takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None.\n" +"\n" +" :arg line_a: First point of the first line\n" +" :type line_a: :class:`mathutils.Vector`\n" +" :arg line_b: Second point of the first line\n" +" :type line_b: :class:`mathutils.Vector`\n" +" :arg plane_co: A point on the plane\n" +" :type plane_co: :class:`mathutils.Vector`\n" +" :arg plane_no: The direction the plane is facing\n" +" :type plane_no: :class:`mathutils.Vector`\n" +" :arg no_flip: Always return an intersection on the directon defined bt line_a -> line_b\n" +" :type no_flip: :boolean\n" +" :return: The point of intersection or None when not found\n" +" :rtype: :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *line_a, *line_b, *plane_co, *plane_no; + int no_flip= 0; + float isect[3]; + if(!PyArg_ParseTuple(args, "O!O!O!O!|i:intersect_line_plane", + &vector_Type, &line_a, + &vector_Type, &line_b, + &vector_Type, &plane_co, + &vector_Type, &plane_no, + &no_flip) + ) { + return NULL; + } + + if( BaseMath_ReadCallback(line_a) == -1 || + BaseMath_ReadCallback(line_b) == -1 || + BaseMath_ReadCallback(plane_co) == -1 || + BaseMath_ReadCallback(plane_no) == -1 + ) { + return NULL; + } + + if(ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { + PyErr_SetString(PyExc_ValueError, + "geometry.intersect_line_plane(...): " + " can't use 2D Vectors"); + return NULL; + } + + if(isect_line_plane_v3(isect, line_a->vec, line_b->vec, plane_co->vec, plane_no->vec, no_flip) == 1) { + return newVectorObject(isect, 3, Py_NEW, NULL); + } + else { + Py_RETURN_NONE; + } +} + + +PyDoc_STRVAR(M_Geometry_intersect_line_sphere_doc, +".. function:: intersect_line_sphere(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" +"\n" +" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" +" returns the intersection\n" +"\n" +" :arg line_a: First point of the first line\n" +" :type line_a: :class:`mathutils.Vector`\n" +" :arg line_b: Second point of the first line\n" +" :type line_b: :class:`mathutils.Vector`\n" +" :arg sphere_co: The center of the sphere\n" +" :type sphere_co: :class:`mathutils.Vector`\n" +" :arg sphere_radius: Radius of the sphere\n" +" :type sphere_radius: sphere_radius\n" +" :return: The intersection points as a pair of vectors or None when there is no intersection\n" +" :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *line_a, *line_b, *sphere_co; + float sphere_radius; + int clip= TRUE; + + float isect_a[3]; + float isect_b[3]; + + if(!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere", + &vector_Type, &line_a, + &vector_Type, &line_b, + &vector_Type, &sphere_co, + &sphere_radius, &clip) + ) { + return NULL; + } + + if( BaseMath_ReadCallback(line_a) == -1 || + BaseMath_ReadCallback(line_b) == -1 || + BaseMath_ReadCallback(sphere_co) == -1 + ) { + return NULL; + } + + if(ELEM3(2, line_a->size, line_b->size, sphere_co->size)) { + PyErr_SetString(PyExc_ValueError, + "geometry.intersect_line_sphere(...): " + " can't use 2D Vectors"); + return NULL; + } + else { + short use_a= TRUE; + short use_b= TRUE; + float lambda; + + PyObject *ret= PyTuple_New(2); + + switch(isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { + case 1: + if(!(!clip || (((lambda= line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a= FALSE; + use_b= FALSE; + break; + case 2: + if(!(!clip || (((lambda= line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a= FALSE; + if(!(!clip || (((lambda= line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b= FALSE; + break; + default: + use_a= FALSE; + use_b= FALSE; + } + + if(use_a) { PyTuple_SET_ITEM(ret, 0, newVectorObject(isect_a, 3, Py_NEW, NULL)); } + else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } + + if(use_b) { PyTuple_SET_ITEM(ret, 1, newVectorObject(isect_b, 3, Py_NEW, NULL)); } + else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } + + return ret; + } +} + +/* keep in sync with M_Geometry_intersect_line_sphere */ +PyDoc_STRVAR(M_Geometry_intersect_line_sphere_2d_doc, +".. function:: intersect_line_sphere_2d(line_a, line_b, sphere_co, sphere_radius, clip=True)\n" +"\n" +" Takes a lines (as 2 vectors), a sphere as a point and a radius and\n" +" returns the intersection\n" +"\n" +" :arg line_a: First point of the first line\n" +" :type line_a: :class:`mathutils.Vector`\n" +" :arg line_b: Second point of the first line\n" +" :type line_b: :class:`mathutils.Vector`\n" +" :arg sphere_co: The center of the sphere\n" +" :type sphere_co: :class:`mathutils.Vector`\n" +" :arg sphere_radius: Radius of the sphere\n" +" :type sphere_radius: sphere_radius\n" +" :return: The intersection points as a pair of vectors or None when there is no intersection\n" +" :rtype: A tuple pair containing :class:`mathutils.Vector` or None\n" +); +static PyObject *M_Geometry_intersect_line_sphere_2d(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *line_a, *line_b, *sphere_co; + float sphere_radius; + int clip= TRUE; + + float isect_a[3]; + float isect_b[3]; + + if(!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere_2d", + &vector_Type, &line_a, + &vector_Type, &line_b, + &vector_Type, &sphere_co, + &sphere_radius, &clip) + ) { + return NULL; + } + + if( BaseMath_ReadCallback(line_a) == -1 || + BaseMath_ReadCallback(line_b) == -1 || + BaseMath_ReadCallback(sphere_co) == -1 + ) { + return NULL; + } + else { + short use_a= TRUE; + short use_b= TRUE; + float lambda; + + PyObject *ret= PyTuple_New(2); + + switch(isect_line_sphere_v2(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) { + case 1: + if(!(!clip || (((lambda= line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a= FALSE; + use_b= FALSE; + break; + case 2: + if(!(!clip || (((lambda= line_point_factor_v2(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a= FALSE; + if(!(!clip || (((lambda= line_point_factor_v2(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b= FALSE; + break; + default: + use_a= FALSE; + use_b= FALSE; + } + + if(use_a) { PyTuple_SET_ITEM(ret, 0, newVectorObject(isect_a, 2, Py_NEW, NULL)); } + else { PyTuple_SET_ITEM(ret, 0, Py_None); Py_INCREF(Py_None); } + + if(use_b) { PyTuple_SET_ITEM(ret, 1, newVectorObject(isect_b, 2, Py_NEW, NULL)); } + else { PyTuple_SET_ITEM(ret, 1, Py_None); Py_INCREF(Py_None); } + + return ret; + } +} + +PyDoc_STRVAR(M_Geometry_intersect_point_line_doc, +".. function:: intersect_point_line(pt, line_p1, line_p2)\n" +"\n" +" Takes a point and a line and returns a tuple with the closest point on the line and its distance from the first point of the line as a percentage of the length of the line.\n" +"\n" +" :arg pt: Point\n" +" :type pt: :class:`mathutils.Vector`\n" +" :arg line_p1: First point of the line\n" +" :type line_p1: :class:`mathutils.Vector`\n" +" :arg line_p1: Second point of the line\n" +" :type line_p1: :class:`mathutils.Vector`\n" +" :rtype: (:class:`mathutils.Vector`, float)\n" +); +static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *pt, *line_1, *line_2; + float pt_in[3], pt_out[3], l1[3], l2[3]; + float lambda; + PyObject *ret; + + if(!PyArg_ParseTuple(args, "O!O!O!:intersect_point_line", + &vector_Type, &pt, + &vector_Type, &line_1, + &vector_Type, &line_2) + ) { + return NULL; + } + + if(BaseMath_ReadCallback(pt) == -1 || BaseMath_ReadCallback(line_1) == -1 || BaseMath_ReadCallback(line_2) == -1) + return NULL; + + /* accept 2d verts */ + if (pt->size==3) { VECCOPY(pt_in, pt->vec);} + else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) } + + if (line_1->size==3) { VECCOPY(l1, line_1->vec);} + else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) } + + if (line_2->size==3) { VECCOPY(l2, line_2->vec);} + else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) } + + /* do the calculation */ + lambda= closest_to_line_v3(pt_out, pt_in, l1, l2); + + ret= PyTuple_New(2); + PyTuple_SET_ITEM(ret, 0, newVectorObject(pt_out, 3, Py_NEW, NULL)); + PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(lambda)); + return ret; +} + +PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc, +".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n" +"\n" +" Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n" +"\n" +" :arg pt: Point\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg tri_p1: First point of the triangle\n" +" :type tri_p1: :class:`mathutils.Vector`\n" +" :arg tri_p2: Second point of the triangle\n" +" :type tri_p2: :class:`mathutils.Vector`\n" +" :arg tri_p3: Third point of the triangle\n" +" :type tri_p3: :class:`mathutils.Vector`\n" +" :rtype: int\n" +); +static PyObject *M_Geometry_intersect_point_tri_2d(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3; + + if(!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri_2d", + &vector_Type, &pt_vec, + &vector_Type, &tri_p1, + &vector_Type, &tri_p2, + &vector_Type, &tri_p3) + ) { + return NULL; + } + + if(BaseMath_ReadCallback(pt_vec) == -1 || BaseMath_ReadCallback(tri_p1) == -1 || BaseMath_ReadCallback(tri_p2) == -1 || BaseMath_ReadCallback(tri_p3) == -1) + return NULL; + + return PyLong_FromLong(isect_point_tri_v2(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)); +} + +PyDoc_STRVAR(M_Geometry_intersect_point_quad_2d_doc, +".. function:: intersect_point_quad_2d(pt, quad_p1, quad_p2, quad_p3, quad_p4)\n" +"\n" +" Takes 5 vectors (using only the x and y coordinates): one is the point and the next 4 define the quad, only the x and y are used from the vectors. Returns 1 if the point is within the quad, otherwise 0.\n" +"\n" +" :arg pt: Point\n" +" :type v1: :class:`mathutils.Vector`\n" +" :arg quad_p1: First point of the quad\n" +" :type quad_p1: :class:`mathutils.Vector`\n" +" :arg quad_p2: Second point of the quad\n" +" :type quad_p2: :class:`mathutils.Vector`\n" +" :arg quad_p3: Third point of the quad\n" +" :type quad_p3: :class:`mathutils.Vector`\n" +" :arg quad_p4: Forth point of the quad\n" +" :type quad_p4: :class:`mathutils.Vector`\n" +" :rtype: int\n" +); +static PyObject *M_Geometry_intersect_point_quad_2d(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *pt_vec, *quad_p1, *quad_p2, *quad_p3, *quad_p4; + + if(!PyArg_ParseTuple(args, "O!O!O!O!O!:intersect_point_quad_2d", + &vector_Type, &pt_vec, + &vector_Type, &quad_p1, + &vector_Type, &quad_p2, + &vector_Type, &quad_p3, + &vector_Type, &quad_p4) + ) { + return NULL; + } + + if(BaseMath_ReadCallback(pt_vec) == -1 || BaseMath_ReadCallback(quad_p1) == -1 || BaseMath_ReadCallback(quad_p2) == -1 || BaseMath_ReadCallback(quad_p3) == -1 || BaseMath_ReadCallback(quad_p4) == -1) + return NULL; + + return PyLong_FromLong(isect_point_quad_v2(pt_vec->vec, quad_p1->vec, quad_p2->vec, quad_p3->vec, quad_p4->vec)); +} + +PyDoc_STRVAR(M_Geometry_barycentric_transform_doc, +".. function:: barycentric_transform(point, tri_a1, tri_a2, tri_a3, tri_b1, tri_b2, tri_b3)\n" +"\n" +" Return a transformed point, the transformation is defined by 2 triangles.\n" +"\n" +" :arg point: The point to transform.\n" +" :type point: :class:`mathutils.Vector`\n" +" :arg tri_a1: source triangle vertex.\n" +" :type tri_a1: :class:`mathutils.Vector`\n" +" :arg tri_a2: source triangle vertex.\n" +" :type tri_a2: :class:`mathutils.Vector`\n" +" :arg tri_a3: source triangle vertex.\n" +" :type tri_a3: :class:`mathutils.Vector`\n" +" :arg tri_a1: target triangle vertex.\n" +" :type tri_a1: :class:`mathutils.Vector`\n" +" :arg tri_a2: target triangle vertex.\n" +" :type tri_a2: :class:`mathutils.Vector`\n" +" :arg tri_a3: target triangle vertex.\n" +" :type tri_a3: :class:`mathutils.Vector`\n" +" :return: The transformed point\n" +" :rtype: :class:`mathutils.Vector`'s\n" +); +static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObject *args) +{ + VectorObject *vec_pt; + VectorObject *vec_t1_tar, *vec_t2_tar, *vec_t3_tar; + VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src; + float vec[3]; + + if(!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform", + &vector_Type, &vec_pt, + &vector_Type, &vec_t1_src, + &vector_Type, &vec_t2_src, + &vector_Type, &vec_t3_src, + &vector_Type, &vec_t1_tar, + &vector_Type, &vec_t2_tar, + &vector_Type, &vec_t3_tar) + ) { + return NULL; + } + + if( vec_pt->size != 3 || + vec_t1_src->size != 3 || + vec_t2_src->size != 3 || + vec_t3_src->size != 3 || + vec_t1_tar->size != 3 || + vec_t2_tar->size != 3 || + vec_t3_tar->size != 3) + { + PyErr_SetString(PyExc_ValueError, + "One of more of the vector arguments wasn't a 3D vector"); + return NULL; + } + + barycentric_transform(vec, vec_pt->vec, + vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec, + vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec); + + return newVectorObject(vec, 3, Py_NEW, NULL); +} + +#ifndef MATH_STANDALONE + +PyDoc_STRVAR(M_Geometry_interpolate_bezier_doc, +".. function:: interpolate_bezier(knot1, handle1, handle2, knot2, resolution)\n" +"\n" +" Interpolate a bezier spline segment.\n" +"\n" +" :arg knot1: First bezier spline point.\n" +" :type knot1: :class:`mathutils.Vector`\n" +" :arg handle1: First bezier spline handle.\n" +" :type handle1: :class:`mathutils.Vector`\n" +" :arg handle2: Second bezier spline handle.\n" +" :type handle2: :class:`mathutils.Vector`\n" +" :arg knot2: Second bezier spline point.\n" +" :type knot2: :class:`mathutils.Vector`\n" +" :arg resolution: Number of points to return.\n" +" :type resolution: int\n" +" :return: The interpolated points\n" +" :rtype: list of :class:`mathutils.Vector`'s\n" +); +static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject* args) +{ + VectorObject *vec_k1, *vec_h1, *vec_k2, *vec_h2; + int resolu; + int dims; + int i; + float *coord_array, *fp; + PyObject *list; + + float k1[4]= {0.0, 0.0, 0.0, 0.0}; + float h1[4]= {0.0, 0.0, 0.0, 0.0}; + float k2[4]= {0.0, 0.0, 0.0, 0.0}; + float h2[4]= {0.0, 0.0, 0.0, 0.0}; + + + if(!PyArg_ParseTuple(args, "O!O!O!O!i:interpolate_bezier", + &vector_Type, &vec_k1, + &vector_Type, &vec_h1, + &vector_Type, &vec_h2, + &vector_Type, &vec_k2, &resolu) + ) { + return NULL; + } + + if(resolu <= 1) { + PyErr_SetString(PyExc_ValueError, + "resolution must be 2 or over"); + return NULL; + } + + if(BaseMath_ReadCallback(vec_k1) == -1 || BaseMath_ReadCallback(vec_h1) == -1 || BaseMath_ReadCallback(vec_k2) == -1 || BaseMath_ReadCallback(vec_h2) == -1) + return NULL; + + dims= MAX4(vec_k1->size, vec_h1->size, vec_h2->size, vec_k2->size); + + for(i=0; i < vec_k1->size; i++) k1[i]= vec_k1->vec[i]; + for(i=0; i < vec_h1->size; i++) h1[i]= vec_h1->vec[i]; + for(i=0; i < vec_k2->size; i++) k2[i]= vec_k2->vec[i]; + for(i=0; i < vec_h2->size; i++) h2[i]= vec_h2->vec[i]; + + coord_array= MEM_callocN(dims * (resolu) * sizeof(float), "interpolate_bezier"); + for(i=0; i<dims; i++) { + forward_diff_bezier(k1[i], h1[i], h2[i], k2[i], coord_array+i, resolu-1, sizeof(float)*dims); + } + + list= PyList_New(resolu); + fp= coord_array; + for(i=0; i<resolu; i++, fp= fp+dims) { + PyList_SET_ITEM(list, i, newVectorObject(fp, dims, Py_NEW, NULL)); + } + MEM_freeN(coord_array); + return list; +} + + +PyDoc_STRVAR(M_Geometry_tesselate_polygon_doc, +".. function:: tesselate_polygon(veclist_list)\n" +"\n" +" Takes a list of polylines (each point a vector) and returns the point indices for a polyline filled with triangles.\n" +"\n" +" :arg veclist_list: list of polylines\n" +" :rtype: list\n" +); +/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */ +static PyObject *M_Geometry_tesselate_polygon(PyObject *UNUSED(self), PyObject *polyLineSeq) +{ + PyObject *tri_list; /*return this list of tri's */ + PyObject *polyLine, *polyVec; + int i, len_polylines, len_polypoints, ls_error= 0; + + /* display listbase */ + ListBase dispbase={NULL, NULL}; + DispList *dl; + float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */ + int index, *dl_face, totpoints=0; + + if(!PySequence_Check(polyLineSeq)) { + PyErr_SetString(PyExc_TypeError, + "expected a sequence of poly lines"); + return NULL; + } + + len_polylines= PySequence_Size(polyLineSeq); + + for(i= 0; i < len_polylines; ++i) { + polyLine= PySequence_GetItem(polyLineSeq, i); + if (!PySequence_Check(polyLine)) { + freedisplist(&dispbase); + Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/ + PyErr_SetString(PyExc_TypeError, + "One or more of the polylines is not a sequence of mathutils.Vector's"); + return NULL; + } + + len_polypoints= PySequence_Size(polyLine); + if (len_polypoints>0) { /* dont bother adding edges as polylines */ +#if 0 + if (EXPP_check_sequence_consistency(polyLine, &vector_Type) != 1) { + freedisplist(&dispbase); + Py_DECREF(polyLine); + PyErr_SetString(PyExc_TypeError, + "A point in one of the polylines is not a mathutils.Vector type"); + return NULL; + } +#endif + dl= MEM_callocN(sizeof(DispList), "poly disp"); + BLI_addtail(&dispbase, dl); + dl->type= DL_INDEX3; + dl->nr= len_polypoints; + dl->type= DL_POLY; + dl->parts= 1; /* no faces, 1 edge loop */ + dl->col= 0; /* no material */ + dl->verts= fp= MEM_callocN(sizeof(float)*3*len_polypoints, "dl verts"); + dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index"); + + for(index= 0; index<len_polypoints; ++index, fp+=3) { + polyVec= PySequence_GetItem(polyLine, index); + if(VectorObject_Check(polyVec)) { + + if(BaseMath_ReadCallback((VectorObject *)polyVec) == -1) + ls_error= 1; + + fp[0]= ((VectorObject *)polyVec)->vec[0]; + fp[1]= ((VectorObject *)polyVec)->vec[1]; + if(((VectorObject *)polyVec)->size > 2) + fp[2]= ((VectorObject *)polyVec)->vec[2]; + else + fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */ + } + else { + ls_error= 1; + } + + totpoints++; + Py_DECREF(polyVec); + } + } + Py_DECREF(polyLine); + } + + if(ls_error) { + freedisplist(&dispbase); /* possible some dl was allocated */ + PyErr_SetString(PyExc_TypeError, + "A point in one of the polylines " + "is not a mathutils.Vector type"); + return NULL; + } + else if (totpoints) { + /* now make the list to return */ + filldisplist(&dispbase, &dispbase, 0); + + /* The faces are stored in a new DisplayList + thats added to the head of the listbase */ + dl= dispbase.first; + + tri_list= PyList_New(dl->parts); + if(!tri_list) { + freedisplist(&dispbase); + PyErr_SetString(PyExc_RuntimeError, + "failed to make a new list"); + return NULL; + } + + 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])); + dl_face+= 3; + index++; + } + freedisplist(&dispbase); + } + else { + /* no points, do this so scripts dont barf */ + freedisplist(&dispbase); /* possible some dl was allocated */ + tri_list= PyList_New(0); + } + + return tri_list; +} + + +static int boxPack_FromPyObject(PyObject *value, boxPack **boxarray) +{ + int len, i; + PyObject *list_item, *item_1, *item_2; + boxPack *box; + + + /* Error checking must already be done */ + if(!PyList_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "can only back a list of [x, y, w, h]"); + return -1; + } + + len= PyList_Size(value); + + (*boxarray)= MEM_mallocN(len*sizeof(boxPack), "boxPack box"); + + + for(i= 0; i < len; i++) { + list_item= PyList_GET_ITEM(value, i); + if(!PyList_Check(list_item) || PyList_Size(list_item) < 4) { + MEM_freeN(*boxarray); + PyErr_SetString(PyExc_TypeError, + "can only pack a list of [x, y, w, h]"); + return -1; + } + + box= (*boxarray)+i; + + item_1= PyList_GET_ITEM(list_item, 2); + item_2= PyList_GET_ITEM(list_item, 3); + + box->w= (float)PyFloat_AsDouble(item_1); + box->h= (float)PyFloat_AsDouble(item_2); + box->index= i; + + /* accounts for error case too and overwrites with own error */ + if (box->w < 0.0f || box->h < 0.0f) { + MEM_freeN(*boxarray); + PyErr_SetString(PyExc_TypeError, + "error parsing width and height values from list: " + "[x, y, w, h], not numbers or below zero"); + return -1; + } + + /* verts will be added later */ + } + return 0; +} + +static void boxPack_ToPyObject(PyObject *value, boxPack **boxarray) +{ + int len, i; + PyObject *list_item; + boxPack *box; + + len= PyList_Size(value); + + for(i= 0; i < len; i++) { + box= (*boxarray)+i; + list_item= PyList_GET_ITEM(value, box->index); + PyList_SET_ITEM(list_item, 0, PyFloat_FromDouble(box->x)); + PyList_SET_ITEM(list_item, 1, PyFloat_FromDouble(box->y)); + } + MEM_freeN(*boxarray); +} + +PyDoc_STRVAR(M_Geometry_box_pack_2d_doc, +".. function:: box_pack_2d(boxes)\n" +"\n" +" Returns the normal of the 3D tri or quad.\n" +"\n" +" :arg boxes: list of boxes, each box is a list where the first 4 items are [x, y, width, height, ...] other items are ignored.\n" +" :type boxes: list\n" +" :return: the width and height of the packed bounding box\n" +" :rtype: tuple, pair of floats\n" +); +static PyObject *M_Geometry_box_pack_2d(PyObject *UNUSED(self), PyObject *boxlist) +{ + float tot_width= 0.0f, tot_height= 0.0f; + int len; + + PyObject *ret; + + if(!PyList_Check(boxlist)) { + PyErr_SetString(PyExc_TypeError, + "expected a list of boxes [[x, y, w, h], ... ]"); + return NULL; + } + + len= PyList_GET_SIZE(boxlist); + if (len) { + boxPack *boxarray= NULL; + if(boxPack_FromPyObject(boxlist, &boxarray) == -1) { + return NULL; /* exception set */ + } + + /* Non Python function */ + boxPack2D(boxarray, len, &tot_width, &tot_height); + + boxPack_ToPyObject(boxlist, &boxarray); + } + + ret= PyTuple_New(2); + PyTuple_SET_ITEM(ret, 0, PyFloat_FromDouble(tot_width)); + PyTuple_SET_ITEM(ret, 1, PyFloat_FromDouble(tot_width)); + return ret; +} + +#endif /* MATH_STANDALONE */ + + +static PyMethodDef M_Geometry_methods[]= { + {"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc}, + {"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc}, + {"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc}, + {"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc}, + {"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc}, + {"intersect_line_line_2d", (PyCFunction) M_Geometry_intersect_line_line_2d, METH_VARARGS, M_Geometry_intersect_line_line_2d_doc}, + {"intersect_line_plane", (PyCFunction) M_Geometry_intersect_line_plane, METH_VARARGS, M_Geometry_intersect_line_plane_doc}, + {"intersect_line_sphere", (PyCFunction) M_Geometry_intersect_line_sphere, METH_VARARGS, M_Geometry_intersect_line_sphere_doc}, + {"intersect_line_sphere_2d", (PyCFunction) M_Geometry_intersect_line_sphere_2d, METH_VARARGS, M_Geometry_intersect_line_sphere_2d_doc}, + {"area_tri", (PyCFunction) M_Geometry_area_tri, METH_VARARGS, M_Geometry_area_tri_doc}, + {"normal", (PyCFunction) M_Geometry_normal, METH_VARARGS, M_Geometry_normal_doc}, + {"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc}, +#ifndef MATH_STANDALONE + {"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_doc}, + {"tesselate_polygon", (PyCFunction) M_Geometry_tesselate_polygon, METH_O, M_Geometry_tesselate_polygon_doc}, + {"box_pack_2d", (PyCFunction) M_Geometry_box_pack_2d, METH_O, M_Geometry_box_pack_2d_doc}, +#endif + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef M_Geometry_module_def= { + PyModuleDef_HEAD_INIT, + "mathutils.geometry", /* m_name */ + M_Geometry_doc, /* m_doc */ + 0, /* m_size */ + M_Geometry_methods, /* m_methods */ + NULL, /* m_reload */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; + +/*----------------------------MODULE INIT-------------------------*/ +PyMODINIT_FUNC PyInit_mathutils_geometry(void) +{ + PyObject *submodule= PyModule_Create(&M_Geometry_module_def); + return submodule; +} diff --git a/source/blender/python/mathutils/mathutils_geometry.h b/source/blender/python/mathutils/mathutils_geometry.h new file mode 100644 index 00000000000..c963a63ce7f --- /dev/null +++ b/source/blender/python/mathutils/mathutils_geometry.h @@ -0,0 +1,43 @@ +/* + * $Id$ + * + * ***** 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. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Joseph Gilbert + * + * ***** END GPL LICENSE BLOCK ***** +*/ + +/** \file blender/python/generic/mathutils_geometry.h + * \ingroup pygen + */ + +/*Include this file for access to vector, quat, matrix, euler, etc...*/ + +#ifndef MATHUTILS_GEOMETRY_H +#define MATHUTILS_GEOMETRY_H + +#include "mathutils.h" + +PyMODINIT_FUNC PyInit_mathutils_geometry(void); + +#endif /* MATHUTILS_GEOMETRY_H */ |