From f70f16723741405ab3c32b9e1f05af35ecf9eb21 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Thu, 14 Jul 2011 08:20:19 +0000 Subject: Shuffle code so it compiles with MSVC too. (Array of unknown size otherwise). --- source/blender/python/generic/bgl.c | 76 ++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 39 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 1891e13fdc1..18d01f45015 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -69,11 +69,44 @@ static PySequenceMethods Buffer_SeqMethods = { }; static void Buffer_dealloc(PyObject *self); -static PyObject *Buffer_tolist(PyObject *self, void *arg); -static PyObject *Buffer_dimensions(PyObject *self, void *arg); static PyObject *Buffer_repr(PyObject *self); -static PyMethodDef Buffer_methods[]; -static PyGetSetDef Buffer_getseters[]; + +static PyObject *Buffer_to_list(PyObject *self) +{ + int i, len= ((Buffer *)self)->dimensions[0]; + PyObject *list= PyList_New(len); + + for (i=0; indimensions); + int i; + + for (i= 0; indimensions; i++) { + PyList_SET_ITEM(list, i, PyLong_FromLong(buffer->dimensions[i])); + } + + return list; +} + +static PyMethodDef Buffer_methods[] = { + {"to_list", (PyCFunction)Buffer_to_list, METH_NOARGS, + "return the buffer as a list"}, + {NULL, NULL, 0, NULL} +}; + +static PyGetSetDef Buffer_getseters[] = { + {(char *)"dimensions", (getter)Buffer_dimensions, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + PyTypeObject BGL_bufferType = { PyVarObject_HEAD_INIT(NULL, 0) @@ -460,41 +493,6 @@ static void Buffer_dealloc(PyObject *self) PyObject_DEL(self); } -static PyObject *Buffer_to_list(PyObject *self) -{ - int i, len= ((Buffer *)self)->dimensions[0]; - PyObject *list= PyList_New(len); - - for (i=0; indimensions); - int i; - - for (i= 0; indimensions; i++) { - PyList_SET_ITEM(list, i, PyLong_FromLong(buffer->dimensions[i])); - } - - return list; -} - -static PyMethodDef Buffer_methods[] = { - {"to_list", (PyCFunction)Buffer_to_list, METH_NOARGS, - "return the buffer as a list"}, - {NULL, NULL, 0, NULL} -}; - -static PyGetSetDef Buffer_getseters[] = { - {(char *)"dimensions", (getter)Buffer_dimensions, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL} -}; static PyObject *Buffer_repr(PyObject *self) { -- cgit v1.2.3 From b028cba0e4878b5034b96772aba85abc9f669a12 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 14 Jul 2011 09:54:03 +0000 Subject: many mathutils exception types were wrong, went over all exceptions in mathutils and double checked the're correct. --- source/blender/python/generic/mathutils.c | 2 +- source/blender/python/generic/mathutils_Color.c | 22 +++---- source/blender/python/generic/mathutils_Euler.c | 14 ++--- source/blender/python/generic/mathutils_Matrix.c | 71 +++++++++++----------- .../blender/python/generic/mathutils_Quaternion.c | 16 +++-- source/blender/python/generic/mathutils_Vector.c | 25 ++++---- source/blender/python/generic/mathutils_geometry.c | 7 ++- 7 files changed, 75 insertions(+), 82 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/generic/mathutils.c b/source/blender/python/generic/mathutils.c index bba08e312b7..1ff33d5a6bb 100644 --- a/source/blender/python/generic/mathutils.c +++ b/source/blender/python/generic/mathutils.c @@ -75,7 +75,7 @@ static int mathutils_array_parse_fast(float *array, int array_min, int array_max do { i--; if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0f) && PyErr_Occurred()) { - PyErr_Format(PyExc_ValueError, + PyErr_Format(PyExc_TypeError, "%.200s: sequence index %d expected a number, " "found '%.200s' type, ", error_prefix, i, Py_TYPE(item)->tp_name); diff --git a/source/blender/python/generic/mathutils_Color.c b/source/blender/python/generic/mathutils_Color.c index fd187fd92fd..d0c7ec72cea 100644 --- a/source/blender/python/generic/mathutils_Color.c +++ b/source/blender/python/generic/mathutils_Color.c @@ -259,7 +259,7 @@ static int Color_ass_slice(ColorObject *self, int begin, int end, PyObject *seq) return -1; if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "color[begin:end] = []: " "size mismatch in slice assignment"); return -1; @@ -296,7 +296,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item) return Color_slice(self, start, stop); } else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with color"); return NULL; } @@ -328,7 +328,7 @@ static int Color_ass_subscript(ColorObject *self, PyObject *item, PyObject *valu if (step == 1) return Color_ass_slice(self, start, stop, value); else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with color"); return -1; } @@ -371,7 +371,7 @@ static PyObject *Color_add(PyObject *v1, PyObject *v2) float col[COLOR_SIZE]; if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Color addition: " "arguments not valid for this operation"); return NULL; @@ -393,7 +393,7 @@ static PyObject *Color_iadd(PyObject *v1, PyObject *v2) ColorObject *color1 = NULL, *color2 = NULL; if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Color addition: " "arguments not valid for this operation"); return NULL; @@ -418,7 +418,7 @@ static PyObject *Color_sub(PyObject *v1, PyObject *v2) float col[COLOR_SIZE]; if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Color subtraction: " "arguments not valid for this operation"); return NULL; @@ -440,7 +440,7 @@ static PyObject *Color_isub(PyObject *v1, PyObject *v2) ColorObject *color1= NULL, *color2= NULL; if (!ColorObject_Check(v1) || !ColorObject_Check(v2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Color subtraction: " "arguments not valid for this operation"); return NULL; @@ -555,7 +555,9 @@ static PyObject *Color_imul(PyObject *v1, PyObject *v2) mul_vn_fl(color->col, COLOR_SIZE, scalar); } else { - PyErr_SetString(PyExc_TypeError, "Color multiplication: arguments not acceptable for this operation"); + PyErr_SetString(PyExc_TypeError, + "Color multiplication: " + "arguments not acceptable for this operation"); return NULL; } @@ -846,9 +848,7 @@ PyObject *newColorObject(float *col, int type, PyTypeObject *base_type) self->wrapped = Py_NEW; } else { - PyErr_SetString(PyExc_RuntimeError, - "Color(): invalid type, internal error"); - return NULL; + Py_FatalError("Color(): invalid type!"); } } diff --git a/source/blender/python/generic/mathutils_Euler.c b/source/blender/python/generic/mathutils_Euler.c index 2888b0667f1..a7d6d921d16 100644 --- a/source/blender/python/generic/mathutils_Euler.c +++ b/source/blender/python/generic/mathutils_Euler.c @@ -99,7 +99,7 @@ short euler_order_from_string(const char *str, const char *error_prefix) } } - PyErr_Format(PyExc_TypeError, + PyErr_Format(PyExc_ValueError, "%s: invalid euler order '%s'", error_prefix, str); return -1; @@ -209,7 +209,7 @@ static PyObject *Euler_rotate_axis(EulerObject * self, PyObject *args) return NULL; } if(!(ELEM3(*axis, 'X', 'Y', 'Z') && axis[1]=='\0')){ - PyErr_SetString(PyExc_TypeError, "euler.rotate(): " + PyErr_SetString(PyExc_ValueError, "euler.rotate(): " "expected axis to be 'X', 'Y' or 'Z'"); return NULL; } @@ -449,7 +449,7 @@ static int Euler_ass_slice(EulerObject *self, int begin, int end, PyObject *seq) return -1; if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "euler[begin:end] = []: " "size mismatch in slice assignment"); return -1; @@ -486,7 +486,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item) return Euler_slice(self, start, stop); } else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with eulers"); return NULL; } @@ -519,7 +519,7 @@ static int Euler_ass_subscript(EulerObject *self, PyObject *item, PyObject *valu if (step == 1) return Euler_ass_slice(self, start, stop, value); else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with euler"); return -1; } @@ -701,9 +701,7 @@ PyObject *newEulerObject(float *eul, short order, int type, PyTypeObject *base_t self->wrapped = Py_NEW; } else { - PyErr_SetString(PyExc_RuntimeError, - "Euler(): invalid type, internal error"); - return NULL; + Py_FatalError("Euler(): invalid type!"); } self->order= order; diff --git a/source/blender/python/generic/mathutils_Matrix.c b/source/blender/python/generic/mathutils_Matrix.c index 4343485bb3a..c5ed1e32ee8 100644 --- a/source/blender/python/generic/mathutils_Matrix.c +++ b/source/blender/python/generic/mathutils_Matrix.c @@ -225,7 +225,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) 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_TypeError, + PyErr_SetString(PyExc_ValueError, "mathutils.RotationMatrix(): " "3rd argument axis value must be a 3D vector " "or a string in 'X', 'Y', 'Z'"); @@ -240,19 +240,19 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) angle= angle_wrap_rad(angle); if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, + 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_AttributeError, + 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_AttributeError, + PyErr_SetString(PyExc_ValueError, "mathutils.RotationMatrix(): " "axis of rotation for 3d and 4d matrices is required"); return NULL; @@ -300,7 +300,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args) } else { /* should never get here */ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "mathutils.RotationMatrix(): unknown error"); return NULL; } @@ -365,7 +365,7 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args) return NULL; } if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "Matrix.Scale(): " "can only return a 2x2 3x3 or 4x4 matrix"); return NULL; @@ -451,7 +451,7 @@ static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args) return NULL; } if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "mathutils.Matrix.OrthoProjection(): " "can only return a 2x2 3x3 or 4x4 matrix"); return NULL; @@ -568,7 +568,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) return NULL; } if(matSize != 2 && matSize != 3 && matSize != 4) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "mathutils.Matrix.Shear(): " "can only return a 2x2 3x3 or 4x4 matrix"); return NULL; @@ -578,7 +578,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) float const factor= PyFloat_AsDouble(fac); if(factor==-1.0f && PyErr_Occurred()) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "mathutils.Matrix.Shear(): " "the factor to be a float"); return NULL; @@ -595,7 +595,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) mat[1] = factor; } else { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "Matrix.Shear(): " "expected: X, Y or wrong matrix size for shearing plane"); return NULL; @@ -627,7 +627,7 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args) mat[2] = factor[1]; } else { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "mathutils.Matrix.Shear(): " "expected: X, Y, XY, XZ, YZ"); return NULL; @@ -686,7 +686,7 @@ static PyObject *Matrix_to_quaternion(MatrixObject *self) /*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_AttributeError, + PyErr_SetString(PyExc_ValueError, "matrix.to_quat(): " "inappropriate matrix size - expects 3x3 or 4x4 matrix"); return NULL; @@ -750,7 +750,7 @@ static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args) mat= tmat; } else { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "matrix.to_euler(): " "inappropriate matrix size - expects 3x3 or 4x4 matrix"); return NULL; @@ -879,7 +879,7 @@ static PyObject *Matrix_to_3x3(MatrixObject *self) return NULL; if((self->col_size < 3) || (self->row_size < 3)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.to_3x3(): inappropriate matrix size"); return NULL; } @@ -903,7 +903,7 @@ static PyObject *Matrix_to_translation(MatrixObject *self) return NULL; if((self->col_size < 3) || self->row_size < 4){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.to_translation(): " "inappropriate matrix size"); return NULL; @@ -933,7 +933,7 @@ static PyObject *Matrix_to_scale(MatrixObject *self) /*must be 3-4 cols, 3-4 rows, square matrix*/ if((self->col_size < 3) || (self->row_size < 3)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.to_scale(): " "inappropriate matrix size, 3x3 minimum size"); return NULL; @@ -969,7 +969,7 @@ static PyObject *Matrix_invert(MatrixObject *self) return NULL; if(self->row_size != self->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.invert(ed): " "only square matrices are supported"); return NULL; @@ -1050,7 +1050,7 @@ static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value) return NULL; if(self->col_size != 3 || self->row_size != 3) { - PyErr_SetString(PyExc_ValueError, + PyErr_SetString(PyExc_TypeError, "Matrix must have 3x3 dimensions"); return NULL; } @@ -1082,7 +1082,7 @@ static PyObject *Matrix_decompose(MatrixObject *self) float size[3]; if(self->col_size != 4 || self->row_size != 4) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.decompose(): " "inappropriate matrix size - expects 4x4 matrix"); return NULL; @@ -1125,7 +1125,7 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) return NULL; if(self->row_size != mat2->row_size || self->col_size != mat2->col_size) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "matrix.lerp(): " "expects both matrix objects of the same dimensions"); return NULL; @@ -1142,7 +1142,7 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->contigPtr, (float (*)[3])mat2->contigPtr, fac); } else { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "matrix.lerp(): " "only 3x3 and 4x4 matrices supported"); return NULL; @@ -1168,7 +1168,7 @@ static PyObject *Matrix_determinant(MatrixObject *self) return NULL; if(self->row_size != self->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.determinant: " "only square matrices are supported"); return NULL; @@ -1192,7 +1192,7 @@ static PyObject *Matrix_transpose(MatrixObject *self) return NULL; if(self->row_size != self->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.transpose(d): " "only square matrices are supported"); return NULL; @@ -1261,7 +1261,7 @@ static PyObject *Matrix_identity(MatrixObject *self) return NULL; if(self->row_size != self->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix.identity: " "only square matrices are supported"); return NULL; @@ -1409,7 +1409,7 @@ static int Matrix_ass_item(MatrixObject *self, int i, PyObject *value) return -1; if(i >= self->row_size || i < 0){ - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "matrix[attribute] = x: bad column"); return -1; } @@ -1473,7 +1473,7 @@ static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *va if(PySequence_Fast_GET_SIZE(value_fast) != size) { Py_DECREF(value_fast); - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "matrix[begin:end] = []: " "size mismatch in slice assignment"); return -1; @@ -1509,7 +1509,7 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2) mat2 = (MatrixObject*)m2; if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Matrix addition: " "arguments not valid for this operation"); return NULL; @@ -1519,7 +1519,7 @@ static PyObject *Matrix_add(PyObject *m1, PyObject *m2) return NULL; if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Matrix addition: " "matrices must have the same dimensions for this operation"); return NULL; @@ -1540,7 +1540,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) mat2 = (MatrixObject*)m2; if(!MatrixObject_Check(m1) || !MatrixObject_Check(m2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Matrix addition: " "arguments not valid for this operation"); return NULL; @@ -1550,7 +1550,7 @@ static PyObject *Matrix_sub(PyObject *m1, PyObject *m2) return NULL; if(mat1->row_size != mat2->row_size || mat1->col_size != mat2->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Matrix addition: " "matrices must have the same dimensions for this operation"); return NULL; @@ -1589,7 +1589,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) if(mat1 && mat2) { /*MATRIX * MATRIX*/ if(mat1->row_size != mat2->col_size){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "Matrix multiplication: " "matrix A rowsize must equal matrix B colsize"); return NULL; @@ -1683,14 +1683,14 @@ static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item) return Matrix_slice(self, start, stop); } else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with matricies"); return NULL; } } else { PyErr_Format(PyExc_TypeError, - "vector indices must be integers, not %.200s", + "matrix indices must be integers, not %.200s", Py_TYPE(item)->tp_name); return NULL; } @@ -1715,7 +1715,7 @@ static int Matrix_ass_subscript(MatrixObject* self, PyObject* item, PyObject* va if (step == 1) return Matrix_ass_slice(self, start, stop, value); else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with matricies"); return -1; } @@ -2021,8 +2021,7 @@ PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsign self->wrapped = Py_NEW; } else { - PyErr_SetString(PyExc_RuntimeError, - "Matrix(): invalid type, internal error"); + Py_FatalError("Matrix(): invalid type!"); return NULL; } } diff --git a/source/blender/python/generic/mathutils_Quaternion.c b/source/blender/python/generic/mathutils_Quaternion.c index 977ff7ccbc7..3b05b9a250b 100644 --- a/source/blender/python/generic/mathutils_Quaternion.c +++ b/source/blender/python/generic/mathutils_Quaternion.c @@ -248,7 +248,7 @@ static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args) return NULL; if(fac > 1.0f || fac < 0.0f) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "quat.slerp(): " "interpolation factor must be between 0.0 and 1.0"); return NULL; @@ -582,7 +582,7 @@ static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyOb return -1; if(size != (end - begin)){ - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "quaternion[begin:end] = []: " "size mismatch in slice assignment"); return -1; @@ -620,7 +620,7 @@ static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item) return Quaternion_slice(self, start, stop); } else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternions"); return NULL; } @@ -653,7 +653,7 @@ static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyOb if (step == 1) return Quaternion_ass_slice(self, start, stop, value); else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with quaternion"); return -1; } @@ -675,7 +675,7 @@ static PyObject *Quaternion_add(PyObject *q1, PyObject *q2) QuaternionObject *quat1 = NULL, *quat2 = NULL; if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Quaternion addition: " "arguments not valid for this operation"); return NULL; @@ -698,7 +698,7 @@ static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2) QuaternionObject *quat1 = NULL, *quat2 = NULL; if(!QuaternionObject_Check(q1) || !QuaternionObject_Check(q2)) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "Quaternion addition: " "arguments not valid for this operation"); return NULL; @@ -1142,9 +1142,7 @@ PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type) self->wrapped = Py_NEW; } else { - PyErr_SetString(PyExc_RuntimeError, - "Quaternion(): invalid type, internal error"); - return NULL; + Py_FatalError("Quaternion(): invalid type!"); } } return (PyObject *) self; diff --git a/source/blender/python/generic/mathutils_Vector.c b/source/blender/python/generic/mathutils_Vector.c index b8fdc2f0890..a834e8f2ba4 100644 --- a/source/blender/python/generic/mathutils_Vector.c +++ b/source/blender/python/generic/mathutils_Vector.c @@ -442,8 +442,7 @@ static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args) } } else { - PyErr_SetString(PyExc_ValueError, - axis_err_msg); + PyErr_SetString(PyExc_ValueError, axis_err_msg); return NULL; } } @@ -667,7 +666,7 @@ 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_AttributeError, + PyErr_SetString(PyExc_ValueError, "vec.difference(value): " "expects both vectors to be size 3 or 4"); return NULL; @@ -1094,7 +1093,7 @@ static int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject vec_cpy[3] = 1.0f; } else { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_TypeError, "matrix * vector: " "matrix.row_size and len(vector) must be the same, " "except for 3D vector * 4x4 matrix."); @@ -1147,7 +1146,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) double dot = 0.0f; if(vec1->size != vec2->size) { - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "Vector multiplication: " "vectors must have the same dimensions for this operation"); return NULL; @@ -1177,7 +1176,7 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) float tvec[3]; if(vec1->size != 3) { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "Vector multiplication: " "only 3D vector rotations (with quats) currently supported"); return NULL; @@ -1235,7 +1234,7 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2) QuaternionObject *quat2 = (QuaternionObject*)v2; if(vec->size != 3) { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "Vector multiplication: " "only 3D vector rotations (with quats) currently supported"); return NULL; @@ -1485,7 +1484,7 @@ static PyObject *Vector_subscript(VectorObject* self, PyObject* item) return Vector_slice(self, start, stop); } else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors"); return NULL; } @@ -1517,7 +1516,7 @@ static int Vector_ass_subscript(VectorObject* self, PyObject* item, PyObject* va if (step == 1) return Vector_ass_slice(self, start, stop, value); else { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_IndexError, "slice steps not supported with vectors"); return -1; } @@ -1620,7 +1619,7 @@ static int Vector_setLength(VectorObject *self, PyObject *value) } if (param < 0.0) { - PyErr_SetString(PyExc_TypeError, + PyErr_SetString(PyExc_ValueError, "cannot set a vectors length to a negative value"); return -1; } @@ -2174,7 +2173,7 @@ static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObj if(mat->colSize != vec_size){ if(mat->colSize == 4 && vec_size != 3){ - PyErr_SetString(PyExc_AttributeError, + PyErr_SetString(PyExc_ValueError, "vector * matrix: matrix column size " "and the vector size must be the same"); return -1; @@ -2390,9 +2389,7 @@ PyObject *newVectorObject(float *vec, const int size, const int type, PyTypeObje self->wrapped = Py_NEW; } else { - PyErr_SetString(PyExc_RuntimeError, - "Vector(): invalid type, internal error"); - return NULL; + Py_FatalError("Vector(): invalid type!"); } } return (PyObject *) self; diff --git a/source/blender/python/generic/mathutils_geometry.c b/source/blender/python/generic/mathutils_geometry.c index 601daf01d00..d2724f6603e 100644 --- a/source/blender/python/generic/mathutils_geometry.c +++ b/source/blender/python/generic/mathutils_geometry.c @@ -556,7 +556,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec } if(ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_plane(...): " " can't use 2D Vectors"); return NULL; @@ -614,7 +614,7 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje } if(ELEM3(2, line_a->size, line_b->size, sphere_co->size)) { - PyErr_SetString(PyExc_RuntimeError, + PyErr_SetString(PyExc_ValueError, "geometry.intersect_line_sphere(...): " " can't use 2D Vectors"); return NULL; @@ -881,6 +881,7 @@ static int boxPack_FromPyObject(PyObject *value, boxPack **boxarray) 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, @@ -1075,7 +1076,7 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje vec_t3_tar->size != 3) { PyErr_SetString(PyExc_ValueError, - "One of more of the vector arguments wasnt a 3D vector"); + "One of more of the vector arguments wasn't a 3D vector"); return NULL; } -- cgit v1.2.3 From 5ff9acfd28211d90045e9dc08da7790099b9c462 Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Fri, 15 Jul 2011 00:39:49 +0000 Subject: Fix for [#27307] Blender crashes when loading a new scene while baking fluid dynamics * Fluid bakes didn't respect the job stop flag. * Also made msvc happy with some casts. --- source/blender/editors/physics/physics_fluid.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index b573c77c7f3..37309f1e07c 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -722,15 +722,17 @@ typedef struct FluidBakeJob { static void fluidbake_free(void *customdata) { - FluidBakeJob *fb= customdata; + FluidBakeJob *fb= (FluidBakeJob *)customdata; MEM_freeN(fb); } /* called by fluidbake, only to check job 'stop' value */ -static int fluidbake_breakjob(void *UNUSED(customdata)) +static int fluidbake_breakjob(void *customdata) { - //FluidBakeJob *fb= (FluidBakeJob *)customdata; - //return *(fb->stop); + FluidBakeJob *fb= (FluidBakeJob *)customdata; + + if(fb->stop && *(fb->stop)) + return 1; /* this is not nice yet, need to make the jobs list template better * for identifying/acting upon various different jobs */ @@ -741,7 +743,7 @@ static int fluidbake_breakjob(void *UNUSED(customdata)) /* called by fluidbake, wmJob sends notifier */ static void fluidbake_updatejob(void *customdata, float progress) { - FluidBakeJob *fb= customdata; + FluidBakeJob *fb= (FluidBakeJob *)customdata; *(fb->do_update)= 1; *(fb->progress)= progress; @@ -749,7 +751,7 @@ static void fluidbake_updatejob(void *customdata, float progress) static void fluidbake_startjob(void *customdata, short *stop, short *do_update, float *progress) { - FluidBakeJob *fb= customdata; + FluidBakeJob *fb= (FluidBakeJob *)customdata; fb->stop= stop; fb->do_update = do_update; @@ -764,7 +766,7 @@ static void fluidbake_startjob(void *customdata, short *stop, short *do_update, static void fluidbake_endjob(void *customdata) { - FluidBakeJob *fb= customdata; + FluidBakeJob *fb= (FluidBakeJob *)customdata; if (fb->settings) { MEM_freeN(fb->settings); -- cgit v1.2.3 From 3a6158a8bf2b5518ef3a126b003debeba6bbea90 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Jul 2011 04:01:47 +0000 Subject: move mathutils into its own lib. --- source/blender/python/CMakeLists.txt | 1 + source/blender/python/SConscript | 11 +- source/blender/python/generic/CMakeLists.txt | 14 - source/blender/python/generic/mathutils.c | 384 ---- source/blender/python/generic/mathutils.h | 111 - source/blender/python/generic/mathutils_Color.c | 870 ------- source/blender/python/generic/mathutils_Color.h | 55 - source/blender/python/generic/mathutils_Euler.c | 725 ------ source/blender/python/generic/mathutils_Euler.h | 60 - source/blender/python/generic/mathutils_Matrix.c | 2042 ----------------- source/blender/python/generic/mathutils_Matrix.h | 63 - .../blender/python/generic/mathutils_Quaternion.c | 1164 ---------- .../blender/python/generic/mathutils_Quaternion.h | 55 - source/blender/python/generic/mathutils_Vector.c | 2411 -------------------- source/blender/python/generic/mathutils_Vector.h | 52 - source/blender/python/generic/mathutils_geometry.c | 1126 --------- source/blender/python/generic/mathutils_geometry.h | 43 - source/blender/python/intern/bpy.c | 4 +- source/blender/python/intern/bpy_interface.c | 8 +- source/blender/python/intern/bpy_rna.c | 2 +- source/blender/python/mathutils/CMakeLists.txt | 52 + source/blender/python/mathutils/mathutils.c | 384 ++++ source/blender/python/mathutils/mathutils.h | 111 + source/blender/python/mathutils/mathutils_Color.c | 870 +++++++ source/blender/python/mathutils/mathutils_Color.h | 55 + source/blender/python/mathutils/mathutils_Euler.c | 721 ++++++ source/blender/python/mathutils/mathutils_Euler.h | 60 + source/blender/python/mathutils/mathutils_Matrix.c | 2041 +++++++++++++++++ source/blender/python/mathutils/mathutils_Matrix.h | 63 + .../python/mathutils/mathutils_Quaternion.c | 1164 ++++++++++ .../python/mathutils/mathutils_Quaternion.h | 55 + source/blender/python/mathutils/mathutils_Vector.c | 2410 +++++++++++++++++++ source/blender/python/mathutils/mathutils_Vector.h | 52 + .../blender/python/mathutils/mathutils_geometry.c | 1135 +++++++++ .../blender/python/mathutils/mathutils_geometry.h | 43 + 35 files changed, 9233 insertions(+), 9184 deletions(-) delete mode 100644 source/blender/python/generic/mathutils.c delete mode 100644 source/blender/python/generic/mathutils.h delete mode 100644 source/blender/python/generic/mathutils_Color.c delete mode 100644 source/blender/python/generic/mathutils_Color.h delete mode 100644 source/blender/python/generic/mathutils_Euler.c delete mode 100644 source/blender/python/generic/mathutils_Euler.h delete mode 100644 source/blender/python/generic/mathutils_Matrix.c delete mode 100644 source/blender/python/generic/mathutils_Matrix.h delete mode 100644 source/blender/python/generic/mathutils_Quaternion.c delete mode 100644 source/blender/python/generic/mathutils_Quaternion.h delete mode 100644 source/blender/python/generic/mathutils_Vector.c delete mode 100644 source/blender/python/generic/mathutils_Vector.h delete mode 100644 source/blender/python/generic/mathutils_geometry.c delete mode 100644 source/blender/python/generic/mathutils_geometry.h create mode 100644 source/blender/python/mathutils/CMakeLists.txt create mode 100644 source/blender/python/mathutils/mathutils.c create mode 100644 source/blender/python/mathutils/mathutils.h create mode 100644 source/blender/python/mathutils/mathutils_Color.c create mode 100644 source/blender/python/mathutils/mathutils_Color.h create mode 100644 source/blender/python/mathutils/mathutils_Euler.c create mode 100644 source/blender/python/mathutils/mathutils_Euler.h create mode 100644 source/blender/python/mathutils/mathutils_Matrix.c create mode 100644 source/blender/python/mathutils/mathutils_Matrix.h create mode 100644 source/blender/python/mathutils/mathutils_Quaternion.c create mode 100644 source/blender/python/mathutils/mathutils_Quaternion.h create mode 100644 source/blender/python/mathutils/mathutils_Vector.c create mode 100644 source/blender/python/mathutils/mathutils_Vector.h create mode 100644 source/blender/python/mathutils/mathutils_geometry.c create mode 100644 source/blender/python/mathutils/mathutils_geometry.h (limited to 'source/blender') diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt index fe9e0307703..8071edb378f 100644 --- a/source/blender/python/CMakeLists.txt +++ b/source/blender/python/CMakeLists.txt @@ -18,3 +18,4 @@ add_subdirectory(intern) add_subdirectory(generic) +add_subdirectory(mathutils) diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index de6b859d259..3d17e113a8a 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -1,6 +1,6 @@ #!/usr/bin/python -# TODO, split into 2 files. +# TODO, split into 3 files. Import ('env') @@ -18,7 +18,14 @@ if is_debug: defs.append('_DEBUG') sources = env.Glob('generic/*.c') -env.BlenderLib( libname = 'bf_python_ext', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165]) # ketsji is 360 +env.BlenderLib( libname = 'bf_python_ext', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [363,165]) # ketsji is 360 + + +# mathutils +defs = [] + +sources = env.Glob('mathutils/*.c') +env.BlenderLib( libname = 'bf_python_mathutils', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [361,165]) # bpy diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt index 0889c77f9ad..794b31b4ed3 100644 --- a/source/blender/python/generic/CMakeLists.txt +++ b/source/blender/python/generic/CMakeLists.txt @@ -37,13 +37,6 @@ set(SRC bgl.c blf_py_api.c bpy_internal_import.c - mathutils.c - mathutils_Color.c - mathutils_Euler.c - mathutils_Matrix.c - mathutils_Quaternion.c - mathutils_Vector.c - mathutils_geometry.c noise_py_api.c py_capi_utils.c @@ -51,13 +44,6 @@ set(SRC bgl.h blf_py_api.h bpy_internal_import.h - mathutils.h - mathutils_Color.h - mathutils_Euler.h - mathutils_Matrix.h - mathutils_Quaternion.h - mathutils_Vector.h - mathutils_geometry.h noise_py_api.h py_capi_utils.h ) diff --git a/source/blender/python/generic/mathutils.c b/source/blender/python/generic/mathutils.c deleted file mode 100644 index 1ff33d5a6bb..00000000000 --- a/source/blender/python/generic/mathutils.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * $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 - -#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 BPyInit_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=BPyInit_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/generic/mathutils.h b/source/blender/python/generic/mathutils.h deleted file mode 100644 index 449708d1ac1..00000000000 --- a/source/blender/python/generic/mathutils.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * $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 BPyInit_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/generic/mathutils_Color.c b/source/blender/python/generic/mathutils_Color.c deleted file mode 100644 index d0c7ec72cea..00000000000 --- a/source/blender/python/generic/mathutils_Color.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * $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 - -#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/generic/mathutils_Color.h b/source/blender/python/generic/mathutils_Color.h deleted file mode 100644 index 0fc880363f4..00000000000 --- a/source/blender/python/generic/mathutils_Color.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * $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/generic/mathutils_Euler.c b/source/blender/python/generic/mathutils_Euler.c deleted file mode 100644 index a7d6d921d16..00000000000 --- a/source/blender/python/generic/mathutils_Euler.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - * $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 - -#include "mathutils.h" - -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#ifndef int32_t -#include "BLO_sys_types.h" -#endif - -#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(*((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/generic/mathutils_Euler.h b/source/blender/python/generic/mathutils_Euler.h deleted file mode 100644 index 849e16c2bb7..00000000000 --- a/source/blender/python/generic/mathutils_Euler.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * $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/generic/mathutils_Matrix.c b/source/blender/python/generic/mathutils_Matrix.c deleted file mode 100644 index c5ed1e32ee8..00000000000 --- a/source/blender/python/generic/mathutils_Matrix.c +++ /dev/null @@ -1,2042 +0,0 @@ -/* - * $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 - -#include "mathutils.h" - -#include "BLI_math.h" -#include "BLI_blenlib.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:: \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:: \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:: \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:: \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/generic/mathutils_Matrix.h b/source/blender/python/generic/mathutils_Matrix.h deleted file mode 100644 index aa736d1e959..00000000000 --- a/source/blender/python/generic/mathutils_Matrix.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * $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/generic/mathutils_Quaternion.c b/source/blender/python/generic/mathutils_Quaternion.c deleted file mode 100644 index 3b05b9a250b..00000000000 --- a/source/blender/python/generic/mathutils_Quaternion.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* - * $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 - -#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/generic/mathutils_Quaternion.h b/source/blender/python/generic/mathutils_Quaternion.h deleted file mode 100644 index d606621390a..00000000000 --- a/source/blender/python/generic/mathutils_Quaternion.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * $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/generic/mathutils_Vector.c b/source/blender/python/generic/mathutils_Vector.c deleted file mode 100644 index a834e8f2ba4..00000000000 --- a/source/blender/python/generic/mathutils_Vector.c +++ /dev/null @@ -1,2411 +0,0 @@ -/* - * $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 - -#include "mathutils.h" - -#include "BLI_blenlib.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; isize != 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)<= 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)<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)<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)<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 "." */ - "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/generic/mathutils_Vector.h b/source/blender/python/generic/mathutils_Vector.h deleted file mode 100644 index 0ede836ce44..00000000000 --- a/source/blender/python/generic/mathutils_Vector.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * $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/generic/mathutils_geometry.c b/source/blender/python/generic/mathutils_geometry.c deleted file mode 100644 index d2724f6603e..00000000000 --- a/source/blender/python/generic/mathutils_geometry.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * $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 - -#include "mathutils_geometry.h" - -/* Used for PolyFill */ -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" -#include "BLI_boxpack2d.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" - -#include "BKE_displist.h" - -#include "BKE_curve.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; - } -} - -/*----------------------------------geometry.PolyFill() -------------------*/ -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; indexvec[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; -} - -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)); -} - -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; -} - -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; isize != 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); -} - -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}, - {"interpolate_bezier", (PyCFunction) M_Geometry_interpolate_bezier, METH_VARARGS, M_Geometry_interpolate_bezier_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}, - {"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}, - {"barycentric_transform", (PyCFunction) M_Geometry_barycentric_transform, METH_VARARGS, M_Geometry_barycentric_transform_doc}, - {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 BPyInit_mathutils_geometry(void) -{ - PyObject *submodule= PyModule_Create(&M_Geometry_module_def); - return submodule; -} diff --git a/source/blender/python/generic/mathutils_geometry.h b/source/blender/python/generic/mathutils_geometry.h deleted file mode 100644 index 929b8cc8d75..00000000000 --- a/source/blender/python/generic/mathutils_geometry.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * $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 BPyInit_mathutils_geometry(void); - -#endif /* MATHUTILS_GEOMETRY_H */ diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index fb4c285a458..3f637feadf7 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -55,10 +55,10 @@ #include "MEM_guardedalloc.h" /* external util modules */ -#include "../generic/mathutils.h" +#include "../generic/IDProp.h" #include "../generic/bgl.h" #include "../generic/blf_py_api.h" -#include "../generic/IDProp.h" +#include "../mathutils/mathutils.h" PyObject *bpy_package_py= NULL; diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index f091a511e93..8bd6e6c611c 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -66,10 +66,10 @@ #include "../generic/py_capi_utils.h" /* inittab initialization functions */ -#include "../generic/noise_py_api.h" -#include "../generic/mathutils.h" #include "../generic/bgl.h" #include "../generic/blf_py_api.h" +#include "../generic/noise_py_api.h" +#include "../mathutils/mathutils.h" /* for internal use, when starting and ending python scripts */ @@ -175,8 +175,8 @@ extern PyObject *AUD_initPython(void); static struct _inittab bpy_internal_modules[]= { {(char *)"noise", BPyInit_noise}, - {(char *)"mathutils", BPyInit_mathutils}, -// {(char *)"mathutils.geometry", BPyInit_mathutils_geometry}, + {(char *)"mathutils", PyInit_mathutils}, +// {(char *)"mathutils.geometry", PyInit_mathutils_geometry}, {(char *)"bgl", BPyInit_bgl}, {(char *)"blf", BPyInit_blf}, #ifdef WITH_AUDASPACE diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 4f6edb02a7c..61fc2e483b1 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -346,7 +346,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb static int deferred_register_prop(StructRNA *srna, PyObject *key, PyObject *item); #ifdef USE_MATHUTILS -#include "../generic/mathutils.h" /* so we can have mathutils callbacks */ +#include "../mathutils/mathutils.h" /* so we can have mathutils callbacks */ static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, Py_ssize_t start, Py_ssize_t stop, Py_ssize_t length); static short pyrna_rotation_euler_order_get(PointerRNA *ptr, PropertyRNA **prop_eul_order, short order_fallback); 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 + +#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 + +#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 + +#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 + +#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:: \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:: \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:: \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:: \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 + +#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 + +#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; isize != 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)<= 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)<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)<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)<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 "." */ + "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 + +#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; iverts 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; indexvec[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 */ -- cgit v1.2.3 From 7984e338db93c7d5d276f1cb8a6a468ccd4446a7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Jul 2011 10:10:25 +0000 Subject: fix for linking on mingw/scons with recent changes to mathutils --- source/blender/python/SConscript | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript index 3d17e113a8a..dec0de4a6ab 100644 --- a/source/blender/python/SConscript +++ b/source/blender/python/SConscript @@ -25,7 +25,7 @@ env.BlenderLib( libname = 'bf_python_ext', sources = Split(sources), includes = defs = [] sources = env.Glob('mathutils/*.c') -env.BlenderLib( libname = 'bf_python_mathutils', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [361,165]) +env.BlenderLib( libname = 'bf_python_mathutils', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165]) # bpy -- cgit v1.2.3 From 729498ab2da989d0bfbba02c1b1a6bc9f6964b1c Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Fri, 15 Jul 2011 13:32:02 +0000 Subject: Fix for [#26712] Particle group instance 'Use Count' value gets reset on file-load. * New object pointers can't be loaded properly for library linked groups, so the weight groups now store an index to the group objects at save time. This index is used at load time to set the objects without relying on the old pointers. * If the library linked group is modified the indices can be wrong, but this can't really be avoided easily as there's no way to relate objects in a linked group between loads. --- source/blender/blenloader/intern/readfile.c | 35 +++++++++++++++++++++++++--- source/blender/blenloader/intern/writefile.c | 11 ++++++++- source/blender/makesdna/DNA_particle_types.h | 3 ++- 3 files changed, 44 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 2402106306e..ab30d92f03e 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -75,6 +75,7 @@ #include "DNA_node_types.h" #include "DNA_object_fluidsim.h" // NT #include "DNA_packedFile_types.h" +#include "DNA_particle_types.h" #include "DNA_property_types.h" #include "DNA_text_types.h" #include "DNA_view3d_types.h" @@ -3161,9 +3162,37 @@ static void lib_link_particlesettings(FileData *fd, Main *main) if(part->effector_weights) part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group); - dw = part->dupliweights.first; - for(; dw; dw=dw->next) - dw->ob = newlibadr(fd, part->id.lib, dw->ob); + if(part->dupliweights.first) { + int index_ok = 0; + /* check for old files without indices (all indexes 0) */ + dw = part->dupliweights.first; + if(part->dupliweights.first == part->dupliweights.last) { + /* special case for only one object in the group */ + index_ok = 1; + } + else { + for(; dw; dw=dw->next) { + if(dw->index > 0) { + index_ok = 1; + break; + } + } + } + + if(index_ok) { + /* if we have indexes, let's use them */ + dw = part->dupliweights.first; + for(; dw; dw=dw->next) { + GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index); + dw->ob = go ? go->ob : NULL; + } + } + else { + /* otherwise try to get objects from own library (won't work on library linked groups) */ + for(; dw; dw=dw->next) + dw->ob = newlibadr(fd, part->id.lib, dw->ob); + } + } if(part->boids) { BoidState *state = part->boids->states.first; diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ba4395ace9c..bf86527b9d3 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -837,6 +837,7 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) { ParticleSettings *part; ParticleDupliWeight *dw; + GroupObject *go; int a; part= idbase->first; @@ -851,8 +852,16 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights); dw = part->dupliweights.first; - for(; dw; dw=dw->next) + for(; dw; dw=dw->next) { + /* update indices */ + dw->index = 0; + go = part->dup_group->gobject.first; + while(go && go->ob != dw->ob) { + go=go->next; + dw->index++; + } writestruct(wd, DATA, "ParticleDupliWeight", 1, dw); + } if(part->boids && part->phystype == PART_PHYS_BOIDS) { BoidState *state = part->boids->states.first; diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index aace8156e9d..69ee530c0b6 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -89,7 +89,8 @@ typedef struct ParticleDupliWeight { struct ParticleDupliWeight *next, *prev; struct Object *ob; short count; - short flag, rt[2]; + short flag; + short index, rt; /* only updated on file save and used on file load */ } ParticleDupliWeight; typedef struct ParticleData { -- cgit v1.2.3 From 4ca88c99be18651cc96c549afde8dc190120b052 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Jul 2011 23:55:20 +0000 Subject: fix for crash with edit armature buttons when no bones were selected (uninitialized pointer) --- source/blender/editors/space_view3d/view3d_buttons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index ef7ada85843..6e03866153f 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -967,7 +967,7 @@ static void v3d_editarmature_buts(uiLayout *layout, Object *ob) ebone= arm->act_edbone; if (!ebone || (ebone->layer & arm->layer)==0) { - uiItemL(col, "Nothing selected", ICON_NONE); + uiItemL(layout, "Nothing selected", ICON_NONE); return; } // row= uiLayoutRow(layout, 0); -- cgit v1.2.3 From d54a014963dd3a90972e0bf9d83df76aef08bb25 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sat, 16 Jul 2011 17:55:46 +0000 Subject: Fixed crash of multires baker when baking from sculpt mode. Incorrect low level was used for this case -- it should be sculpt level, not preview level. Thanks to Morten Mikkelsen to point on this bug :) --- source/blender/editors/object/object_bake.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 57f6c9de88e..bdd911d68ee 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -966,9 +966,10 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0); Mesh *me= (Mesh*)ob->data; - *lvl= mmd->lvl; + if(ob->mode==OB_MODE_SCULPT) *lvl= mmd->sculptlvl; + else *lvl= mmd->lvl; - if(mmd->lvl==0) { + if(*lvl==0) { DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob); dm= CDDM_copy(tmp_dm); tmp_dm->release(tmp_dm); @@ -976,7 +977,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l MultiresModifierData tmp_mmd= *mmd; DerivedMesh *cddm= CDDM_from_mesh(me, ob); - tmp_mmd.lvl= mmd->lvl; + tmp_mmd.lvl= *lvl; dm= multires_dm_create_from_derived(&tmp_mmd, 1, cddm, ob, 0, 0); cddm->release(cddm); } -- cgit v1.2.3 From 410c5e3cd284eba6b17c79042b161eaa9efe6e71 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 16 Jul 2011 23:01:14 +0000 Subject: cmake source definitions: remove missing includes and use more strict formatting. --- source/blender/blenfont/CMakeLists.txt | 4 +- source/blender/blenkernel/CMakeLists.txt | 51 ++++++++++++++++------ source/blender/blenlib/CMakeLists.txt | 4 +- source/blender/blenpluginapi/CMakeLists.txt | 4 +- source/blender/editors/render/CMakeLists.txt | 8 +++- source/blender/editors/space_script/CMakeLists.txt | 8 +++- source/blender/editors/space_text/CMakeLists.txt | 8 +++- source/blender/editors/space_view3d/CMakeLists.txt | 4 +- source/blender/imbuf/CMakeLists.txt | 28 +++++++++--- source/blender/imbuf/intern/dds/CMakeLists.txt | 1 - source/blender/imbuf/intern/openexr/CMakeLists.txt | 5 ++- source/blender/makesrna/intern/CMakeLists.txt | 8 +++- source/blender/modifiers/CMakeLists.txt | 7 ++- source/blender/nodes/CMakeLists.txt | 8 +++- source/blender/python/intern/CMakeLists.txt | 3 -- source/blender/quicktime/CMakeLists.txt | 13 +++--- source/blender/render/CMakeLists.txt | 8 +++- source/blender/windowmanager/CMakeLists.txt | 16 +++++-- 18 files changed, 132 insertions(+), 56 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index b915764c1bb..0258a41fb56 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -50,7 +50,9 @@ set(SRC ) if(WITH_INTERNATIONAL) - list(APPEND INC_SYS ${GETTEXT_INC}) + list(APPEND INC_SYS + ${GETTEXT_INC} + ) add_definitions(-DINTERNATIONAL) endif() diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 92c50242e74..a3c3357508f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -32,8 +32,10 @@ endif() set(INC . ../avi + ../blenfont ../blenlib ../blenloader + ../editors/include ../gpu ../ikplugin ../imbuf @@ -41,18 +43,19 @@ set(INC ../makesrna ../modifiers ../nodes - ../editors/include ../render/extern/include - ../../../intern/bsp/extern ../blenfont + ../../../intern/bsp/extern ../../../intern/decimation/extern ../../../intern/elbeem/extern ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/memutil + ../../../intern/mikktspace ../../../intern/opennl/extern ../../../intern/smoke/extern - ../../../intern/mikktspace - ../../../source/blender/windowmanager # XXX - BAD LEVEL CALL WM_api.h + + # XXX - BAD LEVEL CALL WM_api.h + ../../../source/blender/windowmanager ) set(INC_SYS @@ -243,12 +246,16 @@ if(WITH_AUDASPACE) endif() if(WITH_BULLET) - list(APPEND INC ../../../extern/bullet2/src) + list(APPEND INC + ../../../extern/bullet2/src + ) add_definitions(-DUSE_BULLET) endif() if(WITH_MOD_CLOTH_ELTOPO) - list(APPEND INC ../../../extern/eltopo) + list(APPEND INC + ../../../extern/eltopo + ) add_definitions(-DWITH_ELTOPO) endif() @@ -277,20 +284,32 @@ if(WITH_IMAGE_HDR) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC + ../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() if(WITH_CODEC_FFMPEG) - list(APPEND INC ../../../intern/ffmpeg) - list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS}) + list(APPEND INC + ../../../intern/ffmpeg + ) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_FFMPEG) endif() if(WITH_PYTHON) - list(APPEND INC ../python) - list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS}) + list(APPEND INC + ../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) add_definitions(-DWITH_PYTHON) if(WITH_PYTHON_SECURITY) @@ -315,12 +334,16 @@ if(WITH_JACK) endif() if(WITH_LZO) - list(APPEND INC_SYS ../../../extern/lzo/minilzo) + list(APPEND INC_SYS + ../../../extern/lzo/minilzo + ) add_definitions(-DWITH_LZO) endif() if(WITH_LZMA) - list(APPEND INC_SYS ../../../extern/lzma) + list(APPEND INC_SYS + ../../../extern/lzma + ) add_definitions(-DWITH_LZMA) endif() diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 2e05ac7892b..de7695b63cf 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -138,7 +138,9 @@ set(SRC ) if(WITH_BINRELOC) - list(APPEND INC_SYS "${BINRELOC_INCLUDE_DIRS}") + list(APPEND INC_SYS + ${BINRELOC_INCLUDE_DIRS} + ) add_definitions(-DWITH_BINRELOC) endif() diff --git a/source/blender/blenpluginapi/CMakeLists.txt b/source/blender/blenpluginapi/CMakeLists.txt index a5af15d7f55..193e40147e1 100644 --- a/source/blender/blenpluginapi/CMakeLists.txt +++ b/source/blender/blenpluginapi/CMakeLists.txt @@ -50,7 +50,9 @@ set(SRC ) if(WITH_CODEC_QUICKTIME) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 7e497200710..cf6c4290ee0 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -51,8 +51,12 @@ set(SRC ) if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC + ../../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt index 1aed177eed1..1884852d3ad 100644 --- a/source/blender/editors/space_script/CMakeLists.txt +++ b/source/blender/editors/space_script/CMakeLists.txt @@ -44,8 +44,12 @@ set(SRC ) if(WITH_PYTHON) - list(APPEND INC ../../python) - list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS}) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) add_definitions(-DWITH_PYTHON) endif() diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 0c174225a58..145da6c9aaa 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -46,8 +46,12 @@ set(SRC ) if(WITH_PYTHON) - list(APPEND INC ../../python) - list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS}) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) add_definitions(-DWITH_PYTHON) endif() diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index 0a12a28af8d..e83e51aaa4f 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -61,7 +61,9 @@ set(SRC ) if(WITH_GAMEENGINE) - list(APPEND INC ../../../../source/gameengine/BlenderRoutines) + list(APPEND INC + ../../../../source/gameengine/BlenderRoutines + ) add_definitions(-DWITH_GAMEENGINE) endif() diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index c9a8f62a197..1517432f614 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -113,29 +113,43 @@ if(WITH_IMAGE_OPENEXR) endif() if(WITH_IMAGE_TIFF) - list(APPEND INC_SYS ${TIFF_INCLUDE_DIR}) + list(APPEND INC_SYS + ${TIFF_INCLUDE_DIR} + ) add_definitions(-DWITH_TIFF) endif() if(WITH_IMAGE_OPENJPEG) - list(APPEND INC_SYS ${OPENJPEG_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${OPENJPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_OPENJPEG) endif() if(WITH_IMAGE_REDCODE) - list(APPEND INC_SYS ${REDCODE_INC}) + list(APPEND INC_SYS + ${REDCODE_INC} + ) add_definitions(-DWITH_REDCODE) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC + ../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() if(WITH_CODEC_FFMPEG) - list(APPEND INC ../../../intern/ffmpeg) - list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS}) + list(APPEND INC + ../../../intern/ffmpeg + ) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_FFMPEG) endif() diff --git a/source/blender/imbuf/intern/dds/CMakeLists.txt b/source/blender/imbuf/intern/dds/CMakeLists.txt index fd2b94547b4..db3c85da884 100644 --- a/source/blender/imbuf/intern/dds/CMakeLists.txt +++ b/source/blender/imbuf/intern/dds/CMakeLists.txt @@ -28,7 +28,6 @@ set(INC . .. ../.. - intern/include ../../../blenlib ../../../blenkernel ../../../makesdna diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt index 9ca4dff5bc8..ca638b8356e 100644 --- a/source/blender/imbuf/intern/openexr/CMakeLists.txt +++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt @@ -30,7 +30,6 @@ set(INC ../.. ../../../blenkernel ../../../blenlib - intern/include ../../../../../intern/guardedalloc ../../../makesdna ) @@ -44,7 +43,9 @@ set(SRC ) if(WITH_IMAGE_OPENEXR) - list(APPEND INC_SYS ${OPENEXR_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${OPENEXR_INCLUDE_DIRS} + ) add_definitions(-DWITH_OPENEXR) endif() diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 1db29855c18..c9865bf3df4 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -176,12 +176,16 @@ if(WITH_AUDASPACE) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../../quicktime) + list(APPEND INC + ../../quicktime + ) add_definitions(-DWITH_QUICKTIME) endif() if(WITH_CODEC_FFMPEG) - list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_FFMPEG) endif() diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index 348e2a0ec1d..ba5a7ac64bc 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -25,7 +25,8 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - . ./intern + . + ./intern ../blenlib ../blenloader ../makesdna @@ -98,7 +99,9 @@ endif() if(WITH_MOD_DECIMATE) add_definitions(-DWITH_MOD_DECIMATE) - list(APPEND INC ../../../intern/decimation/extern) + list(APPEND INC + ../../../intern/decimation/extern + ) endif() if(NOT WITH_MOD_FLUID) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d2b58d61112..c3bd37c18ee 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -152,8 +152,12 @@ set(SRC ) if(WITH_PYTHON) - list(APPEND INC ../python) - list(APPEND INC_SYS ${PYTHON_INCLUDE_DIRS}) + list(APPEND INC + ../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) add_definitions(-DWITH_PYTHON) endif() diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 287ba45a1cf..a1eb9585e83 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -88,9 +88,6 @@ if(WITH_PYTHON_SAFETY) endif() if(WITH_AUDASPACE) - list(APPEND INC - ../../../intern/audaspace/intern - ) add_definitions(-DWITH_AUDASPACE) endif() diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/quicktime/CMakeLists.txt index 6ce4954f053..6e72f053af7 100644 --- a/source/blender/quicktime/CMakeLists.txt +++ b/source/blender/quicktime/CMakeLists.txt @@ -26,17 +26,16 @@ set(INC . - ../quicktime - ../makesdna - ../makesrna - ../blenlib - ../blenkernel ../avi + ../blenkernel + ../blenlib + ../blenloader ../imbuf ../imbuf/intern - ../blenloader + ../makesdna + ../makesrna + ../quicktime ../render/extern/include - ../include ../windowmanager ../../../intern/guardedalloc ) diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 003f0b839f8..9adebffc55e 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -125,8 +125,12 @@ if(WITH_MOD_SMOKE) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC + ../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index f9c1d800c02..c815b4aad2f 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -89,18 +89,26 @@ if(WITH_OPENCOLLADA) endif() if(WITH_CODEC_QUICKTIME) - list(APPEND INC ../quicktime) - list(APPEND INC_SYS ${QUICKTIME_INCLUDE_DIRS}) + list(APPEND INC + ../quicktime + ) + list(APPEND INC_SYS + ${QUICKTIME_INCLUDE_DIRS} + ) add_definitions(-DWITH_QUICKTIME) endif() if(WITH_CODEC_FFMPEG) - list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) add_definitions(-DWITH_FFMPEG) endif() if(WITH_PYTHON) - list(APPEND INC ../python) + list(APPEND INC + ../python + ) add_definitions(-DWITH_PYTHON) if(WITH_PYTHON_SECURITY) -- cgit v1.2.3 From c9ad903af2b70013eaab85567e3affa8bcc6d172 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sun, 17 Jul 2011 08:38:04 +0000 Subject: Added notifier listener for node editor. Now it behaves right on playback: - Starting playback "Anim Player" button appears on header. It used to appear only on mouse hover before. - Stopping playback triggers refresh on compositor, so actual result would be visible if image sequence/movie is used in nodes. --- source/blender/editors/space_node/space_node.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 029c55d0851..3c5f4a163a2 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -228,6 +228,13 @@ static void node_area_listener(ScrArea *sa, wmNotifier *wmn) else if (wmn->action == NA_SELECTED) ED_area_tag_redraw(sa); break; + case NC_SCREEN: + switch(wmn->data) { + case ND_ANIMPLAY: + ED_area_tag_refresh(sa); + break; + } + break; case NC_IMAGE: if (wmn->action == NA_EDITED) { -- cgit v1.2.3 From 5792bd7cc74581a5ac37325207c1cc6a338be9c7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 17 Jul 2011 09:11:13 +0000 Subject: cmake: cleanup include paths, some duplicates and going up some unneeded dirs. --- source/blender/avi/CMakeLists.txt | 2 +- source/blender/blenfont/CMakeLists.txt | 4 ++-- source/blender/blenkernel/CMakeLists.txt | 2 +- source/blender/blenlib/CMakeLists.txt | 2 +- source/blender/blenloader/CMakeLists.txt | 2 +- source/blender/blenpluginapi/CMakeLists.txt | 2 +- source/blender/collada/CMakeLists.txt | 6 +++--- source/blender/editors/animation/CMakeLists.txt | 2 +- source/blender/editors/armature/CMakeLists.txt | 2 +- source/blender/editors/curve/CMakeLists.txt | 2 +- source/blender/editors/gpencil/CMakeLists.txt | 2 +- source/blender/editors/interface/CMakeLists.txt | 2 +- source/blender/editors/mesh/CMakeLists.txt | 4 ++-- source/blender/editors/metaball/CMakeLists.txt | 2 +- source/blender/editors/object/CMakeLists.txt | 4 ++-- source/blender/editors/physics/CMakeLists.txt | 2 +- source/blender/editors/screen/CMakeLists.txt | 2 +- source/blender/editors/sculpt_paint/CMakeLists.txt | 6 +++--- source/blender/editors/sound/CMakeLists.txt | 2 +- source/blender/editors/space_action/CMakeLists.txt | 2 +- source/blender/editors/space_api/CMakeLists.txt | 2 +- source/blender/editors/space_buttons/CMakeLists.txt | 2 +- source/blender/editors/space_file/CMakeLists.txt | 2 +- source/blender/editors/space_graph/CMakeLists.txt | 2 +- source/blender/editors/space_image/CMakeLists.txt | 4 ++-- source/blender/editors/space_info/CMakeLists.txt | 2 +- source/blender/editors/space_logic/CMakeLists.txt | 4 ++-- source/blender/editors/space_nla/CMakeLists.txt | 2 +- source/blender/editors/space_node/CMakeLists.txt | 4 ++-- source/blender/editors/space_outliner/CMakeLists.txt | 2 +- source/blender/editors/space_script/CMakeLists.txt | 2 +- source/blender/editors/space_sequencer/CMakeLists.txt | 2 +- source/blender/editors/space_sound/CMakeLists.txt | 2 +- source/blender/editors/space_text/CMakeLists.txt | 2 +- source/blender/editors/space_time/CMakeLists.txt | 2 +- source/blender/editors/space_userpref/CMakeLists.txt | 2 +- source/blender/editors/space_view3d/CMakeLists.txt | 6 +++--- source/blender/editors/transform/CMakeLists.txt | 2 +- source/blender/editors/util/CMakeLists.txt | 2 +- source/blender/editors/uvedit/CMakeLists.txt | 2 +- source/blender/gpu/CMakeLists.txt | 2 +- source/blender/ikplugin/CMakeLists.txt | 4 ++-- source/blender/imbuf/CMakeLists.txt | 4 ++-- source/blender/imbuf/intern/cineon/CMakeLists.txt | 2 +- source/blender/imbuf/intern/dds/CMakeLists.txt | 2 +- source/blender/imbuf/intern/openexr/CMakeLists.txt | 2 +- source/blender/modifiers/CMakeLists.txt | 8 ++++---- source/blender/python/generic/CMakeLists.txt | 4 ++-- source/blender/python/intern/CMakeLists.txt | 6 +++--- source/blender/quicktime/CMakeLists.txt | 1 - source/blender/render/CMakeLists.txt | 10 +++++----- source/blender/windowmanager/CMakeLists.txt | 18 +++++++++--------- 52 files changed, 83 insertions(+), 84 deletions(-) (limited to 'source/blender') diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt index bae61fd678b..0fd6435ec4e 100644 --- a/source/blender/avi/CMakeLists.txt +++ b/source/blender/avi/CMakeLists.txt @@ -26,8 +26,8 @@ set(INC . - ../../../intern/guardedalloc ../blenlib + ../../../intern/guardedalloc ) set(INC_SYS diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 0258a41fb56..82099d4f125 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -24,10 +24,10 @@ set(INC . + ../blenkernel ../blenlib - ../makesdna ../editors/include - ../blenkernel + ../makesdna ../../../intern/guardedalloc ) diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index a3c3357508f..9a384c40e24 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -55,7 +55,7 @@ set(INC ../../../intern/smoke/extern # XXX - BAD LEVEL CALL WM_api.h - ../../../source/blender/windowmanager + ../windowmanager ) set(INC_SYS diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index de7695b63cf..b4fc983008c 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -26,10 +26,10 @@ set(INC . - ../makesdna ../blenkernel ../blenloader ../gpu + ../makesdna ../../../intern/ghost ../../../intern/guardedalloc ) diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 312a6546e22..be15b191c8a 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -26,8 +26,8 @@ set(INC . - ../blenlib ../blenkernel + ../blenlib ../makesdna ../makesrna ../render/extern/include diff --git a/source/blender/blenpluginapi/CMakeLists.txt b/source/blender/blenpluginapi/CMakeLists.txt index 193e40147e1..9d398291b85 100644 --- a/source/blender/blenpluginapi/CMakeLists.txt +++ b/source/blender/blenpluginapi/CMakeLists.txt @@ -28,9 +28,9 @@ set(INC . .. ../blenlib + ../blenloader ../imbuf ../makesdna - ../blenloader ../../../intern/guardedalloc ) diff --git a/source/blender/collada/CMakeLists.txt b/source/blender/collada/CMakeLists.txt index 07da532146f..e2a68d19682 100644 --- a/source/blender/collada/CMakeLists.txt +++ b/source/blender/collada/CMakeLists.txt @@ -28,13 +28,13 @@ remove_strict_flags() set(INC . - ../blenlib ../blenkernel + ../blenlib ../blenloader - ../windowmanager + ../editors/include ../makesdna ../makesrna - ../editors/include + ../windowmanager ../../../intern/guardedalloc ) diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt index a3c1d035d9b..83fe91d6f76 100644 --- a/source/blender/editors/animation/CMakeLists.txt +++ b/source/blender/editors/animation/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt index 2db6e278460..9a44525611a 100644 --- a/source/blender/editors/armature/CMakeLists.txt +++ b/source/blender/editors/armature/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/curve/CMakeLists.txt b/source/blender/editors/curve/CMakeLists.txt index dfc7e336e84..9bad02eca1f 100644 --- a/source/blender/editors/curve/CMakeLists.txt +++ b/source/blender/editors/curve/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 352960d285a..7a2f196fd6d 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 6dd7af70e33..cc4c1eaa21c 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -23,8 +23,8 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index bd8789b9eef..02a25a2a122 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -22,13 +22,13 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/metaball/CMakeLists.txt b/source/blender/editors/metaball/CMakeLists.txt index 690a8ec2fcb..76561b12183 100644 --- a/source/blender/editors/metaball/CMakeLists.txt +++ b/source/blender/editors/metaball/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../render/extern/include diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 4d50b78b7a1..14b40d55f11 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -22,16 +22,16 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../gpu ../../ikplugin ../../imbuf ../../makesdna ../../makesrna ../../python - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt index 1badccffe3b..f32b23cd3ee 100644 --- a/source/blender/editors/physics/CMakeLists.txt +++ b/source/blender/editors/physics/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 54341257692..4282110901b 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -23,8 +23,8 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 6ecbc9c5eec..94e08a020f6 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -22,14 +22,14 @@ set(INC ../include ../../blenkernel + ../../blenlib ../../blenloader - ../../imbuf ../../gpu - ../../blenlib + ../../imbuf ../../makesdna ../../makesrna - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/sound/CMakeLists.txt b/source/blender/editors/sound/CMakeLists.txt index 55af283b5de..f66288812ad 100644 --- a/source/blender/editors/sound/CMakeLists.txt +++ b/source/blender/editors/sound/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt index 6789556aa2b..edebaa8273a 100644 --- a/source/blender/editors/space_action/CMakeLists.txt +++ b/source/blender/editors/space_action/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index c2dc2582c82..4cbb290be76 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt index 0a4f251e46f..631e2adea34 100644 --- a/source/blender/editors/space_buttons/CMakeLists.txt +++ b/source/blender/editors/space_buttons/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index afa746ea359..4aa6cdbcf2f 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -28,8 +28,8 @@ set(INC ../../imbuf ../../makesdna ../../makesrna - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt index b7cde90546c..80205ad5564 100644 --- a/source/blender/editors/space_graph/CMakeLists.txt +++ b/source/blender/editors/space_graph/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 7c2d7ffb47b..0d4408faf49 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -23,13 +23,13 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index c6ed1b7bac7..22347df93a3 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -23,8 +23,8 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/space_logic/CMakeLists.txt b/source/blender/editors/space_logic/CMakeLists.txt index cd24cb5e5d0..44471902040 100644 --- a/source/blender/editors/space_logic/CMakeLists.txt +++ b/source/blender/editors/space_logic/CMakeLists.txt @@ -21,13 +21,13 @@ set(INC ../include + ../interface ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager - ../../editors/interface ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt index 1bf04f4dc37..b05d157365d 100644 --- a/source/blender/editors/space_nla/CMakeLists.txt +++ b/source/blender/editors/space_nla/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 9172bc4e9eb..dcd6bcd3403 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -23,14 +23,14 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna ../../nodes - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ../../../../intern/opennl/extern ) diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index c05350c256f..4194d463e10 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt index 1884852d3ad..9d3bd4a67aa 100644 --- a/source/blender/editors/space_script/CMakeLists.txt +++ b/source/blender/editors/space_script/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 71a4cfca868..9ce5f8e5279 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/space_sound/CMakeLists.txt b/source/blender/editors/space_sound/CMakeLists.txt index 367d07c0c0b..870065966cc 100644 --- a/source/blender/editors/space_sound/CMakeLists.txt +++ b/source/blender/editors/space_sound/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt index 145da6c9aaa..acf00d205a6 100644 --- a/source/blender/editors/space_text/CMakeLists.txt +++ b/source/blender/editors/space_text/CMakeLists.txt @@ -23,8 +23,8 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_time/CMakeLists.txt b/source/blender/editors/space_time/CMakeLists.txt index 79081c7cfd4..758d1e629f9 100644 --- a/source/blender/editors/space_time/CMakeLists.txt +++ b/source/blender/editors/space_time/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_userpref/CMakeLists.txt b/source/blender/editors/space_userpref/CMakeLists.txt index 656a5d2f0ef..43ac90dce94 100644 --- a/source/blender/editors/space_userpref/CMakeLists.txt +++ b/source/blender/editors/space_userpref/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index e83e51aaa4f..c6e936606c8 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -23,14 +23,14 @@ set(INC ../include ../../blenfont ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../gpu ../../imbuf ../../makesdna ../../makesrna - ../../windowmanager ../../render/extern/include + ../../windowmanager ../../../../intern/guardedalloc ../../../../intern/smoke/extern ) @@ -62,7 +62,7 @@ set(SRC if(WITH_GAMEENGINE) list(APPEND INC - ../../../../source/gameengine/BlenderRoutines + ../../../gameengine/BlenderRoutines ) add_definitions(-DWITH_GAMEENGINE) endif() diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 8eb8d538396..283b09f42e4 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 8e5415945c7..72f13c14f5d 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 11e1703d84c..552e1b60154 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -22,8 +22,8 @@ set(INC ../include ../../blenkernel - ../../blenloader ../../blenlib + ../../blenloader ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 76e347270ba..8f575dfb50b 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -26,8 +26,8 @@ set(INC . - ../blenlib ../blenkernel + ../blenlib ../blenloader ../imbuf ../makesdna diff --git a/source/blender/ikplugin/CMakeLists.txt b/source/blender/ikplugin/CMakeLists.txt index da5c2f69635..dc637aedd6d 100644 --- a/source/blender/ikplugin/CMakeLists.txt +++ b/source/blender/ikplugin/CMakeLists.txt @@ -25,10 +25,10 @@ # ***** END GPL LICENSE BLOCK ***** set(INC + . + ../blenkernel ../blenlib ../makesdna - ../blenkernel - ../ikplugin ../../../intern/guardedalloc ../../../intern/iksolver/extern ) diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index 1517432f614..18b5eff5c73 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -32,12 +32,12 @@ endif() set(INC . ../avi - ../blenlib ../blenkernel + ../blenlib ../blenloader ../makesdna - ../../../intern/memutil ../../../intern/guardedalloc + ../../../intern/memutil ) set(INC_SYS diff --git a/source/blender/imbuf/intern/cineon/CMakeLists.txt b/source/blender/imbuf/intern/cineon/CMakeLists.txt index 079f34af773..4f7f20beecf 100644 --- a/source/blender/imbuf/intern/cineon/CMakeLists.txt +++ b/source/blender/imbuf/intern/cineon/CMakeLists.txt @@ -29,8 +29,8 @@ set(INC .. ../.. ../../../blenkernel - ../../../blenloader ../../../blenlib + ../../../blenloader ../../../makesdna ../../../../../intern/guardedalloc ) diff --git a/source/blender/imbuf/intern/dds/CMakeLists.txt b/source/blender/imbuf/intern/dds/CMakeLists.txt index db3c85da884..53822b830f7 100644 --- a/source/blender/imbuf/intern/dds/CMakeLists.txt +++ b/source/blender/imbuf/intern/dds/CMakeLists.txt @@ -28,8 +28,8 @@ set(INC . .. ../.. - ../../../blenlib ../../../blenkernel + ../../../blenlib ../../../makesdna ../../../../../intern/guardedalloc ) diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt index ca638b8356e..3be5219ae44 100644 --- a/source/blender/imbuf/intern/openexr/CMakeLists.txt +++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt @@ -30,8 +30,8 @@ set(INC ../.. ../../../blenkernel ../../../blenlib - ../../../../../intern/guardedalloc ../../../makesdna + ../../../../../intern/guardedalloc ) set(INC_SYS diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index ba5a7ac64bc..d1f153265ac 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -26,15 +26,15 @@ set(INC . - ./intern + intern + ../blenkernel + ../blenkernel/intern ../blenlib ../blenloader ../makesdna - ../blenkernel - ../blenkernel/intern ../render/extern/include - ../../../intern/guardedalloc ../../../intern/elbeem/extern + ../../../intern/guardedalloc ) set(INC_SYS diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt index 794b31b4ed3..8dfbf476995 100644 --- a/source/blender/python/generic/CMakeLists.txt +++ b/source/blender/python/generic/CMakeLists.txt @@ -20,10 +20,10 @@ set(INC . - ../../blenlib - ../../makesdna ../../blenkernel + ../../blenlib ../../blenloader + ../../makesdna ../../../../intern/guardedalloc ) diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index a1eb9585e83..93a4b3ec269 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -25,13 +25,13 @@ set(INC .. + ../../blenkernel ../../blenlib + ../../blenloader + ../../editors/include ../../makesdna ../../makesrna - ../../blenkernel - ../../blenloader ../../windowmanager - ../../editors/include ../../../../intern/guardedalloc ) diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/quicktime/CMakeLists.txt index 6e72f053af7..b647466d2a8 100644 --- a/source/blender/quicktime/CMakeLists.txt +++ b/source/blender/quicktime/CMakeLists.txt @@ -34,7 +34,6 @@ set(INC ../imbuf/intern ../makesdna ../makesrna - ../quicktime ../render/extern/include ../windowmanager ../../../intern/guardedalloc diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index 9adebffc55e..90aef816e2c 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -26,17 +26,17 @@ set(INC - intern/include extern/include + intern/include + ../blenkernel ../blenlib ../blenloader + ../imbuf ../makesdna ../makesrna - ../blenkernel - ../imbuf - ../../../intern/smoke/extern - ../../../intern/mikktspace ../../../intern/guardedalloc + ../../../intern/mikktspace + ../../../intern/smoke/extern ) set(INC_SYS diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index c815b4aad2f..20ac3ba7077 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -26,23 +26,23 @@ set(INC . - ../nodes - ../gpu ../blenfont - ../blenlib - ../makesdna - ../makesrna ../blenkernel - ../imbuf + ../blenlib ../blenloader ../editors/include + ../gpu + ../imbuf + ../makesdna + ../makesrna + ../nodes ../render/extern/include - ../../../intern/guardedalloc - ../../../intern/memutil + ../../gameengine/BlenderRoutines ../../../intern/elbeem/extern ../../../intern/ghost + ../../../intern/guardedalloc + ../../../intern/memutil ../../../intern/opennl/extern - ../../../source/gameengine/BlenderRoutines ) set(INC_SYS -- cgit v1.2.3 From 7f850ff25dbc0523c43ce344f49d47b78d24e514 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 17 Jul 2011 12:30:23 +0000 Subject: 'bgl' python module. - add back slicing for buffers, (was previously in 2.4x but not working in py3): buf = bgl.Buffer(...) ls = buf[:] - fix for crash with negative index access not being clamped. - improve repr() function for multi dimensional buffers. - add back 'list' attribute, but print deprecation warning. --- source/blender/python/generic/bgl.c | 248 +++++++++++++++++++++++++----------- 1 file changed, 173 insertions(+), 75 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 18d01f45015..603f9f31743 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -48,12 +48,15 @@ static PyObject *Buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds); /* Buffer sequence methods */ -static int Buffer_len(PyObject *self); -static PyObject *Buffer_item(PyObject *self, int i); -static PyObject *Buffer_slice(PyObject *self, int begin, int end); -static int Buffer_ass_item(PyObject *self, int i, PyObject *v); -static int Buffer_ass_slice(PyObject *self, int begin, int end, +static int Buffer_len(Buffer *self); +static PyObject *Buffer_item(Buffer *self, int i); +static PyObject *Buffer_slice(Buffer *self, int begin, int end); +static int Buffer_ass_item(Buffer *self, int i, PyObject *v); +static int Buffer_ass_slice(Buffer *self, int begin, int end, PyObject *seq); +static PyObject *Buffer_subscript(Buffer *self, PyObject *item); +static int Buffer_ass_subscript(Buffer *self, PyObject *item, + PyObject *value); static PySequenceMethods Buffer_SeqMethods = { (lenfunc) Buffer_len, /*sq_length */ @@ -68,12 +71,19 @@ static PySequenceMethods Buffer_SeqMethods = { (ssizeargfunc) NULL, /* sq_inplace_repeat */ }; -static void Buffer_dealloc(PyObject *self); -static PyObject *Buffer_repr(PyObject *self); -static PyObject *Buffer_to_list(PyObject *self) +static PyMappingMethods Buffer_AsMapping = { + (lenfunc)Buffer_len, + (binaryfunc)Buffer_subscript, + (objobjargproc)Buffer_ass_subscript +}; + +static void Buffer_dealloc(Buffer *self); +static PyObject *Buffer_repr(Buffer *self); + +static PyObject *Buffer_to_list(Buffer *self) { - int i, len= ((Buffer *)self)->dimensions[0]; + int i, len= self->dimensions[0]; PyObject *list= PyList_New(len); for (i=0; indimensions > 1) { + int i, len= self->dimensions[0]; + list= PyList_New(len); + + for (i=0; indimensions); + fprintf(stderr, "Warning: 'Buffer.list' deprecated, use '[:]' instead\n"); + return Buffer_to_list(self); +} + +static PyObject *Buffer_dimensions(Buffer *self, void *UNUSED(arg)) +{ + PyObject *list= PyList_New(self->ndimensions); int i; - for (i= 0; indimensions; i++) { - PyList_SET_ITEM(list, i, PyLong_FromLong(buffer->dimensions[i])); + for (i= 0; indimensions; i++) { + PyList_SET_ITEM(list, i, PyLong_FromLong(self->dimensions[i])); } return list; } static PyMethodDef Buffer_methods[] = { - {"to_list", (PyCFunction)Buffer_to_list, METH_NOARGS, + {"to_list", (PyCFunction)Buffer_to_list_recursive, METH_NOARGS, "return the buffer as a list"}, {NULL, NULL, 0, NULL} }; static PyGetSetDef Buffer_getseters[] = { + {(char *)"list", (getter)Buffer_list, NULL, NULL, NULL}, {(char *)"dimensions", (getter)Buffer_dimensions, NULL, NULL, NULL}, {NULL, NULL, NULL, NULL, NULL} }; @@ -121,7 +159,7 @@ PyTypeObject BGL_bufferType = { (reprfunc) Buffer_repr, /*tp_repr */ NULL, /*tp_as_number */ &Buffer_SeqMethods, /*tp_as_sequence */ - NULL, /* PyMappingMethods *tp_as_mapping; */ + &Buffer_AsMapping, /* PyMappingMethods *tp_as_mapping; */ /* More standard operations (here for binary compatibility) */ @@ -262,7 +300,8 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject int ndimensions = 0; if(kwds && PyDict_Size(kwds)) { - PyErr_SetString(PyExc_TypeError, "bgl.Buffer(): takes no keyword args"); + PyErr_SetString(PyExc_TypeError, + "bgl.Buffer(): takes no keyword args"); return NULL; } @@ -319,7 +358,7 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject buffer= BGL_MakeBuffer(type, ndimensions, dimensions, NULL); if (init && ndimensions) { - if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], init)) { + if (Buffer_ass_slice(buffer, 0, dimensions[0], init)) { Py_DECREF(buffer); return NULL; } @@ -330,51 +369,48 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject /*@ Buffer sequence methods */ -static int Buffer_len(PyObject *self) +static int Buffer_len(Buffer *self) { - Buffer *buf= (Buffer *) self; - return buf->dimensions[0]; + return self->dimensions[0]; } -static PyObject *Buffer_item(PyObject *self, int i) +static PyObject *Buffer_item(Buffer *self, int i) { - Buffer *buf= (Buffer *) self; - - if (i >= buf->dimensions[0]) { + if (i >= self->dimensions[0] || i < 0) { PyErr_SetString(PyExc_IndexError, "array index out of range"); return NULL; } - if (buf->ndimensions==1) { - switch (buf->type) { - case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]); - case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]); - case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]); - case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]); - case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]); + if (self->ndimensions==1) { + switch (self->type) { + case GL_BYTE: return Py_BuildValue("b", self->buf.asbyte[i]); + case GL_SHORT: return Py_BuildValue("h", self->buf.asshort[i]); + case GL_INT: return Py_BuildValue("i", self->buf.asint[i]); + case GL_FLOAT: return PyFloat_FromDouble(self->buf.asfloat[i]); + case GL_DOUBLE: return Py_BuildValue("d", self->buf.asdouble[i]); } } else { Buffer *newbuf; int j, length, size; - + length= 1; - for (j=1; jndimensions; j++) { - length*= buf->dimensions[j]; + for (j=1; j < self->ndimensions; j++) { + length *= self->dimensions[j]; } - size= BGL_typeSize(buf->type); + size= BGL_typeSize(self->type); newbuf= (Buffer *) PyObject_NEW(Buffer, &BGL_bufferType); Py_INCREF(self); - newbuf->parent= self; + newbuf->parent= (PyObject *)self; - newbuf->ndimensions= buf->ndimensions-1; - newbuf->type= buf->type; - newbuf->buf.asvoid= buf->buf.asbyte + i*length*size; + newbuf->ndimensions= self->ndimensions - 1; + newbuf->type= self->type; + newbuf->buf.asvoid= self->buf.asbyte + i*length*size; newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int), "Buffer dimensions"); - memcpy(newbuf->dimensions, buf->dimensions+1, + memcpy(newbuf->dimensions, self->dimensions+1, newbuf->ndimensions*sizeof(int)); return (PyObject *) newbuf; @@ -383,16 +419,14 @@ static PyObject *Buffer_item(PyObject *self, int i) return NULL; } -static PyObject *Buffer_slice(PyObject *self, int begin, int end) +static PyObject *Buffer_slice(Buffer *self, int begin, int end) { - Buffer *buf= (Buffer *) self; PyObject *list; int count; - if (begin<0) begin= 0; - if (end>buf->dimensions[0]) - end= buf->dimensions[0]; - if (begin>end) begin= end; + if (begin < 0) begin= 0; + if (end > self->dimensions[0]) end= self->dimensions[0]; + if (begin > end) begin= end; list= PyList_New(end-begin); @@ -402,21 +436,19 @@ static PyObject *Buffer_slice(PyObject *self, int begin, int end) return list; } -static int Buffer_ass_item(PyObject *self, int i, PyObject *v) +static int Buffer_ass_item(Buffer *self, int i, PyObject *v) { - Buffer *buf= (Buffer *) self; - - if (i >= buf->dimensions[0]) { + if (i >= self->dimensions[0] || i < 0) { PyErr_SetString(PyExc_IndexError, "array assignment index out of range"); return -1; } - if (buf->ndimensions!=1) { - PyObject *row= Buffer_item(self, i); + if (self->ndimensions!=1) { + Buffer *row= (Buffer *)Buffer_item(self, i); if (row) { - int ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v); + int ret= Buffer_ass_slice(row, 0, self->dimensions[1], v); Py_DECREF(row); return ret; } @@ -425,31 +457,30 @@ static int Buffer_ass_item(PyObject *self, int i, PyObject *v) } } - switch(buf->type) { + switch(self->type) { case GL_BYTE: - return PyArg_Parse(v, "b:Expected ints", &buf->buf.asbyte[i]) ? 0:-1; + return PyArg_Parse(v, "b:Expected ints", &self->buf.asbyte[i]) ? 0:-1; case GL_SHORT: - return PyArg_Parse(v, "h:Expected ints", &buf->buf.asshort[i]) ? 0:-1; + return PyArg_Parse(v, "h:Expected ints", &self->buf.asshort[i]) ? 0:-1; case GL_INT: - return PyArg_Parse(v, "i:Expected ints", &buf->buf.asint[i]) ? 0:-1; + return PyArg_Parse(v, "i:Expected ints", &self->buf.asint[i]) ? 0:-1; case GL_FLOAT: - return PyArg_Parse(v, "f:Expected floats", &buf->buf.asfloat[i]) ? 0:-1; + return PyArg_Parse(v, "f:Expected floats", &self->buf.asfloat[i]) ? 0:-1; case GL_DOUBLE: - return PyArg_Parse(v, "d:Expected floats", &buf->buf.asdouble[i]) ? 0:-1; + return PyArg_Parse(v, "d:Expected floats", &self->buf.asdouble[i]) ? 0:-1; default: return 0; /* should never happen */ } } -static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq) +static int Buffer_ass_slice(Buffer *self, int begin, int end, PyObject *seq) { - Buffer *buf= (Buffer *) self; PyObject *item; int count, err=0; - if (begin<0) begin= 0; - if (end>buf->dimensions[0]) end= buf->dimensions[0]; - if (begin>end) begin= end; + if (begin < 0) begin= 0; + if (end > self->dimensions[0]) end= self->dimensions[0]; + if (begin > end) begin= end; if (!PySequence_Check(seq)) { PyErr_Format(PyExc_TypeError, @@ -481,27 +512,94 @@ static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq) return err; } -static void Buffer_dealloc(PyObject *self) +static PyObject *Buffer_subscript(Buffer *self, PyObject *item) { - Buffer *buf = (Buffer *)self; + 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->dimensions[0]; + return Buffer_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; - if (buf->parent) Py_DECREF(buf->parent); - else MEM_freeN (buf->buf.asvoid); + if (PySlice_GetIndicesEx((void *)item, self->dimensions[0], &start, &stop, &step, &slicelength) < 0) + return NULL; + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else if (step == 1) { + return Buffer_slice(self, start, stop); + } + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with vectors"); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "buffer indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return NULL; + } +} + +static int Buffer_ass_subscript(Buffer *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->dimensions[0]; + return Buffer_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((void *)item, self->dimensions[0], &start, &stop, &step, &slicelength) < 0) + return -1; + + if (step == 1) + return Buffer_ass_slice(self, start, stop, value); + else { + PyErr_SetString(PyExc_IndexError, + "slice steps not supported with vectors"); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "buffer indices must be integers, not %.200s", + Py_TYPE(item)->tp_name); + return -1; + } +} + + +static void Buffer_dealloc(Buffer *self) +{ + if (self->parent) Py_DECREF(self->parent); + else MEM_freeN (self->buf.asvoid); + + MEM_freeN(self->dimensions); - MEM_freeN (buf->dimensions); - PyObject_DEL(self); } -static PyObject *Buffer_repr(PyObject *self) +static PyObject *Buffer_repr(Buffer *self) { - PyObject *list= Buffer_to_list(self); + PyObject *list= Buffer_to_list_recursive(self); PyObject *repr; const char *typestr= "UNKNOWN"; - Buffer *buffer= (Buffer *)self; - switch(buffer->type) { + switch(self->type) { case GL_BYTE: typestr= "GL_BYTE"; break; case GL_SHORT: typestr= "GL_SHORT"; break; case GL_INT: typestr= "GL_BYTE"; break; -- cgit v1.2.3 From ebf21a98487cb851fdd1a3559fc8f890c347aad9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 17 Jul 2011 12:40:18 +0000 Subject: patch [#28001] Find the nearest point on an object to the given location from Andrew Hale (trumanblending) --- source/blender/makesrna/intern/rna_object_api.c | 55 +++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index d6af04f2475..b33935b7bed 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -415,6 +415,41 @@ void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], fl *index= -1; } +void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float n_location[3], float n_normal[3], int *index) +{ + BVHTreeFromMesh treeData= {NULL}; + + if(ob->derivedFinal==NULL) { + BKE_reportf(reports, RPT_ERROR, "object \"%s\" has no mesh data to be used for finding nearest point.", ob->id.name+2); + return; + } + + /* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */ + bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6); + + if(treeData.tree==NULL) { + BKE_reportf(reports, RPT_ERROR, "object \"%s\" could not create internal data for finding nearest point", ob->id.name+2); + return; + } + else { + BVHTreeNearest nearest; + + nearest.index = -1; + nearest.dist = FLT_MAX; + + if(BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) { + copy_v3_v3(n_location, nearest.co); + copy_v3_v3(n_normal, nearest.no); + *index= nearest.index; + return; + } + } + + zero_v3(n_location); + zero_v3(n_normal); + *index= -1; +} + /* ObjectBase */ void rna_ObjectBase_layers_from_view(Base *base, View3D *v3d) @@ -501,6 +536,26 @@ void RNA_api_object(StructRNA *srna) parm= RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no intersection is found.", 0, 0); RNA_def_function_output(func, parm); + /* Nearest Point */ + func= RNA_def_function(srna, "closest_point_on_mesh", "rna_Object_closest_point_on_mesh"); + RNA_def_function_ui_description(func, "Find the nearest point on the object."); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + + /* ray start and end */ + parm= RNA_def_float_vector(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + RNA_def_property_flag(parm, PROP_REQUIRED); + + /* return location and normal */ + parm= RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The location on the object closest to the point", -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + parm= RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "The face normal at the closest point", -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + + parm= RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no intersection is found.", 0, 0); + RNA_def_function_output(func, parm); + /* View */ func= RNA_def_function(srna, "is_visible", "rna_Object_is_visible"); RNA_def_function_ui_description(func, "Determine if object is visible in a given scene."); -- cgit v1.2.3 From b29b0acdceb98b0f67b214223c7624ca5d1e7697 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 17 Jul 2011 16:14:52 +0000 Subject: Removed the autoconnect call when adding new nodes, this hardly ever gives usable results and leads to annoyed artists. --- source/blender/editors/space_node/node_header.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index a982f4b1994..4f3991e8ff8 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -94,8 +94,6 @@ static void do_node_add(bContext *C, void *UNUSED(arg), int event) if(node->flag & NODE_TEST) node->flag |= NODE_SELECT; } - snode_autoconnect(snode, 1, 0); - /* deselect after autoconnection */ for(node= snode->edittree->nodes.first; node; node= node->next) { if(node->flag & NODE_TEST) node->flag &= ~NODE_SELECT; -- cgit v1.2.3 From 756ef16e21c18b863bc7c9c86f5f34e15fa30f41 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 17 Jul 2011 18:04:28 +0000 Subject: Little modification of the duplicate operator on artist request: The default behavior (shift+dkey) is now to copy nodes and internal links, but not the input links from unselected nodes. This feature is available with the alternate duplicate operator (alt+dkey). --- source/blender/editors/space_node/node_edit.c | 12 ++++++++---- source/blender/editors/space_node/node_ops.c | 9 +++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index e760c9021c2..36e8bc35e73 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2000,12 +2000,13 @@ bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float /* ****************** Duplicate *********************** */ -static int node_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +static int node_duplicate_exec(bContext *C, wmOperator *op) { SpaceNode *snode= CTX_wm_space_node(C); bNodeTree *ntree= snode->edittree; bNode *node, *newnode, *lastnode; bNodeLink *link, *newlink, *lastlink; + int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); ED_preview_kill_jobs(C); @@ -2033,10 +2034,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) */ lastlink = ntree->links.last; for (link=ntree->links.first; link; link=link->next) { - /* this creates new links between copied nodes, - * as well as input links from unselected (when fromnode==NULL) ! + /* This creates new links between copied nodes. + * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! */ - if (link->tonode && (link->tonode->flag & NODE_SELECT)) { + if (link->tonode && (link->tonode->flag & NODE_SELECT) + && (keep_inputs || link->fromnode && (link->fromnode->flag & NODE_SELECT))) { newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; @@ -2096,6 +2098,8 @@ void NODE_OT_duplicate(wmOperatorType *ot) /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes"); } /* *************************** add link op ******************** */ diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 4d181a34894..905347d6b80 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -101,11 +101,18 @@ void node_operatortypes(void) void ED_operatormacros_node(void) { wmOperatorType *ot; + wmOperatorTypeMacro *mot; ot= WM_operatortype_append_macro("NODE_OT_duplicate_move", "Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER); WM_operatortype_macro_define(ot, "NODE_OT_duplicate"); WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + /* modified operator call for duplicating with input links */ + ot= WM_operatortype_append_macro("NODE_OT_duplicate_move_keep_inputs", "Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER); + mot = WM_operatortype_macro_define(ot, "NODE_OT_duplicate"); + RNA_boolean_set(mot->ptr, "keep_inputs", 1); + WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + ot= WM_operatortype_append_macro("NODE_OT_select_link_viewer", "Link Viewer", OPTYPE_UNDO); WM_operatortype_macro_define(ot, "NODE_OT_select"); WM_operatortype_macro_define(ot, "NODE_OT_link_viewer"); @@ -155,6 +162,8 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "NODE_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); + /* modified operator call for duplicating with input links */ + WM_keymap_add_item(keymap, "NODE_OT_duplicate_move_keep_inputs", DKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "NODE_OT_hide_toggle", HKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_mute_toggle", MKEY, KM_PRESS, 0, 0); -- cgit v1.2.3 From f62df587d9f3d0a5bd5a1b8f576d907b4f7af0b4 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 17 Jul 2011 18:17:35 +0000 Subject: Changed the default keys for duplicate-nodes-while-keeping-input-links to ctrl+shift+dkey, to avoid conflicts with alt+dkey for linked duplicates. --- source/blender/editors/space_node/node_edit.c | 2 +- source/blender/editors/space_node/node_ops.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 36e8bc35e73..94263091d3b 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2038,7 +2038,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) * If keep_inputs is set, also copies input links from unselected (when fromnode==NULL)! */ if (link->tonode && (link->tonode->flag & NODE_SELECT) - && (keep_inputs || link->fromnode && (link->fromnode->flag & NODE_SELECT))) { + && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { newlink = MEM_callocN(sizeof(bNodeLink), "bNodeLink"); newlink->flag = link->flag; newlink->tonode = link->tonode->new_node; diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 905347d6b80..4bb0283690b 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -163,7 +163,7 @@ void node_keymap(struct wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "NODE_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "NODE_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); /* modified operator call for duplicating with input links */ - WM_keymap_add_item(keymap, "NODE_OT_duplicate_move_keep_inputs", DKEY, KM_PRESS, KM_ALT, 0); + WM_keymap_add_item(keymap, "NODE_OT_duplicate_move_keep_inputs", DKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); WM_keymap_add_item(keymap, "NODE_OT_hide_toggle", HKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "NODE_OT_mute_toggle", MKEY, KM_PRESS, 0, 0); -- cgit v1.2.3 From cf83cabb101cadd8994b436932fdd847a7df2279 Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Sun, 17 Jul 2011 19:43:14 +0000 Subject: Modified behavior when replacing input links: The new target socket for the existing link is now chosen from available sockets that match the _target_ type, instead of the source type. This leads to more usable replacements, e.g. for toggling inputs on mix nodes. Still not a great solution to the mute/autoconnect problem, but a bit more intuitive for replacements. --- source/blender/editors/space_node/node_edit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 94263091d3b..abc7b273ec9 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2118,9 +2118,9 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeSocket *tsock, bNodeL if(tlink) { /* try to move the existing link to the next available socket */ if (tlink->tonode) { - /* is there a free input socket with same type? */ + /* is there a free input socket with the target type? */ for(sock= tlink->tonode->inputs.first; sock; sock= sock->next) { - if(sock->type==tlink->fromsock->type) + if(sock->type==tlink->tosock->type) if(nodeCountSocketLinks(snode->edittree, sock) < sock->limit) break; } -- cgit v1.2.3 From 9469f0d0af61ce445e7eadf5b832a99baff0b976 Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Mon, 18 Jul 2011 02:40:54 +0000 Subject: Bug fix: particle cache should only be cleared on the exact first integer frame, not in the case of a subframe between the first and second frame. --- source/blender/blenkernel/intern/particle_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 63a9c224971..1423f520b95 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -3987,7 +3987,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) BKE_ptcache_id_time(pid, sim->scene, 0.0f, &startframe, &endframe, NULL); /* clear everythin on start frame */ - if((int)cfra == startframe) { + if(cfra == startframe) { BKE_ptcache_id_reset(sim->scene, pid, PTCACHE_RESET_OUTDATED); BKE_ptcache_validate(cache, startframe); cache->flag &= ~PTCACHE_REDO_NEEDED; -- cgit v1.2.3 From 9fa20e6d88be6d44152b9e856a83c850e5db2928 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 18 Jul 2011 07:38:44 +0000 Subject: fix [#28003] Unable to delete vgroup still need to find how an invalid defgroup index is set, but at least dont show the vertex group as selected when its not. --- source/blender/makesrna/intern/rna_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index dd66e49fdec..61e65585dd4 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -483,7 +483,7 @@ static PointerRNA rna_Object_active_vertex_group_get(PointerRNA *ptr) static int rna_Object_active_vertex_group_index_get(PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; - return MAX2(ob->actdef-1, 0); + return ob->actdef-1; } static void rna_Object_active_vertex_group_index_set(PointerRNA *ptr, int value) -- cgit v1.2.3 From 35ce13562db2eb2dedef76ffdf77b83e48fb684a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 18 Jul 2011 09:49:26 +0000 Subject: script to report deprecated functions of text and their age in days. --- source/blender/python/generic/bgl.c | 2 +- source/blender/python/intern/bpy_rna.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 603f9f31743..09432e0b316 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -114,7 +114,7 @@ static PyObject *Buffer_to_list_recursive(Buffer *self) return list; } -/* deprecate */ +/* *DEPRECATED* 2011/7/17 bgl.Buffer.list */ static PyObject *Buffer_list(Buffer *self, void *UNUSED(arg)) { fprintf(stderr, "Warning: 'Buffer.list' deprecated, use '[:]' instead\n"); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 61fc2e483b1..6e1b9c807f3 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -4548,7 +4548,7 @@ PyTypeObject pyrna_struct_meta_idprop_Type= { NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ - NULL, /* tp_compare */ /* DEPRECATED in python 3.0! */ + NULL, /* tp_compare */ /* deprecated in python 3.0! */ NULL, /* tp_repr */ /* Method suites for standard classes */ -- cgit v1.2.3 From 384831dd9d0944b2d2c80e09d402192a67a6a2db Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Mon, 18 Jul 2011 14:41:59 +0000 Subject: Bugfix #27927 This fixes assigning 'tweak' keymap option for border selecting in Node editor. Thanks Perry Parks for the patch! --- source/blender/windowmanager/intern/wm_operators.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 35afdf29b53..29afdb570ea 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -3567,10 +3567,12 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf) /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); - WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, GESTURE_MODAL_CANCEL); + /* Note: cancel only on press otherwise you cannot map this to RMB-gesture */ + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, GESTURE_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, 0, 0, GESTURE_MODAL_BEGIN); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_RELEASE, KM_ANY, 0, GESTURE_MODAL_SELECT); #if 0 // Durian guys like this WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_SHIFT, 0, GESTURE_MODAL_BEGIN); -- cgit v1.2.3 From 7de78a812c633e268d96fd0881004f1e126089ed Mon Sep 17 00:00:00 2001 From: Lukas Toenne Date: Mon, 18 Jul 2011 18:14:22 +0000 Subject: Missing struct keyword in function declaration causes compiler error with cmake/gcc. --- source/blender/modifiers/intern/MOD_util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h index b9b5c8a064a..5e6f377acf1 100644 --- a/source/blender/modifiers/intern/MOD_util.h +++ b/source/blender/modifiers/intern/MOD_util.h @@ -52,6 +52,6 @@ void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]); void validate_layer_name(const struct CustomData *data, int type, char *name, char *outname); struct DerivedMesh *get_cddm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]); struct DerivedMesh *get_dm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco); -void modifier_get_vgroup(struct Object *ob, DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index); +void modifier_get_vgroup(struct Object *ob, struct DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index); #endif /* MOD_UTIL_H */ -- cgit v1.2.3 From ce0ad0b40b93fc6074daaba6ead0e0e82867d4d2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 19 Jul 2011 01:36:59 +0000 Subject: fix [#28018] Sequence Swap Data Operator does not work --- source/blender/blenkernel/intern/sequencer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 265cc3eeb79..d6a152a5280 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3232,9 +3232,10 @@ int seq_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) { char name[sizeof(seq_a->name)]; - if(seq_a->len != seq_b->len) + if(seq_a->len != seq_b->len) { *error_str= "Strips must be the same length"; return 0; + } /* type checking, could be more advanced but disalow sound vs non-sound copy */ if(seq_a->type != seq_b->type) { -- cgit v1.2.3 From d8e216833a278d85caece8407d6ea5fad1a10c11 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 19 Jul 2011 02:47:43 +0000 Subject: cleanup of scene->gamedata DNA xsch and ysch were originally planed to replace the scene->r.xsch/r.ysch however in blender/3dview we still need to use the r. values. Therefore we can't really run from using those values even in bplayer. So removed the values in gamedata. The way it's now, render values (xsch and ysch) are responsible for aspect ratio and gamedata xplay and yplay are responsible for the size of the window. --- source/blender/blenloader/intern/readfile.c | 2 -- source/blender/makesdna/DNA_scene_types.h | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ab30d92f03e..4ad99c02b2d 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -10281,8 +10281,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) sce->gm.attrib = sce->r.attrib; //Stereo - sce->gm.xsch = sce->r.xsch; - sce->gm.ysch = sce->r.ysch; sce->gm.stereomode = sce->r.stereomode; /* reassigning stereomode NO_STEREO and DOME to a separeted flag*/ if (sce->gm.stereomode == 1){ //1 = STEREO_NOSTEREO diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index f351a48b998..3c14dacf973 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -430,7 +430,8 @@ typedef struct GameData { /* * Radius of the activity bubble, in Manhattan length. Objects * outside the box are activity-culled. */ - float activityBoxRadius; //it's not being used ANYWHERE !!!!!!!!!!!!!! + float activityBoxRadius; + /* * bit 3: (gameengine): Activity culling is enabled. * bit 5: (gameengine) : enable Bullet DBVT tree for view frustrum culling @@ -447,7 +448,8 @@ typedef struct GameData { /* stereo/dome mode */ struct GameDome dome; - short stereoflag, stereomode, xsch, ysch; //xsch and ysch used for backwards compat. + short stereoflag, stereomode; + short pad2, pad3; float eyeseparation, pad1; } GameData; -- cgit v1.2.3 From 4024b14b43c6409a319d80611bcf8b5e536bda1f Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 19 Jul 2011 08:31:53 +0000 Subject: fix for [#28012] Mat ID messy with shader nodes Issue was that the Shader tree execution changed the ShaderInput. Changes are that the UI is updated that only the main material will have the pass_index this is displayed in the "render pipeline options" panel. When the material is not a node material the pass_index will be shown at the "options" panel To test enable nodes on the material Add a new input material change the pass_index of the material (render pipeline options) Enable RenderPass material ID and use the compositor to read out the material pass Jeroen --- source/blender/nodes/intern/SHD_util.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/nodes/intern/SHD_util.c b/source/blender/nodes/intern/SHD_util.c index cf7c64c9d5e..190f68ce19a 100644 --- a/source/blender/nodes/intern/SHD_util.c +++ b/source/blender/nodes/intern/SHD_util.c @@ -83,7 +83,11 @@ void nodestack_get_vec(float *in, short type_in, bNodeStack *ns) void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr) { ShaderCallData scd; - + /* + @note: preserve material from ShadeInput for material id, nodetree execs change it + fix for bug "[#28012] Mat ID messy with shader nodes" + */ + Material *mat = shi->mat; /* convert caller data to struct */ scd.shi= shi; scd.shr= shr; @@ -92,7 +96,8 @@ void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr) memset(shr, 0, sizeof(ShadeResult)); ntreeExecTree(ntree, &scd, shi->thread); /* threads */ - + // @note: set material back to preserved material + shi->mat = mat; /* better not allow negative for now */ if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f; if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f; -- cgit v1.2.3 From 0936874695d981a987488b19f02dfe363ec68c0e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 19 Jul 2011 15:21:21 +0000 Subject: update to patch from Andrew Hale - obj.closest_point_ob_mesh() now takes an optional max_dist argument. --- source/blender/makesrna/intern/rna_object_api.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index b33935b7bed..9018fd8c71a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -45,6 +45,8 @@ // #include "ED_mesh.h" +#include "BLI_math.h" + #ifdef RNA_RUNTIME #include "BKE_main.h" @@ -64,8 +66,6 @@ #include "BKE_mball.h" #include "BKE_modifier.h" -#include "BLI_math.h" - #include "DNA_mesh_types.h" #include "DNA_scene_types.h" #include "DNA_meshdata_types.h" @@ -415,7 +415,7 @@ void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], fl *index= -1; } -void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float n_location[3], float n_normal[3], int *index) +void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float point_co[3], float max_dist, float n_location[3], float n_normal[3], int *index) { BVHTreeFromMesh treeData= {NULL}; @@ -435,7 +435,7 @@ void rna_Object_closest_point_on_mesh(Object *ob, ReportList *reports, float poi BVHTreeNearest nearest; nearest.index = -1; - nearest.dist = FLT_MAX; + nearest.dist = max_dist * max_dist; if(BLI_bvhtree_find_nearest(treeData.tree, point_co, &nearest, treeData.nearest_callback, &treeData) != -1) { copy_v3_v3(n_location, nearest.co); @@ -541,9 +541,10 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Find the nearest point on the object."); RNA_def_function_flag(func, FUNC_USE_REPORTS); - /* ray start and end */ + /* location of point for test and max distance */ parm= RNA_def_float_vector(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_float(func, "max_dist", sqrt(FLT_MAX), 0.0, FLT_MAX, "", "", 0.0, FLT_MAX); /* return location and normal */ parm= RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The location on the object closest to the point", -1e4, 1e4); @@ -553,7 +554,7 @@ void RNA_api_object(StructRNA *srna) RNA_def_property_flag(parm, PROP_THICK_WRAP); RNA_def_function_output(func, parm); - parm= RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no intersection is found.", 0, 0); + parm= RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when no closest point is found.", 0, 0); RNA_def_function_output(func, parm); /* View */ -- cgit v1.2.3 From 0ed523a8dd66189bbef192ad37d90c9c462d5dc1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 05:57:38 +0000 Subject: patch [#28032] Python Mathutils: Matrix Multiplication Error from Scott Giese (sgiese) --- source/blender/python/mathutils/mathutils_Matrix.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index b0187c1ef25..39d0784b287 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1594,20 +1594,14 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) 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; + float mat[16]= {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]); + for(x = 0; x < mat1->row_size; x++) { + for(y = 0; y < mat2->col_size; y++) { + for(z = 0; z < mat2->row_size; z++) { + mat[x * mat1->col_size + y] += (mat1->matrix[x][z] * mat2->matrix[z][y]); } - mat[((x * mat1->col_size) + y)] = (float)dot; - dot = 0.0f; } } -- cgit v1.2.3 From 74219d2704dfcc77c8530be47a626287ec1423a9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 06:05:47 +0000 Subject: patch [#28031] Minor typo in Blenlib from Scott Giese (sgiese) --- source/blender/blenlib/intern/path_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 80b85661762..f89283178ec 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -1680,7 +1680,7 @@ void BLI_where_am_i(char *fullname, const size_t maxlen, const char *name) if(GetModuleFileName(0, fullname, maxlen)) { if(!BLI_exists(fullname)) { printf("path can't be found: \"%.*s\"\n", maxlen, fullname); - MessageBox(NULL, "path constains invalid characters or is too long (see console)", "Error", MB_OK); + MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK); } return; } -- cgit v1.2.3 From 8b5e7f26501ba1794ad4e556fae169b2ca3c8769 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 06:41:51 +0000 Subject: patch [#28032] swapped matrix multiplication order, reverse it back, tested with FBX, BVH import/export which are very sensitive to changes in matrix rotation. --- source/blender/python/mathutils/mathutils_Matrix.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 39d0784b287..a7ed63776a5 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1587,7 +1587,7 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) if(mat1 && mat2) { /*MATRIX * MATRIX*/ - if(mat1->row_size != mat2->col_size){ + if(mat2->row_size != mat1->col_size){ PyErr_SetString(PyExc_ValueError, "Matrix multiplication: " "matrix A rowsize must equal matrix B colsize"); @@ -1597,15 +1597,15 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) float mat[16]= {0.0f}; int x, y, z; - for(x = 0; x < mat1->row_size; x++) { - for(y = 0; y < mat2->col_size; y++) { - for(z = 0; z < mat2->row_size; z++) { - mat[x * mat1->col_size + y] += (mat1->matrix[x][z] * mat2->matrix[z][y]); + for(x = 0; x < mat2->row_size; x++) { + for(y = 0; y < mat1->col_size; y++) { + for(z = 0; z < mat1->row_size; z++) { + mat[x * mat2->col_size + y] += (mat2->matrix[x][z] * mat1->matrix[z][y]); } } } - return newMatrixObject(mat, mat2->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1)); + return newMatrixObject(mat, mat1->row_size, mat2->col_size, Py_NEW, Py_TYPE(mat1)); } } else if(mat2) { -- cgit v1.2.3 From 28780342eddb0e1e767bf64d69cb99bd138d621f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 00:41:00 +0000 Subject: fix/workaround [#28040] float images reduced to 256 levels per channel upon save Generated images would not be re-generated with a float buffer on load, even when selected on creation. Now save the float buffer setting as a generated image flag. This means you can enable before baking to enable baking to a float buffer. --- source/blender/blenkernel/intern/image.c | 3 ++- source/blender/editors/space_image/image_buttons.c | 1 + source/blender/makesdna/DNA_image_types.h | 6 +++++- source/blender/makesrna/intern/rna_image.c | 5 +++++ 4 files changed, 13 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index c48497c45a1..ab67d7e3f25 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -432,6 +432,7 @@ Image *BKE_add_image_size(unsigned int width, unsigned int height, const char *n ima->gen_x= width; ima->gen_y= height; ima->gen_type= uvtestgrid; + ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); ibuf= add_ibuf_size(width, height, name, depth, floatbuf, uvtestgrid, color); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); @@ -2172,7 +2173,7 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r) /* UV testgrid or black or solid etc */ if(ima->gen_x==0) ima->gen_x= 1024; if(ima->gen_y==0) ima->gen_y= 1024; - ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 24, 0, ima->gen_type, color); + ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, 24, (ima->gen_flag & IMA_GEN_FLOAT) != 0, ima->gen_type, color); image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0); ima->ok= IMA_OK_LOADED; } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index e9ebe78da29..66e844e67a8 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -804,6 +804,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char col= uiLayoutColumn(split, 1); uiItemR(col, &imaptr, "generated_width", 0, "X", ICON_NONE); uiItemR(col, &imaptr, "generated_height", 0, "Y", ICON_NONE); + uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE); uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); } diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 99ed2319415..dd033339ca4 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -102,7 +102,8 @@ typedef struct Image { short animspeed; /* for generated images */ - short gen_x, gen_y, gen_type; + short gen_x, gen_y; + char gen_type, gen_flag; /* display aspect - for UV editing images resized for faster openGL display */ float aspx, aspy; @@ -136,5 +137,8 @@ typedef struct Image { #define IMA_MAX_RENDER_TEXT 512 #define IMA_MAX_RENDER_SLOT 8 +/* gen_flag */ +#define IMA_GEN_FLOAT 1 + #endif diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index a52849b3366..eac4932ac43 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -502,6 +502,11 @@ static void rna_def_image(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Generated Height", "Generated image height"); RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_generated_update"); + prop= RNA_def_property(srna, "use_generated_float", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gen_flag", IMA_GEN_FLOAT); + RNA_def_property_ui_text(prop, "Float Buffer", "Generate floating point buffer"); + RNA_def_property_update(prop, NC_IMAGE|ND_DISPLAY, "rna_Image_generated_update"); + /* realtime properties */ prop= RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); -- cgit v1.2.3 From 98774eba0e459faf801d5be4bed3588b75166a1b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 01:30:26 +0000 Subject: fix [#28037] Missing orange selection lines (trivial) From what I can tell there is no good fix for this bug, calculating the 2d/3d viewborder and then attempting to align them to be pixel perfect fails because of float imprecision. Added a workaround, so the camera border is always drawn in 2d space, since this workaround may cause problems later on its kept under the define VIEW3D_CAMERA_BORDER_HACK so we can get old behavior back easily. --- source/blender/editors/space_view3d/drawobject.c | 15 ++++++++++++++- source/blender/editors/space_view3d/view3d_draw.c | 14 +++++++++++++- source/blender/editors/space_view3d/view3d_intern.h | 10 ++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index e314d249e6d..e6889f4563f 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1335,6 +1335,11 @@ static void draw_focus_cross(float dist, float size) glEnd(); } +#ifdef VIEW3D_CAMERA_BORDER_HACK +float view3d_camera_border_hack_col[4]; +short view3d_camera_border_hack_test= FALSE; +#endif + /* flag similar to draw_object() */ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, int flag) { @@ -1348,7 +1353,15 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob const float scax= 1.0f / len_v3(ob->obmat[0]); const float scay= 1.0f / len_v3(ob->obmat[1]); const float scaz= 1.0f / len_v3(ob->obmat[2]); - + +#ifdef VIEW3D_CAMERA_BORDER_HACK + if(is_view && !(G.f & G_PICKSEL)) { + glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col); + view3d_camera_border_hack_test= TRUE; + return; + } +#endif + cam= ob->data; aspx= (float) scene->r.xsch*scene->r.xasp; aspy= (float) scene->r.ysch*scene->r.yasp; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 0ed62f3953f..d2ff6eef097 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1007,6 +1007,8 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) /* note: quite un-scientific but without this bit extra * 0.0001 on the lower left the 2D border sometimes * obscures the 3D camera border */ + /* note: with VIEW3D_CAMERA_BORDER_HACK defined this error isn't noticable + * but keep it here incase we need to remove the workaround */ x1i= (int)(x1 - 1.0001f); y1i= (int)(y1 - 1.0001f); x2i= (int)(x2 + (1.0f-0.0001f)); @@ -1039,7 +1041,17 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d) setlinestyle(0); UI_ThemeColor(TH_BACK); glRectf(x1i, y1i, x2i, y2i); - + +#ifdef VIEW3D_CAMERA_BORDER_HACK + { + if(view3d_camera_border_hack_test == TRUE) { + glColor4fv(view3d_camera_border_hack_col); + glRectf(x1i+1, y1i+1, x2i-1, y2i-1); + view3d_camera_border_hack_test= FALSE; + } + } +#endif + setlinestyle(3); UI_ThemeColor(TH_WIRE); glRectf(x1i, y1i, x2i, y2i); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index aa92f0d0a59..d3886d48873 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -194,6 +194,16 @@ extern const char *view3d_context_dir[]; /* doc access */ /* draw_volume.c */ void draw_volume(struct ARegion *ar, struct GPUTexture *tex, float *min, float *max, int res[3], float dx, struct GPUTexture *tex_shadow); +/* workaround for trivial but noticable camera bug caused by imprecision + * between view border calculation in 2D/3D space, workaround for bug [#28037]. + * without this deifne we get the old behavior which is to try and align them + * both which _mostly_ works fine, but when the camera moves beyond ~1000 in + * any direction it starts to fail */ +#define VIEW3D_CAMERA_BORDER_HACK +#ifdef VIEW3D_CAMERA_BORDER_HACK +extern float view3d_camera_border_hack_col[4]; +extern short view3d_camera_border_hack_test; +#endif #endif /* ED_VIEW3D_INTERN_H */ -- cgit v1.2.3 From c608288d76472856a0a0f7d1f1f0be4eebe15b88 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 01:37:15 +0000 Subject: add tip that duplicator system doesnt support xray / transp object draw options since we keep getting reports about this. --- source/blender/makesrna/intern/rna_object.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 61e65585dd4..76bbfcbed41 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2274,12 +2274,12 @@ static void rna_def_object(BlenderRNA *brna) prop= RNA_def_property(srna, "show_transparent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWTRANSP); - RNA_def_property_ui_text(prop, "Draw Transparent", "Displays material transparency in the object"); + RNA_def_property_ui_text(prop, "Draw Transparent", "Displays material transparency in the object (unsupported for duplicator drawing)"); RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); prop= RNA_def_property(srna, "show_x_ray", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "dtx", OB_DRAWXRAY); - RNA_def_property_ui_text(prop, "X-Ray", "Makes the object draw in front of others"); + RNA_def_property_ui_text(prop, "X-Ray", "Makes the object draw in front of others (unsupported for duplicator drawing)"); RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); /* Grease Pencil */ -- cgit v1.2.3 From 314fdb941e28d5f1fbe2acace6133d6216f4e36c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 02:00:29 +0000 Subject: revert recent matrix multiplication patch: [#28032] Python Mathutils: Matrix Multiplication Error Since they ended up reversing the order we better keep old code unless its proven to be incorrect. also change Matrix.__repr__ function args to evaluate correctly (need to be inside a tuple). --- source/blender/python/mathutils/mathutils_Matrix.c | 53 ++++++++++------------ 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index a7ed63776a5..76a0994c3aa 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1318,21 +1318,20 @@ static PyObject *Matrix_repr(MatrixObject *self) } } switch(self->row_size) { - case 2: return PyUnicode_FromFormat("Matrix(%R,\n" - " %R)", rows[0], rows[1]); + 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 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]); + 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!"); + Py_FatalError("Matrix(): invalid row size!"); return NULL; } @@ -1587,26 +1586,24 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) if(mat1 && mat2) { /*MATRIX * MATRIX*/ - if(mat2->row_size != mat1->col_size){ - PyErr_SetString(PyExc_ValueError, - "Matrix multiplication: " - "matrix A rowsize must equal matrix B colsize"); - return NULL; - } - else { - float mat[16]= {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++) { - mat[x * mat2->col_size + y] += (mat2->matrix[x][z] * mat1->matrix[z][y]); - } + 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, mat1->row_size, mat2->col_size, Py_NEW, Py_TYPE(mat1)); } + + return newMatrixObject(mat, mat2->row_size, mat1->col_size, Py_NEW, Py_TYPE(mat1)); } else if(mat2) { /*FLOAT/INT * MATRIX */ -- cgit v1.2.3 From e7669caf5a21cfda67fd73aee795932eaba8067e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 21 Jul 2011 08:10:34 +0000 Subject: Fixed bug with multires baking to float buffers. Was missed a flag to set rect marked as changed. --- source/blender/editors/object/object_bake.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index bdd911d68ee..679e4e58017 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -860,6 +860,10 @@ static void finish_images(MultiresBakeRender *bkr) RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, bkr->bake_filter); ibuf->userflags|= IB_BITMAPDIRTY; + + if(ibuf->rect_float) + ibuf->userflags|= IB_RECT_INVALID; + if(ibuf->mipmap[0]) { ibuf->userflags|= IB_MIPMAP_INVALID; imb_freemipmapImBuf(ibuf); -- cgit v1.2.3 From 3e9d1d7683c7d7bf2386c73048808bacd238d550 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 21 Jul 2011 09:50:39 +0000 Subject: Corrected View Selected operator for image editor so now it works fine for images with different X and Y aspect ratio. --- source/blender/editors/space_image/image_ops.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 10b8cb238aa..d5515bd1cf8 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -500,7 +500,7 @@ static int view_selected_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene; Object *obedit; Image *ima; - float size, min[2], max[2], d[2]; + float size, min[2], max[2], d[2], aspx, aspy; int width, height; /* retrieve state */ @@ -511,6 +511,10 @@ static int view_selected_exec(bContext *C, wmOperator *UNUSED(op)) ima= ED_space_image(sima); ED_space_image_size(sima, &width, &height); + ED_image_aspect(ima, &aspx, &aspy); + + width= width*aspx; + height= height*aspy; /* get bounds */ if(!ED_uvedit_minmax(scene, ima, obedit, min, max)) -- cgit v1.2.3 From bbfe3c9c49523d3987a3144da119d8f6afd09cf9 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Thu, 21 Jul 2011 17:40:20 +0000 Subject: Bugfix #28034 Blender render optimizes alpha=0 materials away, unless it has a number of properties... but there wasn't a check for material being ray-mirror, it then should be rendered always. --- source/blender/render/intern/source/convertblender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 583b792f240..2a7fb468bfa 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -3375,7 +3375,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) /* test for 100% transparant */ ok= 1; - if(ma->alpha==0.0f && ma->spectra==0.0f && ma->filter==0.0f && (ma->mode & MA_TRANSP)) { + if(ma->alpha==0.0f && ma->spectra==0.0f && ma->filter==0.0f && (ma->mode & MA_TRANSP) && (ma->mode & MA_RAYMIRROR)==0) { ok= 0; /* texture on transparency? */ for(a=0; a Date: Thu, 21 Jul 2011 21:34:08 +0000 Subject: Adding Shear transform to UV menu and Ctrl Alt Shift S hotkey (same as in 3D View) --- source/blender/editors/transform/transform_ops.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7bdf6c909d9..2d0c1ac2818 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -954,6 +954,8 @@ void transform_keymap_for_space(wmKeyConfig *keyconf, wmKeyMap *keymap, int spac WM_keymap_add_item(keymap, OP_RESIZE, SKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, OP_SHEAR, SKEY, KM_PRESS, KM_ALT|KM_CTRL|KM_SHIFT, 0); + WM_keymap_add_item(keymap, "TRANSFORM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0); km = WM_keymap_add_item(keymap, "WM_OT_context_toggle", TABKEY, KM_PRESS, KM_SHIFT, 0); -- cgit v1.2.3 From e6604288c8886b2c236c1765734a6ed71b8f0ae8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 23:06:51 +0000 Subject: cmake - option to disable the frame server --- source/blender/blenkernel/CMakeLists.txt | 4 ++++ source/blender/blenkernel/SConscript | 1 + source/blender/blenkernel/intern/writeframeserver.c | 2 ++ source/blender/makesrna/intern/CMakeLists.txt | 4 ++++ source/blender/makesrna/intern/SConscript | 2 ++ source/blender/makesrna/intern/rna_scene.c | 2 ++ 6 files changed, 15 insertions(+) (limited to 'source/blender') diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 9a384c40e24..defcef58463 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -279,6 +279,10 @@ if(WITH_IMAGE_CINEON) add_definitions(-DWITH_CINEON) endif() +if(WITH_IMAGE_FRAMESERVER) + add_definitions(-DWITH_FRAMESERVER) +endif() + if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript index 36afce7946c..5ea42ee65ae 100644 --- a/source/blender/blenkernel/SConscript +++ b/source/blender/blenkernel/SConscript @@ -22,6 +22,7 @@ incs += ' ' + env['BF_ZLIB_INC'] defs = [ 'GLEW_STATIC' ] defs.append('WITH_SMOKE') # TODO, make optional +defs.append('WITH_FRAMESERVER') # TODO, make optional if env['WITH_BF_PYTHON']: incs += ' ../python' diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c index 2239f6d3147..d13d15d1269 100644 --- a/source/blender/blenkernel/intern/writeframeserver.c +++ b/source/blender/blenkernel/intern/writeframeserver.c @@ -22,6 +22,7 @@ * */ +#ifdef WITH_FRAMESERVER #include #include @@ -381,3 +382,4 @@ void end_frameserver(void) shutdown_socket_system(); } +#endif /* WITH_FRAMESERVER */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index c9865bf3df4..cb593e7deab 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -171,6 +171,10 @@ if(WITH_IMAGE_HDR) add_definitions(-DWITH_HDR) endif() +if(WITH_IMAGE_FRAMESERVER) + add_definitions(-DWITH_FRAMESERVER) +endif() + if(WITH_AUDASPACE) add_definitions(-DWITH_AUDASPACE) endif() diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript index 421c3a60691..5e43ed9b2fb 100644 --- a/source/blender/makesrna/intern/SConscript +++ b/source/blender/makesrna/intern/SConscript @@ -54,6 +54,8 @@ if env['WITH_BF_CINEON']: if env['WITH_BF_HDR']: defs.append('WITH_HDR') +defs.append('WITH_FRAMESERVER') # TODO, make optional + if env['WITH_BF_FFMPEG']: defs.append('WITH_FFMPEG') incs += ' ' + env['BF_FFMPEG_INC'] diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 662ce04552e..9f751da484e 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -135,7 +135,9 @@ EnumPropertyItem image_type_items[] = { #endif {R_AVIJPEG, "AVI_JPEG", ICON_FILE_MOVIE, "AVI JPEG", "Output video in AVI JPEG format"}, {R_AVIRAW, "AVI_RAW", ICON_FILE_MOVIE, "AVI Raw", "Output video in AVI Raw format"}, +#ifdef WITH_FRAMESERVER {R_FRAMESERVER, "FRAMESERVER", ICON_FILE_SCRIPT, "Frame Server", "Output image to a frameserver"}, +#endif #ifdef WITH_FFMPEG {R_H264, "H264", ICON_FILE_MOVIE, "H.264", "Output video in H.264 format"}, {R_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "MPEG", "Output video in MPEG format"}, -- cgit v1.2.3 From 58895bee7bb1b877a7ba1e1648e75c9598706566 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 21 Jul 2011 23:36:17 +0000 Subject: fix [#28052] PET: Shift-O cycling skips "random falloff" --- source/blender/editors/transform/transform.c | 2 +- source/blender/makesdna/DNA_scene_types.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d3a30991aa6..eea77e36f7c 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -969,7 +969,7 @@ int transformEvent(TransInfo *t, wmEvent *event) break; case OKEY: if (t->flag & T_PROP_EDIT && event->shift) { - t->prop_mode = (t->prop_mode + 1) % 6; + t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX; calculatePropRatio(t); t->redraw |= TREDRAW_HARD; } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 3c14dacf973..8203a4dd77c 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1107,7 +1107,8 @@ typedef struct Scene { #define PROP_SHARP 3 #define PROP_LIN 4 #define PROP_CONST 5 -#define PROP_RANDOM 6 +#define PROP_RANDOM 6 +#define PROP_MODE_MAX 7 /* toolsettings->proportional */ #define PROP_EDIT_OFF 0 -- cgit v1.2.3 From 03bae345bebd01cd513e2b477e8409048c3f142c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jul 2011 00:31:24 +0000 Subject: fix [#28053] New material tooltip --- source/blender/editors/render/render_shading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index fdd53d27b02..cfed2750e18 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -108,7 +108,7 @@ void OBJECT_OT_material_slot_add(wmOperatorType *ot) /* identifiers */ ot->name= "Add Material Slot"; ot->idname= "OBJECT_OT_material_slot_add"; - ot->description="Add a new material slot or duplicate the selected one"; + ot->description="Add a new material slot"; /* api callbacks */ ot->exec= material_slot_add_exec; -- cgit v1.2.3 From 6040a28f039dc73cc62372fd329fe38e25b8f31f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jul 2011 00:34:03 +0000 Subject: missed this file when adding option to disable frameserver --- source/blender/blenkernel/intern/writeavi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c index ba7f9bdd415..769a3f9b11e 100644 --- a/source/blender/blenkernel/intern/writeavi.c +++ b/source/blender/blenkernel/intern/writeavi.c @@ -105,13 +105,18 @@ bMovieHandle *BKE_get_movie_handle(int imtype) mh.get_movie_path = filepath_ffmpeg; } #endif +#ifdef WITH_FRAMESERVER if (imtype == R_FRAMESERVER) { mh.start_movie = start_frameserver; mh.append_movie = append_frameserver; mh.end_movie = end_frameserver; mh.get_next_frame = frameserver_loop; } - +#endif + + /* incase all above are disabled */ + (void)imtype; + return &mh; } -- cgit v1.2.3 From 30da1336a8d7811fb9409c6e48209f7a533af1cc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jul 2011 01:21:20 +0000 Subject: patch [#28045] Straighten tool from Simple Todos from Kyle Mills (khonkhortisan) --- source/blender/editors/uvedit/uvedit_ops.c | 131 +++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) (limited to 'source/blender') diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index c09f8cff02d..d0393c970a6 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1057,6 +1057,134 @@ static void weld_align_uv(bContext *C, int tool) } } + if(tool == 's' || tool == 't' || tool == 'u') { + /* pass 1&2 variables */ + int i, j; + int starttmpl= -1, connectedtostarttmpl, startcorner; + int endtmpl= -1, connectedtoendtmpl, endcorner; + MTFace *startface, *endface; + int itmpl, jtmpl; + EditVert *eve; + int pass; /* first 2 passes find endpoints, 3rd pass moves middle points, 4th pass is fail-on-face-selected */ + EditFace *startefa, *endefa; + + /* pass 3 variables */ + float startx, starty, firstm, firstb, midx, midy; + float endx, endy, secondm, secondb, midmovedx, midmovedy; + float IsVertical_check= -1; + float IsHorizontal_check= -1; + + for(i= 0, eve= em->verts.first; eve; eve= eve->next, i++) /* give each point a unique name */ + eve->tmp.l= i; + for(pass= 1; pass <= 3; pass++) { /* do this for each endpoint */ + if(pass == 3){ /* calculate */ + startx= startface->uv[startcorner][0]; + starty= startface->uv[startcorner][1]; + endx= endface->uv[endcorner][0]; + endy= endface->uv[endcorner][1]; + firstm= (endy-starty)/(endx-startx); + firstb= starty-(firstm*startx); + secondm= -1.0f/firstm; + if(startx == endx) IsVertical_check= startx; + if(starty == endy) IsHorizontal_check= starty; + } + for(efa= em->faces.first; efa; efa= efa->next) { /* for each face */ + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); /* get face */ + if(uvedit_face_visible(scene, ima, efa, tf)) { /* if you can see it */ + if(uvedit_face_selected(scene, efa, tf)) { /* if the face is selected, get out now! */ + pass= 4; + break; + } + for(i= 0; (i < 3 || (i == 3 && efa->v4)); i++) { /* for each point of the face */ + itmpl= (*(&efa->v1 + i))->tmp.l; /* get unique name for points */ + if(pass == 3) { /* move */ + if(uvedit_uv_selected(scene, efa, tf, i)) { + if(!(itmpl == starttmpl || itmpl == endtmpl)) { + if(IsVertical_check != -1) tf->uv[i][0]= IsVertical_check; + if(IsHorizontal_check != -1) tf->uv[i][1]= IsHorizontal_check; + if((IsVertical_check == -1) && (IsHorizontal_check == -1)) { + midx= tf->uv[i][0]; + midy= tf->uv[i][1]; + if(tool == 's') { + secondb= midy-(secondm*midx); + midmovedx= (secondb-firstb)/(firstm-secondm); + midmovedy= (secondm*midmovedx)+secondb; + tf->uv[i][0]= midmovedx; + tf->uv[i][1]= midmovedy; + } + else if(tool == 't') { + tf->uv[i][0]= (midy-firstb)/firstm; /* midmovedx */ + } + else if(tool == 'u') { + tf->uv[i][1]= (firstm*midx)+firstb; /* midmovedy */ + } + } + } + } + } + else { + for(j= 0; (j < 3 || (j == 3 && efa->v4)); j++) { /* also for each point on the face */ + jtmpl= (*(&efa->v1 + j))->tmp.l; + if(i != j && (!efa->v4 || ABS(i-j) != 2)) { /* if the points are connected */ + /* quad (0,1,2,3) 0,1 0,3 1,0 1,2 2,1 2,3 3,0 3,2 + * triangle (0,1,2) 0,1 0,2 1,0 1,2 2,0 2,1 */ + if(uvedit_uv_selected(scene, efa, tf, i) && uvedit_uv_selected(scene, efa, tf, j)) { + /* if the edge is selected */ + if(pass == 1) { /* if finding first endpoint */ + if(starttmpl == -1) { /* if the first endpoint isn't found yet */ + starttmpl= itmpl; /* set unique name for endpoint */ + connectedtostarttmpl= jtmpl; + /* get point that endpoint is connected to */ + startface= tf; /* get face it's on */ + startcorner= i; /* what corner of the face? */ + startefa= efa; + efa= em->faces.first; + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + i= -1; + break; + } + if(starttmpl == itmpl && jtmpl != connectedtostarttmpl) { + starttmpl= -1; /* not an endpoint */ + efa= startefa; + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + i= startcorner; + break; + } + } + else if(pass == 2) { /* if finding second endpoint */ + if(endtmpl == -1 && itmpl != starttmpl) { + endtmpl= itmpl; + connectedtoendtmpl= jtmpl; + endface= tf; + endcorner= i; + endefa= efa; + efa= em->faces.first; + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + i= -1; + break; + } + if(endtmpl == itmpl && jtmpl != connectedtoendtmpl) { + endtmpl= -1; + efa= endefa; + tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + i= endcorner; + break; + } + } + } + } + } + } + } + } + } + if(pass == 2 && (starttmpl == -1 || endtmpl == -1)) { + /* if endpoints aren't found */ + pass=4; + } + } + } + uvedit_live_unwrap_update(sima, scene, obedit); DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); @@ -1074,6 +1202,9 @@ static int align_exec(bContext *C, wmOperator *op) static void UV_OT_align(wmOperatorType *ot) { static EnumPropertyItem axis_items[] = { + {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"}, + {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"}, + {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"}, {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"}, {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"}, {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"}, -- cgit v1.2.3 From 0e933d089df3a17327caf8700c19df9f419a2973 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jul 2011 05:33:06 +0000 Subject: fix [#27910] baking ambient occlusion, do not consider closer object for blender 2.58a --- source/blender/render/intern/source/convertblender.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 2a7fb468bfa..7782077604d 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5685,7 +5685,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, Object *camera; float mat[4][4]; float amb[3]; - const short onlyselected= !ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW); + const short onlyselected= !ELEM4(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO); const short nolamps= ELEM3(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT); re->main= bmain; -- cgit v1.2.3 From ea90544d65a5b2549d5e0b4761de3bf0f2631688 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Fri, 22 Jul 2011 15:28:50 +0000 Subject: Need some fun once a while: On dragging a non-connected node on a noodle, it will insert it. Functionality tweaks are possible, but it already feels non-intrusive. Rules: - Insertion only when a single noodle is intersecting with node. - Default connects first matching socket type. - If no socket match, it connects the first. --- source/blender/editors/include/ED_node.h | 3 + source/blender/editors/space_node/drawnode.c | 15 ++- source/blender/editors/space_node/node_edit.c | 126 ++++++++++++++++++++- .../editors/transform/transform_conversions.c | 14 ++- source/blender/makesdna/DNA_node_types.h | 4 + 5 files changed, 156 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 829ad3217a9..dfa457c22de 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -39,6 +39,7 @@ struct Tex; struct bContext; struct bNode; struct ID; +struct ScrArea; /* drawnode.c */ void ED_init_node_butfuncs(void); @@ -51,6 +52,8 @@ void ED_node_generic_update(struct Main *bmain, struct bNodeTree *ntree, struct void ED_node_shader_default(struct Material *ma); void ED_node_composit_default(struct Scene *sce); void ED_node_texture_default(struct Tex *tex); +void ED_node_link_intersect_test(struct ScrArea *sa, int test); +void ED_node_link_insert(struct ScrArea *sa); /* node ops.c */ void ED_operatormacros_node(void); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 1bf2c3d89bd..50e657bbb61 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1869,10 +1869,17 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link) else { /* check cyclic */ if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) { - if(link->fromnode->flag & SELECT) - th_col1= TH_EDGE_SELECT; - if(link->tonode->flag & SELECT) - th_col2= TH_EDGE_SELECT; + /* special indicated link, on drop-node */ + if(link->flag & NODE_LINKFLAG_HILITE) { + th_col1= th_col2= TH_ACTIVE; + } + else { + /* regular link */ + if(link->fromnode->flag & SELECT) + th_col1= TH_EDGE_SELECT; + if(link->tonode->flag & SELECT) + th_col2= TH_EDGE_SELECT; + } do_shaded= 1; do_triple= 1; } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index abc7b273ec9..b5648b67d86 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2492,6 +2492,127 @@ void NODE_OT_links_cut(wmOperatorType *ot) RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); } +/* ********************* automatic node insert on dragging ******************* */ + +static bNodeSocket *socket_best_match(ListBase *sockets, int type) +{ + bNodeSocket *sock; + + for(sock= sockets->first; sock; sock= sock->next) + if(type == sock->type) + return sock; + + return sockets->first; +} + +/* prevent duplicate testing code below */ +static SpaceNode *ed_node_link_conditions(ScrArea *sa, bNode **select) +{ + SpaceNode *snode= sa?sa->spacedata.first:NULL; + bNode *node; + bNodeLink *link; + + /* no unlucky accidents */ + if(sa==NULL || sa->spacetype!=SPACE_NODE) return NULL; + + *select= NULL; + + for(node= snode->edittree->nodes.first; node; node= node->next) { + if(node->flag & SELECT) { + if(*select) + break; + else + *select= node; + } + } + /* only one selected */ + if(node || *select==NULL) return NULL; + + /* correct node */ + if((*select)->inputs.first==NULL || (*select)->outputs.first==NULL) return NULL; + + /* test node for links */ + for(link= snode->edittree->links.first; link; link=link->next) { + if(link->tonode == *select || link->fromnode == *select) + return NULL; + } + + return snode; +} + +/* assumes link with NODE_LINKFLAG_HILITE set */ +void ED_node_link_insert(ScrArea *sa) +{ + bNode *node, *select; + SpaceNode *snode= ed_node_link_conditions(sa, &select); + bNodeLink *link; + bNodeSocket *sockto; + + if(snode==NULL) return; + + /* get the link */ + for(link= snode->edittree->links.first; link; link=link->next) + if(link->flag & NODE_LINKFLAG_HILITE) + break; + + if(link) { + node= link->tonode; + sockto= link->tosock; + + link->tonode= select; + link->tosock= socket_best_match(&select->inputs, link->fromsock->type); + link->flag &= ~NODE_LINKFLAG_HILITE; + + nodeAddLink(snode->edittree, select, socket_best_match(&select->outputs, sockto->type), node, sockto); + ntreeSolveOrder(snode->edittree); /* needed for pointers */ + snode_tag_changed(snode, select); + ED_node_changed_update(snode->id, select); + } +} + + +/* test == 0, clear all intersect flags */ +void ED_node_link_intersect_test(ScrArea *sa, int test) +{ + bNode *select; + SpaceNode *snode= ed_node_link_conditions(sa, &select); + bNodeLink *link, *selink=NULL; + float mcoords[4][2]; + + if(snode==NULL) return; + + /* clear flags */ + for(link= snode->edittree->links.first; link; link=link->next) + link->flag &= ~NODE_LINKFLAG_HILITE; + + if(test==0) return; + + /* okay, there's 1 node, without links, now intersect */ + mcoords[0][0]= select->totr.xmin; + mcoords[0][1]= select->totr.ymin; + mcoords[1][0]= select->totr.xmax; + mcoords[1][1]= select->totr.ymin; + mcoords[2][0]= select->totr.xmax; + mcoords[2][1]= select->totr.ymax; + mcoords[3][0]= select->totr.xmin; + mcoords[3][1]= select->totr.ymax; + + /* we only tag a single link for intersect now */ + /* idea; use header dist when more? */ + for(link= snode->edittree->links.first; link; link=link->next) { + + if(cut_links_intersect(link, mcoords, 4)) { + if(selink) + break; + selink= link; + } + } + + if(link==NULL && selink) + selink->flag |= NODE_LINKFLAG_HILITE; +} + + /* ******************************** */ // XXX some code needing updating to operators... @@ -2914,7 +3035,8 @@ void NODE_OT_delete(wmOperatorType *ot) /* note: in cmp_util.c is similar code, for node_compo_pass_on() */ /* used for disabling node (similar code in node_draw.c for disable line) */ -static void node_delete_reconnect(bNodeTree* tree, bNode* node) { +static void node_delete_reconnect(bNodeTree* tree, bNode* node) +{ bNodeLink *link, *next; bNodeSocket *valsocket= NULL, *colsocket= NULL, *vecsocket= NULL; bNodeSocket *deliveringvalsocket= NULL, *deliveringcolsocket= NULL, *deliveringvecsocket= NULL; @@ -3142,3 +3264,5 @@ void NODE_OT_add_file(wmOperatorType *ot) RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Datablock name to assign."); } + + diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 16bfc75c979..0a5e290643a 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -87,6 +87,7 @@ #include "ED_object.h" #include "ED_markers.h" #include "ED_mesh.h" +#include "ED_node.h" #include "ED_types.h" #include "ED_uvedit.h" #include "ED_curve.h" /* for ED_curve_editnurbs */ @@ -2182,6 +2183,12 @@ void flushTransNodes(TransInfo *t) td->loc2d[0]= td->loc[0]; td->loc2d[1]= td->loc[1]; } + + /* handle intersection with noodles */ + if(t->total==1) { + ED_node_link_intersect_test(t->sa, 1); + } + } /* *** SEQUENCE EDITOR *** */ @@ -4756,7 +4763,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t) } else if (t->spacetype == SPACE_NODE) { - /* pass */ + if(cancelled == 0) + ED_node_link_insert(t->sa); + + /* clear link line */ + ED_node_link_intersect_test(t->sa, 0); + } else if (t->spacetype == SPACE_ACTION) { SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 03387c3a63a..efaf30b02f6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -179,6 +179,10 @@ typedef struct bNodeLink { } bNodeLink; + +/* link->flag */ +#define NODE_LINKFLAG_HILITE 1 + /* the basis for a Node tree, all links and nodes reside internal here */ /* only re-usable node trees are in the library though, materials and textures allocate own tree struct */ typedef struct bNodeTree { -- cgit v1.2.3 From eed7702c9932653c68b72e291e30cbca3a741c16 Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Fri, 22 Jul 2011 16:02:56 +0000 Subject: Small fix in drop-node-on-noodle: intersect code only did 3 edges of node. --- source/blender/editors/space_node/node_edit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index b5648b67d86..8cb7528c4d7 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2577,7 +2577,7 @@ void ED_node_link_intersect_test(ScrArea *sa, int test) bNode *select; SpaceNode *snode= ed_node_link_conditions(sa, &select); bNodeLink *link, *selink=NULL; - float mcoords[4][2]; + float mcoords[5][2]; if(snode==NULL) return; @@ -2601,7 +2601,7 @@ void ED_node_link_intersect_test(ScrArea *sa, int test) /* idea; use header dist when more? */ for(link= snode->edittree->links.first; link; link=link->next) { - if(cut_links_intersect(link, mcoords, 4)) { + if(cut_links_intersect(link, mcoords, 5)) { /* 5 - silly intersect code */ if(selink) break; selink= link; -- cgit v1.2.3 From ffc490cbf1d93c7e0a9b97953f6f52e69b9bc8ec Mon Sep 17 00:00:00 2001 From: Ton Roosendaal Date: Fri, 22 Jul 2011 16:39:06 +0000 Subject: Two fixes in drop-node-on-noodle: - Intersection code was using undefined vector caused wrong lines to be picked - Code now also copes with hidden sockets. If all fails, is just unhides a good socket. --- source/blender/editors/space_node/node_edit.c | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 8cb7528c4d7..4230a43d2ec 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -2494,13 +2494,33 @@ void NODE_OT_links_cut(wmOperatorType *ot) /* ********************* automatic node insert on dragging ******************* */ +/* assumes sockets in list */ static bNodeSocket *socket_best_match(ListBase *sockets, int type) { bNodeSocket *sock; + /* first, match type */ for(sock= sockets->first; sock; sock= sock->next) - if(type == sock->type) + if(!(sock->flag & SOCK_HIDDEN)) + if(type == sock->type) + return sock; + + /* then just use first unhidden socket */ + for(sock= sockets->first; sock; sock= sock->next) + if(!(sock->flag & SOCK_HIDDEN)) + return sock; + + /* OK, let's unhide proper one */ + for(sock= sockets->first; sock; sock= sock->next) { + if(type == sock->type) { + sock->flag &= ~SOCK_HIDDEN; return sock; + } + } + + /* just the first */ + sock= sockets->first; + sock->flag &= ~SOCK_HIDDEN; return sockets->first; } @@ -2577,7 +2597,7 @@ void ED_node_link_intersect_test(ScrArea *sa, int test) bNode *select; SpaceNode *snode= ed_node_link_conditions(sa, &select); bNodeLink *link, *selink=NULL; - float mcoords[5][2]; + float mcoords[6][2]; if(snode==NULL) return; @@ -2596,12 +2616,16 @@ void ED_node_link_intersect_test(ScrArea *sa, int test) mcoords[2][1]= select->totr.ymax; mcoords[3][0]= select->totr.xmin; mcoords[3][1]= select->totr.ymax; + mcoords[4][0]= select->totr.xmin; + mcoords[4][1]= select->totr.ymin; + mcoords[5][0]= select->totr.xmax; + mcoords[5][1]= select->totr.ymax; /* we only tag a single link for intersect now */ /* idea; use header dist when more? */ for(link= snode->edittree->links.first; link; link=link->next) { - if(cut_links_intersect(link, mcoords, 5)) { /* 5 - silly intersect code */ + if(cut_links_intersect(link, mcoords, 5)) { /* intersect code wants edges */ if(selink) break; selink= link; -- cgit v1.2.3 From 742225d9b4c3888c1cfd155b575420abf0cf7869 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Sat, 23 Jul 2011 18:03:01 +0000 Subject: bugfix: [#28026] Copy Game Property broken not exactly a bug, but the option to copy individual properties was not working from the SPACE menu. I believe this was happening because we are using dynamic enums. This commit makes the "merge" option to be the default one. So if you call it from the SPACE menu it will be the one used. --- source/blender/editors/object/object_edit.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 29a740affc5..395705dc029 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -2162,16 +2162,20 @@ static int game_property_copy_exec(bContext *C, wmOperator *op) } CTX_DATA_END; } } - else if (ELEM(type, COPY_PROPERTIES_REPLACE, COPY_PROPERTIES_MERGE)) { + + else { CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) { if (ob != ob_iter) { if (ob->data != ob_iter->data){ - if (type == 2) {/* merge */ + if (type == COPY_PROPERTIES_REPLACE) + copy_properties( &ob_iter->prop, &ob->prop ); + + /* merge - the default when calling with no argument */ + else { for(prop = ob->prop.first; prop; prop= prop->next ) { set_ob_property(ob_iter, prop); } - } else /* replace */ - copy_properties( &ob_iter->prop, &ob->prop ); + } } } } -- cgit v1.2.3 From 43994ce213d43ecc4448493a8920b1a9e7f34492 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 23 Jul 2011 22:08:37 +0000 Subject: 2.5: * Removed some old not used code. --- source/blender/editors/space_view3d/view3d_header.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 75c8d5cae73..ae80a554e08 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -505,17 +505,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - /* NDOF */ - /* Not implemented yet - if (G.ndofdevice ==0 ) { - uiDefIconTextButC(block, ICONTEXTROW,B_NDOF, ICON_NDOF_TURN, ndof_pup(), 0,0,UI_UNIT_X+10,UI_UNIT_Y, &(v3d->ndofmode), 0, 3.0, 0, 0, "Ndof mode"); - - uiDefIconButC(block, TOG, B_NDOF, ICON_NDOF_DOM, - 0,0,UI_UNIT_X,UI_UNIT_Y, - &v3d->ndoffilter, 0, 1, 0, 0, "dominant axis"); - } - */ - /* Transform widget / manipulators */ row= uiLayoutRow(layout, 1); uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); -- cgit v1.2.3 From b154b5993829f92e03233a04410b3667f2976556 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sun, 24 Jul 2011 10:26:22 +0000 Subject: New dilation function from Morten Mikkelsen (aka sparky). This commit fixes very noticeable seams caused by margins calculated incorrectly. This commit changes way margin is calculated in and makes textures really seamless. Also margin limited to 32 isn't good now -- artists are baking really large textures nowadays so margin is now limited to 64px. Thank you, Morten! --- source/blender/imbuf/IMB_imbuf.h | 2 +- source/blender/imbuf/intern/filter.c | 219 ++++++++++++----------- source/blender/makesrna/intern/rna_scene.c | 2 +- source/blender/render/intern/source/rendercore.c | 22 +-- 4 files changed, 118 insertions(+), 127 deletions(-) (limited to 'source/blender') diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index ff01e3a8a1e..36123592c54 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -252,7 +252,7 @@ void IMB_filter(struct ImBuf *ibuf); void IMB_filterN(struct ImBuf *out, struct ImBuf *in); void IMB_mask_filter_extend(char *mask, int width, int height); void IMB_mask_clear(struct ImBuf *ibuf, char *mask, int val); -void IMB_filter_extend(struct ImBuf *ibuf, char *mask); +void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter); void IMB_makemipmap(struct ImBuf *ibuf, int use_filter); void IMB_remakemipmap(struct ImBuf *ibuf, int use_filter); struct ImBuf *IMB_getmipmap(struct ImBuf *ibuf, int level); diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c index d12360e5a7e..1644e653df4 100644 --- a/source/blender/imbuf/intern/filter.c +++ b/source/blender/imbuf/intern/filter.c @@ -21,7 +21,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Morten Mikkelsen. * * ***** END GPL LICENSE BLOCK ***** * filter.c @@ -326,121 +326,132 @@ void IMB_mask_clear(ImBuf *ibuf, char *mask, int val) } } -#define EXTEND_PIXEL(color, w) if((color)[3]) {r+= w*(color)[0]; g+= w*(color)[1]; b+= w*(color)[2]; a+= w*(color)[3]; tot+=w;} +static int filter_make_index(const int x, const int y, const int w, const int h) +{ + if(x<0 || x>=w || y<0 || y>=h) return -1; /* return bad index */ + else return y*w+x; +} + +static int check_pixel_assigned(const void *buffer, const char *mask, const int index, const int depth, const int is_float) +{ + int res = 0; + + if(index>=0) { + const int alpha_index = depth*index+(depth-1); + + if(mask!=NULL) { + res = mask[index]!=0 ? 1 : 0; + } + else if( (is_float && ((const float *) buffer)[alpha_index]!=0.0f) || + (!is_float && ((const unsigned char *) buffer)[alpha_index]!=0) ) { + res=1; + } + } + + return res; +} /* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 1.0 * * When a mask is given, only effect pixels with a mask value of 1, defined as BAKE_MASK_MARGIN in rendercore.c * */ -void IMB_filter_extend(struct ImBuf *ibuf, char *mask) +void IMB_filter_extend(struct ImBuf *ibuf, char *mask, int filter) { - register char *row1, *row2, *row3; - register char *cp; - int rowlen, x, y; - - rowlen= ibuf->x; - - - if (ibuf->rect_float) { - float *temprect; - float *row1f, *row2f, *row3f; - float *fp; - temprect= MEM_dupallocN(ibuf->rect_float); - - for(y=1; y<=ibuf->y; y++) { - /* setup rows */ - row1f= (float *)(temprect + (y-2)*rowlen*4); - row2f= row1f + 4*rowlen; - row3f= row2f + 4*rowlen; - if(y==1) - row1f= row2f; - else if(y==ibuf->y) - row3f= row2f; - - fp= (float *)(ibuf->rect_float + (y-1)*rowlen*4); - - for(x=0; xx; + const int height= ibuf->y; + const int depth= 4; /* always 4 channels */ + const int chsize= ibuf->rect_float ? sizeof(float) : sizeof(unsigned char); + const int bsize= width*height*depth*chsize; + const int is_float= ibuf->rect_float!=NULL; + void *dstbuf= (void *) MEM_dupallocN(ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect); + char *dstmask= mask==NULL ? NULL : (char *) MEM_dupallocN(mask); + void *srcbuf= ibuf->rect_float ? (void *) ibuf->rect_float : (void *) ibuf->rect; + char *srcmask= mask; + int cannot_early_out= 1, r, n, k, i, j, c; + float weight[25]; + + /* build a weights buffer */ + n= 2; + k= 0; + for(i = -n; i <= n; i++) + for(j = -n; j <= n; j++) + weight[k++] = sqrt((float) i * i + j * j); + + /* run passes */ + for(r = 0; cannot_early_out == 1 && r < filter; r++) { + int x, y; + cannot_early_out = 0; + + for(y= 0; y 255 ? 255 : (acc[c] < 0 ? 0 : ((unsigned char) (acc[c]+0.5f))); + } + } + + if(dstmask!=NULL) dstmask[index]=FILTER_MASK_MARGIN; /* assigned */ + cannot_early_out = 1; + } } } - fp+=4; - - if(x!=0) { - row1f+=4; row2f+=4; row3f+=4; - } } } - MEM_freeN(temprect); - } - else if(ibuf->rect) { - int *temprect; - - /* make a copy, to prevent flooding */ - temprect= MEM_dupallocN(ibuf->rect); - - for(y=1; y<=ibuf->y; y++) { - /* setup rows */ - row1= (char *)(temprect + (y-2)*rowlen); - row2= row1 + 4*rowlen; - row3= row2 + 4*rowlen; - if(y==1) - row1= row2; - else if(y==ibuf->y) - row3= row2; - - cp= (char *)(ibuf->rect + (y-1)*rowlen); - - for(x=0; xx, ibuf->y); - - temprect = MEM_dupallocN(mask); - - /* expand twice to clear this many pixels, so they blend back in */ - IMB_mask_filter_extend(temprect, ibuf->x, ibuf->y); - IMB_mask_filter_extend(temprect, ibuf->x, ibuf->y); - - /* clear all pixels in the margin */ - IMB_mask_clear(ibuf, temprect, FILTER_MASK_MARGIN); - MEM_freeN(temprect); - - for(i= 0; i < filter; i++) - IMB_filter_extend(ibuf, mask); + IMB_filter_extend(ibuf, mask, filter); } /* if the bake results in new alpha then change the image setting */ -- cgit v1.2.3 From b401d09d8f05d5b7fd81bbaaa27722f24faba165 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 24 Jul 2011 11:11:23 +0000 Subject: * Minor code cleanup / comment changing. No functional changes. --- source/blender/editors/interface/interface_templates.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 25dbb68a258..f388710d5b8 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -851,7 +851,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) /* verify we have valid data */ if(!RNA_struct_is_a(ptr->type, &RNA_Modifier)) { - RNA_warning("uiTemplateModifier: expected modifier on object.\n"); + RNA_warning("uiTemplateModifier: Expected modifier on object.\n"); return NULL; } @@ -859,7 +859,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) md= ptr->data; if(!ob || !(GS(ob->id.name) == ID_OB)) { - RNA_warning("uiTemplateModifier: expected modifier on object.\n"); + RNA_warning("uiTemplateModifier: Expected modifier on object.\n"); return NULL; } @@ -976,9 +976,6 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) block= uiLayoutGetBlock(box); /* Draw constraint header */ - - /* rounded header */ - // rb_col= (con->flag & CONSTRAINT_ACTIVE)?50:20; // UNUSED /* open/close */ uiBlockSetEmboss(block, UI_EMBOSSN); @@ -1083,7 +1080,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) /* verify we have valid data */ if(!RNA_struct_is_a(ptr->type, &RNA_Constraint)) { - RNA_warning("uiTemplateConstraint: expected constraint on object.\n"); + RNA_warning("uiTemplateConstraint: Expected constraint on object.\n"); return NULL; } @@ -1091,7 +1088,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) con= ptr->data; if(!ob || !(GS(ob->id.name) == ID_OB)) { - RNA_warning("uiTemplateConstraint: expected constraint on object.\n"); + RNA_warning("uiTemplateConstraint: Expected constraint on object.\n"); return NULL; } @@ -1137,7 +1134,7 @@ void uiTemplatePreview(uiLayout *layout, ID *id, int show_buttons, ID *parent, M PointerRNA texture_ptr; if(id && !ELEM4(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA)) { - RNA_warning("uiTemplatePreview: expected ID of type material, texture, lamp or world.\n"); + RNA_warning("uiTemplatePreview: Expected ID of type material, texture, lamp or world.\n"); return; } @@ -2171,14 +2168,14 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char * if(prop) { type= RNA_property_type(prop); if(type != PROP_COLLECTION) { - RNA_warning("uiTemplateList: expected collection property.\n"); + RNA_warning("uiTemplateList: Expected collection property.\n"); return; } } activetype= RNA_property_type(activeprop); if(activetype != PROP_INT) { - RNA_warning("uiTemplateList: expected integer property.\n"); + RNA_warning("uiTemplateList: Expected integer property.\n"); return; } -- cgit v1.2.3 From a22de3f73c28b86f481376d52fbcfd7bb8ee25f2 Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Sun, 24 Jul 2011 17:44:22 +0000 Subject: Effector calculations are now thread safe. * where_is_object_time was called for every effector evaluation only to determine the object velocity in some rare cases. * Calculating the effector velocity is now done in the effector precalculation stage. * Removing this makes the code thread safe and also should give some nice performance boosts when simulating a lot of points. * Thanks to MiikaH for noticing this problem. --- source/blender/blenkernel/BKE_effect.h | 1 + source/blender/blenkernel/intern/effect.c | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index 97ac711651b..12f9383cefb 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -105,6 +105,7 @@ typedef struct EffectorCache { /* precalculated for guides */ struct GuideEffectorData *guide_data; float guide_loc[4], guide_dir[3], guide_radius; + float velocity[3]; float frame; int flag; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index ee46bef6038..4b95c44f55f 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -241,6 +241,16 @@ static void precalculate_effector(EffectorCache *eff) } else if(eff->psys) psys_update_particle_tree(eff->psys, eff->scene->r.cfra); + + /* Store object velocity */ + if(eff->ob) { + float old_vel[3]; + + where_is_object_time(eff->scene, eff->ob, cfra - 1.0f); + copy_v3_v3(old_vel, eff->ob->obmat[3]); + where_is_object_time(eff->scene, eff->ob, cfra); + sub_v3_v3v3(eff->velocity, eff->ob->obmat[3], old_vel); + } } static EffectorCache *new_effector_cache(Scene *scene, Object *ob, ParticleSystem *psys, PartDeflect *pd) { @@ -680,10 +690,6 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin Object *ob = eff->ob; Object obcopy = *ob; - /* XXX this is not thread-safe, but used from multiple threads by - particle system */ - where_is_object_time(eff->scene, ob, cfra); - /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); @@ -702,13 +708,8 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin VECCOPY(efd->loc, ob->obmat[3]); } - if(real_velocity) { - VECCOPY(efd->vel, ob->obmat[3]); - - where_is_object_time(eff->scene, ob, cfra - 1.0f); - - sub_v3_v3v3(efd->vel, efd->vel, ob->obmat[3]); - } + if(real_velocity) + copy_v3_v3(efd->vel, eff->velocity); *eff->ob = obcopy; -- cgit v1.2.3 From ced8f1dffcb9b054d7197a21e2a0426056b2babf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 01:44:19 +0000 Subject: deprecate multiplication orders: vector * matrix vector *= matrix vector * quaternion vector *= quaternion Use the reverse order instead, enable WITH_ASSERT_ABORT in cmake to promote the warnings into errors. --- source/blender/python/mathutils/mathutils.h | 2 + source/blender/python/mathutils/mathutils_Matrix.c | 14 +++- .../python/mathutils/mathutils_Quaternion.c | 26 ++++++- source/blender/python/mathutils/mathutils_Vector.c | 80 +++++++++++++++++++++- 4 files changed, 118 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/python/mathutils/mathutils.h b/source/blender/python/mathutils/mathutils.h index 7454cfe78b3..b798b5e7003 100644 --- a/source/blender/python/mathutils/mathutils.h +++ b/source/blender/python/mathutils/mathutils.h @@ -108,4 +108,6 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index); 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); +int column_vector_multiplication(float rvec[4], VectorObject *vec, MatrixObject *mat); + #endif /* MATHUTILS_H */ diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 76a0994c3aa..3953171f263 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1612,8 +1612,20 @@ static PyObject *Matrix_mul(PyObject *m1, PyObject *m2) } } else if(mat1) { + /*VEC * MATRIX */ + if(VectorObject_Check(m2)) { + VectorObject *vec2= (VectorObject *)m2; + float tvec[4]; + if(BaseMath_ReadCallback(vec2) == -1) + return NULL; + if(column_vector_multiplication(tvec, vec2, mat1) == -1) { + return NULL; + } + + return newVectorObject(tvec, vec2->size, Py_NEW, Py_TYPE(m2)); + } /*FLOAT/INT * MATRIX */ - if (((scalar= PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred())==0) { + else if (((scalar= PyFloat_AsDouble(m2)) == -1.0f && PyErr_Occurred())==0) { return matrix_mul_float(mat1, scalar); } } diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c index 3b05b9a250b..2be258a1ef0 100644 --- a/source/blender/python/mathutils/mathutils_Quaternion.c +++ b/source/blender/python/mathutils/mathutils_Quaternion.c @@ -753,8 +753,30 @@ static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2) return quat_mul_float(quat2, scalar); } } - else if (quat1) { /* QUAT*FLOAT */ - if((((scalar= PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred())==0)) { + else if (quat1) { + /* QUAT * VEC */ + if (VectorObject_Check(q2)) { + VectorObject *vec2 = (VectorObject *)q2; + float tvec[3]; + + if(vec2->size != 3) { + PyErr_SetString(PyExc_ValueError, + "Vector multiplication: " + "only 3D vector rotations (with quats) " + "currently supported"); + return NULL; + } + if(BaseMath_ReadCallback(vec2) == -1) { + return NULL; + } + + copy_v3_v3(tvec, vec2->vec); + mul_qt_v3(quat1->quat, tvec); + + return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec2)); + } + /* QUAT * FLOAT */ + else if((((scalar= PyFloat_AsDouble(q2)) == -1.0f && PyErr_Occurred())==0)) { return quat_mul_float(quat1, scalar); } } diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c index e2c958adaa5..a954c07c98d 100644 --- a/source/blender/python/mathutils/mathutils_Vector.c +++ b/source/blender/python/mathutils/mathutils_Vector.c @@ -37,6 +37,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +extern void PyC_LineSpit(void); + #define MAX_DIMENSIONS 4 /* Swizzle axes get packed into a single value that is used as a closure. Each @@ -1081,7 +1083,7 @@ static PyObject *Vector_isub(PyObject *v1, PyObject *v2) * 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) +int column_vector_multiplication(float rvec[MAX_DIMENSIONS], VectorObject* vec, MatrixObject * mat) { float vec_cpy[MAX_DIMENSIONS]; double dot = 0.0f; @@ -1159,8 +1161,29 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) } else if (vec1) { if (MatrixObject_Check(v2)) { + extern void PyC_LineSpit(void); + /* VEC * MATRIX */ + /* this is deprecated!, use the reverse instead */ float tvec[MAX_DIMENSIONS]; + + +/* ------ to be removed ------*/ +#ifndef MATH_STANDALONE +#ifdef WITH_ASSERT_ABORT + PyErr_SetString(PyExc_ValueError, + "(Vector * Matrix) is now removed, reverse the " + "order (promoted to an Error for Debug builds)"); + return NULL; +#else + printf("Warning: (Vector * Matrix) is now deprecated, " + "reverse the multiplication order in the script.\n"); + PyC_LineSpit(); +#endif +#endif /* ifndef MATH_STANDALONE */ +/* ------ to be removed ------*/ + + if(BaseMath_ReadCallback((MatrixObject *)v2) == -1) return NULL; if(column_vector_multiplication(tvec, vec1, (MatrixObject*)v2) == -1) { @@ -1183,6 +1206,24 @@ static PyObject *Vector_mul(PyObject *v1, PyObject *v2) if(BaseMath_ReadCallback(quat2) == -1) { return NULL; } + + +/* ------ to be removed ------*/ +#ifndef MATH_STANDALONE +#ifdef WITH_ASSERT_ABORT + PyErr_SetString(PyExc_ValueError, + "(Vector * Quat) is now removed, reverse the " + "order (promoted to an Error for Debug builds)"); + return NULL; +#else + printf("Warning: (Vector * Quat) is now deprecated, " + "reverse the multiplication order in the script.\n"); + PyC_LineSpit(); +#endif +#endif /* ifndef MATH_STANDALONE */ +/* ------ to be removed ------*/ + + copy_v3_v3(tvec, vec1->vec); mul_qt_v3(quat2->quat, tvec); return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(vec1)); @@ -1226,6 +1267,24 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2) if(column_vector_multiplication(rvec, vec, (MatrixObject*)v2) == -1) return NULL; + +/* ------ to be removed ------*/ +#ifndef MATH_STANDALONE +#ifdef WITH_ASSERT_ABORT + PyErr_SetString(PyExc_ValueError, + "(Vector *= Matrix) is now removed, reverse the " + "order (promoted to an Error for Debug builds) " + "and uses the non in-place multiplication."); + return NULL; +#else + printf("Warning: (Vector *= Matrix) is now deprecated, " + "reverse the (non in-place) multiplication order in the script.\n"); + PyC_LineSpit(); +#endif +#endif /* ifndef MATH_STANDALONE */ +/* ------ to be removed ------*/ + + memcpy(vec->vec, rvec, sizeof(float) * vec->size); } else if (QuaternionObject_Check(v2)) { @@ -1242,6 +1301,25 @@ static PyObject *Vector_imul(PyObject *v1, PyObject *v2) if(BaseMath_ReadCallback(quat2) == -1) { return NULL; } + + +/* ------ to be removed ------*/ +#ifndef MATH_STANDALONE +#ifdef WITH_ASSERT_ABORT + PyErr_SetString(PyExc_ValueError, + "(Vector *= Quat) is now removed, reverse the " + "order (promoted to an Error for Debug builds) " + "and uses the non in-place multiplication."); + return NULL; +#else + printf("Warning: (Vector *= Quat) is now deprecated, " + "reverse the (non in-place) multiplication order in the script.\n"); + PyC_LineSpit(); +#endif +#endif /* ifndef MATH_STANDALONE */ +/* ------ to be removed ------*/ + + mul_qt_v3(quat2->quat, vec->vec); } else if (((scalar= PyFloat_AsDouble(v2)) == -1.0f && PyErr_Occurred())==0) { /* VEC *= FLOAT */ -- cgit v1.2.3 From aec8d72ca7532ccea6daee9ff099ff3f5feafb96 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 25 Jul 2011 16:16:32 +0000 Subject: Fix #28079: UV propertional editing was incorrectly influenced by the mesh X mirror option. --- source/blender/editors/transform/transform_generics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 20a26d8c58d..6d0a978700f 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1070,7 +1070,7 @@ int initTransInfo (bContext *C, TransInfo *t, wmOperator *op, wmEvent *event) } } // Need stuff to take it from edit mesh or whatnot here - else + else if (t->spacetype == SPACE_VIEW3D) { if (t->obedit && t->obedit->type == OB_MESH && (((Mesh *)t->obedit->data)->editflag & ME_EDIT_MIRROR_X)) { -- cgit v1.2.3 From 5b3906728fa358fccd857cbeca85ff102df6e6c7 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 25 Jul 2011 16:37:10 +0000 Subject: Fix #28035: point density texture doesn't bake. --- source/blender/render/intern/source/convertblender.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source/blender') diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 7782077604d..b385b507707 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5778,6 +5778,14 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if(re->r.mode & R_RAYTRACE) makeraytree(re); + /* point density texture */ + if(!re->test_break(re->tbh)) + make_pointdensities(re); + + /* voxel data texture */ + if(!re->test_break(re->tbh)) + make_voxeldata(re); + /* occlusion */ if((re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) && !re->test_break(re->tbh)) if(re->wrld.ao_gather_method == WO_AOGATHER_APPROX) -- cgit v1.2.3 From 9e1a5531274e6b00b877ef924994ceae8ba956e3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 07:41:14 +0000 Subject: set the development cycle to 'beta'. --- source/blender/blenkernel/BKE_blender.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 25fb6f9f9ff..18f6ad21333 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -53,7 +53,7 @@ extern "C" { /* can be left blank, otherwise a,b,c... etc with no quotes */ #define BLENDER_VERSION_CHAR a /* alpha/beta/rc/release, docs use this */ -#define BLENDER_VERSION_CYCLE release +#define BLENDER_VERSION_CYCLE beta struct ListBase; struct MemFile; -- cgit v1.2.3 From 7c9033d606a35dd4311e9f84b06b013e5cb7712a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 26 Jul 2011 08:13:27 +0000 Subject: Fix #28087: Opening files in the text editor ignores the last newline '\n' It was tricky conversion of file buffer to text lines. Should work fine now. --- source/blender/blenkernel/intern/text.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index da329503c9f..56723476251 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -400,7 +400,13 @@ Text *add_text(const char *file, const char *relpath) llen++; } - if (llen!=0 || ta->nlines==0) { + /* create new line in cases: + - rest of line (if last line in file hasn't got \n terminator). + in this case content of such line would be used to fill text line buffer + - file is empty. in this case new line is needed to start editing from. + - last characted in buffer is \n. in this case new line is needed to + deal with newline at end of file. (see [#28087]) (sergey) */ + if (llen!=0 || ta->nlines==0 || buffer[len-1]=='\n') { tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline"); tmp->line= (char*) MEM_mallocN(llen+1, "textline_string"); tmp->format= NULL; -- cgit v1.2.3 From 06ae122f604a00ebe57903439a2a0cedd0f3ffca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 09:19:51 +0000 Subject: include menu ID's in tooltips when python tips are enabled, there was no way to find the ID of a menu which become annoying if you wanted to reference it from a script. --- source/blender/editors/interface/interface_regions.c | 11 +++++++++++ source/blender/makesrna/intern/rna_wm.c | 2 +- source/blender/windowmanager/WM_api.h | 1 + source/blender/windowmanager/intern/wm.c | 6 ++++++ 4 files changed, 19 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index 62043f240e4..9e7717260e6 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -484,6 +484,17 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but) } } } + else if (ELEM(but->type, MENU, PULLDOWN)) { + if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) { + if(but->menu_create_func && WM_menutype_contains((MenuType *)but->poin)) { + MenuType *mt= (MenuType *)but->poin; + BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), "Python: %s", mt->idname); + data->color[data->totline]= 0x888888; + data->totline++; + } + } + + } assert(data->totline < MAX_TOOLTIP_LINES); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 7ea4701dec3..73221c47c90 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -940,7 +940,7 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * rna_Operator_unregister(bmain, ot->ext.srna); } - /* create a new menu type */ + /* create a new operator type */ dummyot.ext.srna= RNA_def_struct(&BLENDER_RNA, dummyot.idname, "Operator"); RNA_def_struct_flag(dummyot.ext.srna, STRUCT_NO_IDPROPERTIES); /* operator properties are registered separately */ dummyot.ext.data= data; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 67294a8eb53..e6325e2101a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -272,6 +272,7 @@ void WM_operator_py_idname(char *to, const char *from); /* *************** menu types ******************** */ struct MenuType *WM_menutype_find(const char *idname, int quiet); int WM_menutype_add(struct MenuType* mt); +int WM_menutype_contains(struct MenuType* mt); void WM_menutype_freelink(struct MenuType* mt); void WM_menutype_free(void); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index bcd5cf38f88..a535c0bc1f8 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -175,6 +175,12 @@ int WM_menutype_add(MenuType* mt) return 1; } +/* inefficient but only used for tooltip code */ +int WM_menutype_contains(MenuType* mt) +{ + return (mt != NULL && BLI_findindex(&menutypes, mt) != -1); +} + void WM_menutype_freelink(MenuType* mt) { BLI_freelinkN(&menutypes, mt); -- cgit v1.2.3 From 40353fe0d841e006d11ad5833eaedbc93fc0d608 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 13:05:22 +0000 Subject: fix for NULL pointer crash with operator repeat, looks like error print got mixed up. --- source/blender/editors/util/undo.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 8a6ec7f75db..a2381a208ef 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -358,19 +358,25 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) ret= 1; } } + else { + if (G.f & G_DEBUG) { + printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name); + } + } /* set region back */ CTX_wm_region_set(C, ar); } else { if (G.f & G_DEBUG) { - printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name); + printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n"); } } return ret; } + void ED_undo_operator_repeat_cb(bContext *C, void *arg_op, void *UNUSED(arg_unused)) { ED_undo_operator_repeat(C, (wmOperator *)arg_op); -- cgit v1.2.3 From ca293c835f15e8b0d19116456c75ba971f02e16b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 13:33:04 +0000 Subject: correct misc warnings --- source/blender/editors/object/object_add.c | 4 ++-- source/blender/editors/space_view3d/view3d_edit.c | 1 - source/blender/editors/transform/transform_snap.c | 5 +++++ source/blender/editors/uvedit/uvedit_ops.c | 4 ++-- source/blender/makesrna/intern/rna_object_api.c | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 7ca172c6945..f5f97c6a5f6 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -806,14 +806,14 @@ static int object_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); - int islamp= 0; + /* int islamp= 0; */ /* UNUSED */ if(CTX_data_edit_object(C)) return OPERATOR_CANCELLED; CTX_DATA_BEGIN(C, Base*, base, selected_bases) { - if(base->object->type==OB_LAMP) islamp= 1; + /* if(base->object->type==OB_LAMP) islamp= 1; */ /* deselect object -- it could be used in other scenes */ base->object->flag &= ~SELECT; diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9ff73767b4c..d563c07baf3 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -129,7 +129,6 @@ void ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d) } else { ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist); - root_parent= v3d->camera; DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB); WM_main_add_notifier(NC_OBJECT|ND_TRANSFORM, v3d->camera); } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index d9d9b0f9102..a4307ea336d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1944,6 +1944,11 @@ static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], Gea int i; float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3) + if(max_index > 3) { + printf("applyGrid: invalid index %d, clamping\n", max_index); + max_index= 3; + } + // Early bailing out if no need to snap if (fac[action] == 0.0f) return; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index d0393c970a6..70659994c55 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1060,8 +1060,8 @@ static void weld_align_uv(bContext *C, int tool) if(tool == 's' || tool == 't' || tool == 'u') { /* pass 1&2 variables */ int i, j; - int starttmpl= -1, connectedtostarttmpl, startcorner; - int endtmpl= -1, connectedtoendtmpl, endcorner; + int starttmpl= -1, connectedtostarttmpl= -1, startcorner; + int endtmpl= -1, connectedtoendtmpl= -1, endcorner; MTFace *startface, *endface; int itmpl, jtmpl; EditVert *eve; diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 9018fd8c71a..21fa28af01a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -544,7 +544,7 @@ void RNA_api_object(StructRNA *srna) /* location of point for test and max distance */ parm= RNA_def_float_vector(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); RNA_def_property_flag(parm, PROP_REQUIRED); - parm= RNA_def_float(func, "max_dist", sqrt(FLT_MAX), 0.0, FLT_MAX, "", "", 0.0, FLT_MAX); + RNA_def_float(func, "max_dist", sqrt(FLT_MAX), 0.0, FLT_MAX, "", "", 0.0, FLT_MAX); /* return location and normal */ parm= RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The location on the object closest to the point", -1e4, 1e4); -- cgit v1.2.3 From 3e81de486a648d06660e3cc2355698b1c27965a5 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 26 Jul 2011 16:01:09 +0000 Subject: RNA: function calls with optional parameters were not giving correct default values for arrays. --- source/blender/makesrna/intern/rna_access.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index d9fbdd7caf2..dcf2400b9ba 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -4407,15 +4407,15 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE if(!(parm->flag & PROP_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) { switch(parm->type) { case PROP_BOOLEAN: - if(parm->arraydimension) memcpy(data, &((BooleanPropertyRNA*)parm)->defaultarray, size); + if(parm->arraydimension) memcpy(data, ((BooleanPropertyRNA*)parm)->defaultarray, size); else memcpy(data, &((BooleanPropertyRNA*)parm)->defaultvalue, size); break; case PROP_INT: - if(parm->arraydimension) memcpy(data, &((IntPropertyRNA*)parm)->defaultarray, size); + if(parm->arraydimension) memcpy(data, ((IntPropertyRNA*)parm)->defaultarray, size); else memcpy(data, &((IntPropertyRNA*)parm)->defaultvalue, size); break; case PROP_FLOAT: - if(parm->arraydimension) memcpy(data, &((FloatPropertyRNA*)parm)->defaultarray, size); + if(parm->arraydimension) memcpy(data, ((FloatPropertyRNA*)parm)->defaultarray, size); else memcpy(data, &((FloatPropertyRNA*)parm)->defaultvalue, size); break; case PROP_ENUM: -- cgit v1.2.3 From a460299b08303d3cfbd9b83d036d87351cb52693 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 19:47:56 +0000 Subject: - bugfix for icon listview where the icons would only wrap once - also quiet some clang warnings --- source/blender/editors/interface/interface_handlers.c | 11 +++++------ source/blender/editors/interface/interface_layout.c | 2 +- source/blender/editors/interface/interface_panel.c | 4 ++-- source/blender/editors/interface/interface_templates.c | 3 +-- 4 files changed, 9 insertions(+), 11 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index e9ec4ccc66d..c5275ea98b5 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1879,7 +1879,6 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle if(but->autocomplete_func || data->searchbox) { changed= ui_textedit_autocomplete(C, but, data); update= 1; /* do live update for tab key */ - retval= WM_UI_HANDLER_BREAK; } /* the hotkey here is not well defined, was G.qual so we check all */ else if(event->shift || event->ctrl || event->alt || event->oskey) { @@ -2325,8 +2324,8 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa if(fac != 1.0f) { /* snap in unit-space */ tempf /= fac; - softmin /= fac; - softmax /= fac; + /* softmin /= fac; */ /* UNUSED */ + /* softmax /= fac; */ /* UNUSED */ softrange /= fac; } @@ -3469,13 +3468,13 @@ static int ui_numedit_but_CURVE(uiBut *but, uiHandleButtonData *data, int snap, CurveMapping *cumap= (CurveMapping*)but->poin; CurveMap *cuma= cumap->cm+cumap->cur; CurveMapPoint *cmp= cuma->curve; - float fx, fy, zoomx, zoomy, offsx, offsy; + float fx, fy, zoomx, zoomy /*, offsx, offsy */ /* UNUSED */; int a, changed= 0; zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin); zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin); - offsx= cumap->curr.xmin; - offsy= cumap->curr.ymin; + /* offsx= cumap->curr.xmin; */ + /* offsy= cumap->curr.ymin; */ if(snap) { float d[2]; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 79a90fb9d1d..b309198d937 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1615,7 +1615,7 @@ static void ui_litem_layout_row(uiLayout *litem) int x, y, w, tot, totw, neww, itemw, minw, itemh, offset; int fixedw, freew, fixedx, freex, flag= 0, lastw= 0; - x= litem->x; + /* x= litem->x; */ /* UNUSED */ y= litem->y; w= litem->w; totw= 0; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 9ed3cabb4cb..3b20533dcd4 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -575,8 +575,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, rcti *rect) ui_draw_tria_rect(&itemrect, 'h'); else ui_draw_tria_rect(&itemrect, 'v'); - - + + (void)ofsx; } /************************** panel alignment *************************/ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index f388710d5b8..34315494e14 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2197,7 +2197,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char * /* create list items */ RNA_PROP_BEGIN(ptr, itemptr, prop) { /* create button */ - if(i == 9) + if(!(i % 9)) row= uiLayoutRow(col, 0); icon= list_item_icon_get(C, &itemptr, rnaicon, 1); @@ -2212,7 +2212,6 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char * } else if(listtype == 'c') { /* compact layout */ - found= 0; row= uiLayoutRow(layout, 1); -- cgit v1.2.3 From 955ba3f7fb5bca6d454ee6a1158cbdc094d6d060 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 26 Jul 2011 20:22:54 +0000 Subject: * Fixed a typo in the code (uiLayoutItemSplt -> uiLayoutItemSplit) --- source/blender/editors/interface/interface_layout.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b309198d937..2f0bcc9d5b4 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -149,10 +149,10 @@ typedef struct uiLayoutItemBx { uiBut *roundbox; } uiLayoutItemBx; -typedef struct uiLayoutItemSplt { +typedef struct uiLayoutItemSplit { uiLayout litem; float percentage; -} uiLayoutItemSplt; +} uiLayoutItemSplit; typedef struct uiLayoutItemRoot { uiLayout litem; @@ -2020,7 +2020,7 @@ static void ui_litem_estimate_split(uiLayout *litem) static void ui_litem_layout_split(uiLayout *litem) { - uiLayoutItemSplt *split= (uiLayoutItemSplt*)litem; + uiLayoutItemSplit *split= (uiLayoutItemSplit*)litem; uiItem *item; float percentage; const int tot= BLI_countlist(&litem->items); @@ -2242,9 +2242,9 @@ uiLayout *uiLayoutOverlap(uiLayout *layout) uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align) { - uiLayoutItemSplt *split; + uiLayoutItemSplit *split; - split= MEM_callocN(sizeof(uiLayoutItemSplt), "uiLayoutItemSplt"); + split= MEM_callocN(sizeof(uiLayoutItemSplit), "uiLayoutItemSplit"); split->litem.item.type= ITEM_LAYOUT_SPLIT; split->litem.root= layout->root; split->litem.align= align; -- cgit v1.2.3 From 48a64ffa702b0b7599aa8d8071d4a2265e9ba122 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 27 Jul 2011 06:55:20 +0000 Subject: more minor warning cleanups and improve error reporting if text fails to save. --- source/blender/blenkernel/intern/seqeffects.c | 2 +- source/blender/blenkernel/intern/text.c | 2 ++ source/blender/editors/armature/editarmature.c | 2 -- source/blender/editors/space_node/node_draw.c | 13 +++++++------ .../blender/editors/space_sequencer/sequencer_add.c | 6 +++--- source/blender/editors/space_text/text_ops.c | 21 +++++++++++++-------- source/blender/gpu/intern/gpu_material.c | 2 +- 7 files changed, 27 insertions(+), 21 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index fbb5a77fa04..8c19b0c15c3 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -2373,7 +2373,7 @@ static void RVBlurBitmap2_float ( float* map, int width,int height, /* Blancmange (bmange@airdmhor.gen.nz) */ k = -1.0f/(2.0f*(float)M_PI*blur*blur); - fval=0; + for (ix = 0;ix< halfWidth;ix++){ weight = (float)exp(k*(ix*ix)); filter[halfWidth - ix] = weight; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 56723476251..2c507370288 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1423,6 +1423,8 @@ void txt_insert_buf(Text *text, const char *in_buffer) } undoing= u; + + (void)count; } /******************/ diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 20352206121..628cdbf21e9 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -1478,10 +1478,8 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, wmEvent *e bArmature *arm; EditBone *bone, *curBone, *next; int extend= RNA_boolean_get(op->ptr, "extend"); - ARegion *ar; Object *obedit= CTX_data_edit_object(C); arm= obedit->data; - ar= CTX_wm_region(C); view3d_operator_needs_opengl(C); diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index cd1fa5c16a7..950b3c72fe7 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -781,14 +781,15 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } { /* always hide/reveal unused sockets */ - int shade; - - iconofs-=iconbutw; // XXX re-enable - /*if(node_has_hidden_sockets(node)) + /* int shade; + if(node_has_hidden_sockets(node)) shade= -40; - else*/ - shade= -90; + else + shade= -90; */ + + iconofs-=iconbutw; + uiDefIconBut(node->block, LABEL, B_REDR, ICON_PLUS, iconofs, rct->ymax-NODE_DY, iconbutw, UI_UNIT_Y, NULL, 0.0, 0.0, 1.0, 0.5, ""); } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index f6e3dc3dd0a..36e334990cb 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -303,7 +303,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad Scene *scene= CTX_data_scene(C); /* only for sound */ Editing *ed= seq_give_editing(scene, TRUE); SeqLoadInfo seq_load; - Sequence *seq; + /* Sequence *seq; */ /* UNUSED */ int tot_files; seq_load_operator_info(&seq_load, op); @@ -324,13 +324,13 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad RNA_string_get(&itemptr, "name", file_only); BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only); - seq= seq_load_func(C, ed->seqbasep, &seq_load); + /* seq= */ seq_load_func(C, ed->seqbasep, &seq_load); } RNA_END; } else { /* single file */ - seq= seq_load_func(C, ed->seqbasep, &seq_load); + /* seq= */ seq_load_func(C, ed->seqbasep, &seq_load); } if (seq_load.tot_success==0) { diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 2bd6bd624df..13eb24ed1f2 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -36,6 +36,7 @@ #include #include /* ispunct */ #include +#include #include "MEM_guardedalloc.h" @@ -449,15 +450,14 @@ static void txt_write_file(Text *text, ReportList *reports) FILE *fp; TextLine *tmp; struct stat st; - int res; - char file[FILE_MAXDIR+FILE_MAXFILE]; + char filepath[FILE_MAXDIR+FILE_MAXFILE]; - BLI_strncpy(file, text->name, FILE_MAXDIR+FILE_MAXFILE); - BLI_path_abs(file, G.main->name); + BLI_strncpy(filepath, text->name, FILE_MAXDIR+FILE_MAXFILE); + BLI_path_abs(filepath, G.main->name); - fp= fopen(file, "w"); + fp= fopen(filepath, "w"); if(fp==NULL) { - BKE_report(reports, RPT_ERROR, "Unable to save file."); + BKE_reportf(reports, RPT_ERROR, "Unable to save \"%s\": %s.", filepath, errno ? strerror(errno) : "Unknown error writing file"); return; } @@ -471,8 +471,13 @@ static void txt_write_file(Text *text, ReportList *reports) fclose (fp); - res= stat(file, &st); - text->mtime= st.st_mtime; + if(stat(filepath, &st) == 0) { + text->mtime= st.st_mtime; + } + else { + text->mtime= 0; + BKE_reportf(reports, RPT_WARNING, "Unable to stat \"%s\": %s.", filepath, errno ? strerror(errno) : "Unknown error starrng file"); + } if(text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 3804aad6848..806c70d841f 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -671,7 +671,7 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la i = is; GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i); - vn = shi->vn; + /*if(ma->mode & MA_TANGENT_VN) GPU_link(mat, "shade_tangent_v_spec", GPU_attribute(CD_TANGENT, ""), &vn);*/ -- cgit v1.2.3 From 46cea372669f25b691fd90dc792a1fee33e36887 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 27 Jul 2011 07:22:31 +0000 Subject: fix [#28066] Unchecking 'self project' messes up 'Snap to Vertex' this option is useful for all non-grid snapping modes (when in editmode) so make available in those cases too. --- source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_snap.c | 8 ++++---- source/blender/makesdna/DNA_scene_types.h | 2 +- source/blender/makesrna/intern/rna_scene.c | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d8e750acb88..d8e42488787 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -96,7 +96,7 @@ typedef struct TransSnap { short modeSelect; short align; char project; - char project_self; + char snap_self; short peel; short status; float snapPoint[3]; /* snapping from this point */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index a4307ea336d..933d90ebbf2 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -392,7 +392,7 @@ static void initSnappingMode(TransInfo *t) } else { - t->tsnap.modeSelect = t->tsnap.project_self ? SNAP_ALL : SNAP_NOT_OBEDIT; + t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT; } } /* Particles edit mode*/ @@ -458,9 +458,9 @@ void initSnapping(TransInfo *t, wmOperator *op) t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project"); } - if (RNA_struct_find_property(op->ptr, "use_snap_project_self")) + if (RNA_struct_find_property(op->ptr, "use_snap_self")) { - t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project_self"); + t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self"); } } } @@ -473,7 +473,7 @@ void initSnapping(TransInfo *t, wmOperator *op) t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE); t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); - t->tsnap.project_self = !((t->settings->snap_flag & SCE_SNAP_PROJECT_NO_SELF) == SCE_SNAP_PROJECT_NO_SELF); + t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) == SCE_SNAP_NO_SELF); t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8203a4dd77c..2211f93a8ae 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1074,7 +1074,7 @@ typedef struct Scene { #define SCE_SNAP_ROTATE 2 #define SCE_SNAP_PEEL_OBJECT 4 #define SCE_SNAP_PROJECT 8 -#define SCE_SNAP_PROJECT_NO_SELF 16 +#define SCE_SNAP_NO_SELF 16 /* toolsettings->snap_target */ #define SCE_SNAP_TARGET_CLOSEST 0 #define SCE_SNAP_TARGET_CENTER 1 diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d9475eaa683..f4028e45e96 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1178,9 +1178,9 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_RETOPO, 0); RNA_def_property_update(prop, NC_SCENE|ND_TOOLSETTINGS, NULL); /* header redraw */ - prop= RNA_def_property(srna, "use_snap_project_self", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_PROJECT_NO_SELF); - RNA_def_property_ui_text(prop, "Project to Self", "Project into its self (editmode)"); + prop= RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF); + RNA_def_property_ui_text(prop, "Project to Self", "Snap onto its self (editmode)"); RNA_def_property_ui_icon(prop, ICON_ORTHO, 0); RNA_def_property_update(prop, NC_SCENE|ND_TOOLSETTINGS, NULL); /* header redraw */ -- cgit v1.2.3 From 3b6cb504b199471d0a3c80b917d16b11827ae84e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 27 Jul 2011 13:03:56 +0000 Subject: minor warning fixes for clang-static-checker --- source/blender/blenkernel/intern/cdderivedmesh.c | 2 ++ source/blender/blenkernel/intern/customdata.c | 1 - source/blender/editors/transform/transform_snap.c | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 3abfa05e1fd..662c872b7f1 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -1287,6 +1287,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang); offset += sizeof(float)*4; } + (void)offset; } curface++; if(mface->v4) { @@ -1327,6 +1328,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang); offset += sizeof(float)*4; } + (void)offset; } curface++; i++; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 45faba8439c..8d19322c0db 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -466,7 +466,6 @@ static void layerInterp_mdisps(void **sources, float *UNUSED(weights), MDisps tris[2]; int vindex[4] = {0}; - S = 0; for(i = 0; i < 2; i++) for(y = 0; y < 4; y++) for(x = 0; x < 4; x++) diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 933d90ebbf2..f677e1ac6b4 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1944,9 +1944,9 @@ static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], Gea int i; float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3) - if(max_index > 3) { + if(max_index > 2) { printf("applyGrid: invalid index %d, clamping\n", max_index); - max_index= 3; + max_index= 2; } // Early bailing out if no need to snap -- cgit v1.2.3 From 7e466266d36f326798de150e7d7d27a81a0e9ee5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 27 Jul 2011 17:49:35 +0000 Subject: fix [#28098] Continuous Grab does not work for movement of the "Backdrop" in the Node Editor --- source/blender/editors/space_node/node_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 4230a43d2ec..18d4d85e3ff 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1101,7 +1101,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot) ot->cancel= snode_bg_viewmove_cancel; /* flags */ - ot->flag= OPTYPE_BLOCKING; + ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER; } static int backimage_zoom(bContext *C, wmOperator *op) -- cgit v1.2.3 From f532ccedf5c3898a5726ba4295297ebb58ba4909 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 27 Jul 2011 20:36:11 +0000 Subject: refix for #27912: crash after mesh.materials.pop() (fixed wrongly on rev. 38299 - patch by Benoit Boilsee bug spotted while reviewing a patch. things are working now --- source/blender/blenkernel/intern/material.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 962c7fd5e86..3f01c55e935 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -550,7 +550,7 @@ Material *material_pop_id(ID *id, int index) Material **mat; if(index + 1 != (*totcol)) - memmove((*matar), (*matar) + 1, sizeof(void *) * ((*totcol) - (index + 1))); + memmove((*matar)+index, (*matar)+(index+1), sizeof(void *) * ((*totcol) - (index + 1))); (*totcol)--; -- cgit v1.2.3 From 7e87165eea9af2e0e9b9e2192341a5a0842bc81e Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Thu, 28 Jul 2011 00:08:03 +0000 Subject: Don't write library_materials tag when there are no materials. --- source/blender/collada/MaterialExporter.cpp | 32 +++++++++++++++++++++++++---- source/blender/collada/MaterialExporter.h | 3 +++ 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/collada/MaterialExporter.cpp b/source/blender/collada/MaterialExporter.cpp index a44fa6802f2..9d29177578d 100644 --- a/source/blender/collada/MaterialExporter.cpp +++ b/source/blender/collada/MaterialExporter.cpp @@ -37,12 +37,36 @@ MaterialsExporter::MaterialsExporter(COLLADASW::StreamWriter *sw): COLLADASW::Li void MaterialsExporter::exportMaterials(Scene *sce, bool export_selected) { - openLibrary(); + if(hasMaterials(sce)) { + openLibrary(); - MaterialFunctor mf; - mf.forEachMaterialInScene(sce, *this, export_selected); + MaterialFunctor mf; + mf.forEachMaterialInScene(sce, *this, export_selected); - closeLibrary(); + closeLibrary(); + } +} + + +bool MaterialsExporter::hasMaterials(Scene *sce) +{ + Base *base = (Base *)sce->base.first; + + while(base) { + Object *ob= base->object; + int a; + for(a = 0; a < ob->totcol; a++) + { + Material *ma = give_current_material(ob, a+1); + + // no material, but check all of the slots + if (!ma) continue; + + return true; + } + base= base->next; + } + return false; } void MaterialsExporter::operator()(Material *ma, Object *ob) diff --git a/source/blender/collada/MaterialExporter.h b/source/blender/collada/MaterialExporter.h index 0a7a276d857..c080e4b0596 100644 --- a/source/blender/collada/MaterialExporter.h +++ b/source/blender/collada/MaterialExporter.h @@ -51,6 +51,9 @@ public: MaterialsExporter(COLLADASW::StreamWriter *sw); void exportMaterials(Scene *sce, bool export_selected); void operator()(Material *ma, Object *ob); + +private: + bool hasMaterials(Scene *sce); }; // used in forEachMaterialInScene -- cgit v1.2.3 From a5631dba8902b8f6732b88ddcc2ef2ba36c49b75 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 02:15:58 +0000 Subject: only initialize snap from the scene settings for view3d and image spaces since snap in the 3D view was enabling snap in the graph editor and sequencer without a button to disable it in those spaces. --- source/blender/editors/transform/transform_snap.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index f677e1ac6b4..ca89670dedb 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -467,14 +467,17 @@ void initSnapping(TransInfo *t, wmOperator *op) /* use scene defaults only when transform is modal */ else if (t->flag & T_MODAL) { - if (ts->snap_flag & SCE_SNAP) { - t->modifiers |= MOD_SNAP; - } + if(ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) + { + if (ts->snap_flag & SCE_SNAP) { + t->modifiers |= MOD_SNAP; + } - t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE); - t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); - t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) == SCE_SNAP_NO_SELF); - t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); + t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE); + t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); + t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) == SCE_SNAP_NO_SELF); + t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT); + } } t->tsnap.target = snap_target; -- cgit v1.2.3 From 784a68e8f1047de0e71beabbc44654ccad743910 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 03:44:17 +0000 Subject: sequencer add strips now check for overlap by default (option can be disabled for python when this can become problematic for automation). --- .../editors/space_sequencer/sequencer_add.c | 33 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 36e334990cb..b105b2507ab 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -101,6 +101,8 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) RNA_def_boolean(ot->srna, "replace_sel", 1, "Replace Selection", "replace the current selection"); + RNA_def_boolean(ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips"); + if(flag & SEQPROP_FILES) RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", ""); } @@ -250,7 +252,11 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op) seq_active_set(scene, seq); seq->flag |= SELECT; } - + + if(RNA_boolean_get(op->ptr, "overlap") == FALSE) { + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + } + WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -303,8 +309,9 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad Scene *scene= CTX_data_scene(C); /* only for sound */ Editing *ed= seq_give_editing(scene, TRUE); SeqLoadInfo seq_load; - /* Sequence *seq; */ /* UNUSED */ + Sequence *seq; int tot_files; + const short overlap= RNA_boolean_get(op->ptr, "overlap"); seq_load_operator_info(&seq_load, op); @@ -324,13 +331,21 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad RNA_string_get(&itemptr, "name", file_only); BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only); - /* seq= */ seq_load_func(C, ed->seqbasep, &seq_load); + seq= seq_load_func(C, ed->seqbasep, &seq_load); + + if(overlap == FALSE) { + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + } } RNA_END; } else { /* single file */ - /* seq= */ seq_load_func(C, ed->seqbasep, &seq_load); + seq= seq_load_func(C, ed->seqbasep, &seq_load); + + if(overlap == FALSE) { + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + } } if (seq_load.tot_success==0) { @@ -506,7 +521,11 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op) /* last active name */ strncpy(ed->act_imagedir, strip->dir, FILE_MAXDIR-1); - + + if(RNA_boolean_get(op->ptr, "overlap") == FALSE) { + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + } + WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene); return OPERATOR_FINISHED; @@ -656,7 +675,9 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op) } } - if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + if(RNA_boolean_get(op->ptr, "overlap") == FALSE) { + if(seq_test_overlap(ed->seqbasep, seq)) shuffle_seq(ed->seqbasep, seq, scene); + } update_changed_seq_and_deps(scene, seq, 1, 1); /* runs calc_sequence */ -- cgit v1.2.3 From 2dc826f083c2209aab83981a8d1dc39c621e0841 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 28 Jul 2011 11:16:10 +0000 Subject: New option for multires modifier: Subdivide UVs Enabled by default and also enabled for older filesm so there should be no regressions. In some cases it's useful to not use subdivided uvs for multires. --- source/blender/blenkernel/intern/multires.c | 18 ++++++++++-------- source/blender/makesdna/DNA_modifier_types.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 5 +++++ 3 files changed, 16 insertions(+), 8 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index d833c184274..88a670ecb22 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -465,12 +465,13 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0); } -static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal) +static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv) { SubsurfModifierData smd= {{NULL}}; smd.levels = smd.renderLevels = lvl; - smd.flags |= eSubsurfModifierFlag_SubsurfUv; + if(!plain_uv) + smd.flags |= eSubsurfModifierFlag_SubsurfUv; if(simple) smd.subdivType = ME_SIMPLE_SUBSURF; if(optimal) @@ -591,7 +592,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* subdivide the mesh to highest level without displacements */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0); + origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); /* calc disps */ @@ -626,7 +627,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create subsurf DM from original mesh at high level */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); /* create multires DM from original mesh at low level */ lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple); @@ -830,7 +831,7 @@ static void multiresModifier_update(DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); /* create multires DM from original mesh and displacements */ lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple); @@ -884,7 +885,7 @@ static void multiresModifier_update(DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0); + subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl); @@ -927,7 +928,8 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca return dm; result = subsurf_dm_create_local(ob, dm, lvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges); + mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, + mmd->flags & eMultiresModifierFlag_PlainUv); if(!local_mmd) { ccgdm = (CCGDerivedMesh*)result; @@ -1633,7 +1635,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) MEM_freeN(vertCos); /* scaled ccgDM for tangent space of object with applied scale */ - dm= subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0); + dm= subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); cddm->release(cddm); /*numGrids= dm->getNumGrids(dm);*/ /*UNUSED*/ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index d2d8e014015..3787675f339 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -624,6 +624,7 @@ typedef struct MultiresModifierData { typedef enum { eMultiresModifierFlag_ControlEdges = (1<<0), + eMultiresModifierFlag_PlainUv = (1<<1), } MultiresModifierFlag; typedef struct FluidsimModifierData { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index d2c1b862fee..ba655915fb6 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -805,6 +805,11 @@ static void rna_def_modifier_multires(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flags", eMultiresModifierFlag_ControlEdges); RNA_def_property_ui_text(prop, "Optimal Display", "Skip drawing/rendering of interior subdivided edges"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop= RNA_def_property(srna, "use_subsurf_uv", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flags", eMultiresModifierFlag_PlainUv); + RNA_def_property_ui_text(prop, "Subdivide UVs", "Use subsurf to subdivide UVs"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); } static void rna_def_modifier_lattice(BlenderRNA *brna) -- cgit v1.2.3 From b948459031dd6d0f1ccc81d607a589fd7d1e8ab2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 12:17:24 +0000 Subject: fix [#28096] Custom gradient for weightpainting in mask mode not working properly. --- source/blender/editors/interface/resources.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 3f825762d74..56ef5e9e8cc 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1115,10 +1115,11 @@ void init_userdef_do_versions(void) } if(U.pad_rot_angle==0) U.pad_rot_angle= 15; - - if(U.flag & USER_CUSTOM_RANGE) - vDM_ColorBand_store(&U.coba_weight); /* signal for derivedmesh to use colorband */ - + + /* signal for derivedmesh to use colorband */ + /* run incase this was on and is now off in the user prefs [#28096] */ + vDM_ColorBand_store((U.flag & USER_CUSTOM_RANGE) ? (&U.coba_weight):NULL); + if (bmain->versionfile <= 191) { strcpy(U.plugtexdir, U.textudir); strcpy(U.sounddir, "/"); -- cgit v1.2.3