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(-) 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(-) 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(-) 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 + source/blenderplayer/CMakeLists.txt | 1 + source/creator/CMakeLists.txt | 1 + source/gameengine/Expressions/PyObjectPlus.h | 2 +- source/gameengine/Ketsji/CMakeLists.txt | 1 + source/gameengine/Ketsji/KX_PyMath.h | 2 +- source/gameengine/Ketsji/KX_PythonInit.cpp | 4 +- source/gameengine/Ketsji/SConscript | 3 +- 42 files changed, 9242 insertions(+), 9189 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 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 */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 9c60cdac22b..ddfdfc97bdc 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -121,6 +121,7 @@ endif() bf_intern_guardedalloc bf_intern_memutil bf_python_ext + bf_python_mathutils bf_blenlib bf_imbuf_cineon bf_imbuf_openexr diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index dc19742c057..43fec85b5bf 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -768,6 +768,7 @@ endif() bf_intern_opennl bf_python bf_python_ext + bf_python_mathutils bf_ikplugin bf_modifiers bf_blenkernel diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 157124ebc81..587f3e4ef35 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -54,7 +54,7 @@ #ifdef WITH_PYTHON #ifdef USE_MATHUTILS extern "C" { -#include "../../blender/python/generic/mathutils.h" /* so we can have mathutils callbacks */ +#include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */ } #endif diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index b5a63f44729..7b3906e0846 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -40,6 +40,7 @@ set(INC ../../../source/blender/blenkernel ../../../source/blender/python ../../../source/blender/python/generic + ../../../source/blender/python/mathutils ../../../source/blender ../../../source/blender/makesdna ../../../source/gameengine/Rasterizer diff --git a/source/gameengine/Ketsji/KX_PyMath.h b/source/gameengine/Ketsji/KX_PyMath.h index 9b198f85664..4864482c33b 100644 --- a/source/gameengine/Ketsji/KX_PyMath.h +++ b/source/gameengine/Ketsji/KX_PyMath.h @@ -49,7 +49,7 @@ #ifdef WITH_PYTHON #ifdef USE_MATHUTILS extern "C" { -#include "../../blender/python/generic/mathutils.h" /* so we can have mathutils callbacks */ +#include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */ } #endif diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index a927de60cd8..f643030e3a2 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -54,7 +54,7 @@ extern "C" { #include "bpy_internal_import.h" /* from the blender python api, but we want to import text too! */ #include "py_capi_utils.h" - #include "mathutils.h" // Blender.Mathutils module copied here so the blenderlayer can use. + #include "mathutils.h" // 'mathutils' module copied here so the blenderlayer can use. #include "bgl.h" #include "blf_py_api.h" @@ -1749,7 +1749,7 @@ static void restorePySysObjects(void) // Copied from bpy_interface.c static struct _inittab bge_internal_modules[]= { - {(char *)"mathutils", BPyInit_mathutils}, + {(char *)"mathutils", PyInit_mathutils}, {(char *)"bgl", BPyInit_bgl}, {(char *)"blf", BPyInit_blf}, {(char *)"aud", AUD_initPython}, diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript index 08642262724..62caa602c23 100644 --- a/source/gameengine/Ketsji/SConscript +++ b/source/gameengine/Ketsji/SConscript @@ -6,7 +6,8 @@ Import ('env') sources = env.Glob('*.cpp') defs = [ 'GLEW_STATIC' ] -incs = '. #source/blender/python/generic' # Only for Mathutils! and bpy_internal_import.h, be very careful +incs = '. #source/blender/python/generic' # Only for bpy_internal_import.h, be very careful +incs += ' #source/blender/python/mathutils' # Only for mathutils, be very careful incs += ' #intern/string #intern/guardedalloc #intern/container' incs += ' #source/gameengine/Rasterizer/RAS_OpenGLRasterizer' -- 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(-) 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(-) 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(-) 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 2d8c1e60e695df3f001f0181bea845a356e14b47 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 16 Jul 2011 06:55:45 +0000 Subject: print an error message if Python.h can't be found for cmake and scons since its such a common problem. --- CMakeLists.txt | 86 +++++++++++++++++++++++++++--------------- SConstruct | 17 +++++++++ intern/mikktspace/mikktspace.c | 4 +- 3 files changed, 75 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5cd23ab66a..ebf7aa8a6c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -729,10 +729,14 @@ elseif(WIN32) endif() if(WITH_PYTHON) - set(PYTHON_VERSION 3.2) - set(PYTHON_INCLUDE_DIRS "${LIBDIR}/python/include/python${PYTHON_VERSION}") - # set(PYTHON_BINARY python) # not used yet - set(PYTHON_LIBRARIES ${LIBDIR}/python/lib/python32.lib) + # normally cached but not since we include them with blender + set(PYTHON_VERSION 3.2) # CACHE STRING) + set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH) + set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python32.lib") #CACHE FILEPATH) + + # uncached vars + set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") + set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") endif() set(PLATFORM_LINKFLAGS "/SUBSYSTEM:CONSOLE /STACK:2097152 /INCREMENTAL:NO /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:msvcmrt.lib /NODEFAULTLIB:msvcurt.lib /NODEFAULTLIB:msvcrtd.lib") @@ -832,12 +836,14 @@ elseif(WIN32) endif() if(WITH_PYTHON) - set(PYTHON ${LIBDIR}/python) - set(PYTHON_VERSION 3.2) - set(PYTHON_INCLUDE_DIRS "${PYTHON}/include/python${PYTHON_VERSION}") - # set(PYTHON_BINARY python) # not used yet - set(PYTHON_LIBRARIES ${PYTHON}/lib/python32mw.lib) - set(PYTHON_LIBPATH ${PYTHON}/lib) + # normally cached but not since we include them with blender + set(PYTHON_VERSION 3.2) # CACHE STRING) + set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") # CACHE PATH) + set(PYTHON_LIBRARY "${LIBDIR}/python/lib/python32mw.lib") # CACHE FILEPATH) + + # uncached vars + set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") + set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") endif() set(PLATFORM_LINKFLAGS "--stack,2097152") @@ -888,27 +894,33 @@ elseif(APPLE) set(SNDFILE_LIBPATH ${SNDFILE}/lib ${FFMPEG}/lib) # TODO, deprecate endif() - set(PYTHON_VERSION 3.2) - - if(PYTHON_VERSION MATCHES 3.2) - # we use precompiled libraries for py 3.2 and up by default - - set(PYTHON ${LIBDIR}/python) - set(PYTHON_INCLUDE_DIRS "${PYTHON}/include/python${PYTHON_VERSION}") - # set(PYTHON_BINARY "${PYTHON}/bin/python${PYTHON_VERSION}") # not used yet - set(PYTHON_LIBRARIES python${PYTHON_VERSION}) - set(PYTHON_LIBPATH "${PYTHON}/lib/python${PYTHON_VERSION}") - # set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled - else() - # otherwise, use custom system framework - - set(PYTHON /System/Library/Frameworks/Python.framework/Versions/) + if(WITH_PYTHON) set(PYTHON_VERSION 3.2) - set(PYTHON_INCLUDE_DIRS "${PYTHON}${PYTHON_VERSION}/include/python${PYTHON_VERSION}") - # set(PYTHON_BINARY ${PYTHON}${PYTHON_VERSION}/bin/python${PYTHON_VERSION}) # not used yet - set(PYTHON_LIBRARIES "") - set(PYTHON_LIBPATH ${PYTHON}${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config) - set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework System -framework Python") + if(PYTHON_VERSION MATCHES 3.2) + # we use precompiled libraries for py 3.2 and up by default + + # normally cached but not since we include them with blender + set(PYTHON_INCLUDE_DIR "${LIBDIR}/python/include/python${PYTHON_VERSION}") + # set(PYTHON_BINARY "${LIBDIR}/python/bin/python${PYTHON_VERSION}") # not used yet + set(PYTHON_LIBRARY python${PYTHON_VERSION}) + set(PYTHON_LIBPATH "${LIBDIR}/python/lib/python${PYTHON_VERSION}") + # set(PYTHON_LINKFLAGS "-u _PyMac_Error") # won't build with this enabled + else() + # otherwise, use custom system framework + # *not used but maintained incase some dev wants to* + + set(PYTHON "/System/Library/Frameworks/Python.framework/Versions/" CACHE PATH) + set(PYTHON_INCLUDE_DIR "${PYTHON}${PYTHON_VERSION}/include/python${PYTHON_VERSION}" CACHE PATH) + # set(PYTHON_BINARY ${PYTHON}${PYTHON_VERSION}/bin/python${PYTHON_VERSION}) # not used yet + set(PYTHON_LIBRARY "" CACHE FILEPATH) + set(PYTHON_LIBPATH "${PYTHON}${PYTHON_VERSION}/lib/python${PYTHON_VERSION}/config" CACHE PATH) + set(PYTHON_LINKFLAGS "-u _PyMac_Error -framework System -framework Python" CACHE STRING) + unset(PYTHON) + endif() + + # uncached vars + set(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") + set(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") endif() if(WITH_INTERNATIONAL) @@ -1203,6 +1215,20 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() endif() + +# ensure python header is found since detection can fail, this could happen +# with _any_ library but since we used a fixed python version this tends to +# be most problematic. +if(WITH_PYTHON) + if(NOT EXISTS "${PYTHON_INCLUDE_DIR}/Python.h") + message(FATAL_ERROR "Missing: \"${PYTHON_INCLUDE_DIR}/Python.h\",\n" + "Set the cache entry 'PYTHON_INCLUDE_DIR' to point " + "to a valid python include path. Containing " + "Python.h for python version \"${PYTHON_VERSION}\"") + endif() +endif() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS} ${C_WARNINGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS} ${CXX_WARNINGS}") diff --git a/SConstruct b/SConstruct index 29146018704..053f414c954 100644 --- a/SConstruct +++ b/SConstruct @@ -361,6 +361,23 @@ if not quickie and do_clean: print B.bc.HEADER+'Already Clean, nothing to do.'+B.bc.ENDC Exit() + +# ensure python header is found since detection can fail, this could happen +# with _any_ library but since we used a fixed python version this tends to +# be most problematic. +if env['WITH_BF_PYTHON']: + py_h = os.path.join(Dir(env.subst('${BF_PYTHON_INC}')).abspath, "Python.h") + + if not os.path.exists(py_h): + print("\nMissing: \"" + env.subst('${BF_PYTHON_INC}') + os.sep + "Python.h\",\n" + " Set 'BF_PYTHON_INC' to point " + "to a valid python include path.\n Containing " + "Python.h for python version \"" + env.subst('${BF_PYTHON_VERSION}') + "\"") + + Exit() + del py_h + + if not os.path.isdir ( B.root_build_dir): os.makedirs ( B.root_build_dir ) os.makedirs ( B.root_build_dir + 'source' ) diff --git a/intern/mikktspace/mikktspace.c b/intern/mikktspace/mikktspace.c index c05ada84773..1bb73553012 100644 --- a/intern/mikktspace/mikktspace.c +++ b/intern/mikktspace/mikktspace.c @@ -243,7 +243,7 @@ tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThre int iNrActiveGroups = 0, index = 0; const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); tbool bRes = TFALSE; - const float fThresCos = (const float) cos((fAngularThreshold*(float)M_PI)/180.0f); + const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); // verify all call-backs have been set if( pContext->m_pInterface->m_getNumFaces==NULL || @@ -1411,7 +1411,7 @@ STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[] // weight contribution by the angle // between the two edge vectors fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); - fAngle = (const float) acos(fCos); + fAngle = (float) acos(fCos); fMagS = pTriInfos[f].fMagS; fMagT = pTriInfos[f].fMagT; -- 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(-) 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. --- extern/glew/CMakeLists.txt | 4 +- extern/lzo/CMakeLists.txt | 2 +- intern/audaspace/CMakeLists.txt | 60 ++++++++++++++++------ intern/ghost/CMakeLists.txt | 16 ++++-- intern/smoke/CMakeLists.txt | 4 +- 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 ++++-- source/gameengine/GameLogic/CMakeLists.txt | 4 +- source/gameengine/Ketsji/CMakeLists.txt | 4 +- 25 files changed, 202 insertions(+), 80 deletions(-) diff --git a/extern/glew/CMakeLists.txt b/extern/glew/CMakeLists.txt index 35beacab6a3..a7ebe36f950 100644 --- a/extern/glew/CMakeLists.txt +++ b/extern/glew/CMakeLists.txt @@ -33,7 +33,9 @@ set(INC_SYS ) if(UNIX) - list(APPEND INC_SYS ${X11_X11_INCLUDE_PATH}) + list(APPEND INC_SYS + ${X11_X11_INCLUDE_PATH} + ) endif() set(SRC diff --git a/extern/lzo/CMakeLists.txt b/extern/lzo/CMakeLists.txt index 10ea2c58f7c..11eb18520b6 100644 --- a/extern/lzo/CMakeLists.txt +++ b/extern/lzo/CMakeLists.txt @@ -25,7 +25,7 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - include + ) set(INC_SYS diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt index ab88c9ecabd..73ad0093c73 100644 --- a/intern/audaspace/CMakeLists.txt +++ b/intern/audaspace/CMakeLists.txt @@ -159,8 +159,12 @@ set(SRC if(WITH_CODEC_FFMPEG) add_definitions(-DWITH_FFMPEG) - list(APPEND INC ffmpeg) - list(APPEND INC_SYS ${FFMPEG_INCLUDE_DIRS}) + list(APPEND INC + ffmpeg + ) + list(APPEND INC_SYS + ${FFMPEG_INCLUDE_DIRS} + ) list(APPEND SRC ffmpeg/AUD_FFMPEGFactory.cpp ffmpeg/AUD_FFMPEGReader.cpp @@ -172,8 +176,12 @@ endif() if(WITH_SDL) add_definitions(-DWITH_SDL) - list(APPEND INC SDL) - list(APPEND INC_SYS ${SDL_INCLUDE_DIR}) + list(APPEND INC + SDL + ) + list(APPEND INC_SYS + ${SDL_INCLUDE_DIR} + ) list(APPEND SRC SDL/AUD_SDLDevice.cpp @@ -183,8 +191,12 @@ endif() if(WITH_OPENAL) add_definitions(-DWITH_OPENAL) - list(APPEND INC OpenAL) - list(APPEND INC_SYS ${OPENAL_INCLUDE_DIR}) + list(APPEND INC + OpenAL + ) + list(APPEND INC_SYS + ${OPENAL_INCLUDE_DIR} + ) list(APPEND SRC OpenAL/AUD_OpenALDevice.cpp @@ -194,8 +206,12 @@ endif() if(WITH_JACK) add_definitions(-DWITH_JACK) - list(APPEND INC jack) - list(APPEND INC_SYS ${JACK_INCLUDE_DIRS}) + list(APPEND INC + jack + ) + list(APPEND INC_SYS + ${JACK_INCLUDE_DIRS} + ) list(APPEND SRC jack/AUD_JackDevice.cpp @@ -205,8 +221,12 @@ endif() if(WITH_CODEC_SNDFILE) add_definitions(-DWITH_SNDFILE) - list(APPEND INC sndfile) - list(APPEND INC_SYS ${SNDFILE_INCLUDE_DIRS}) + list(APPEND INC + sndfile + ) + list(APPEND INC_SYS + ${SNDFILE_INCLUDE_DIRS} + ) list(APPEND SRC sndfile/AUD_SndFileFactory.cpp sndfile/AUD_SndFileReader.cpp @@ -218,7 +238,9 @@ endif() if(WITH_SAMPLERATE) add_definitions(-DWITH_SAMPLERATE) - list(APPEND INC_SYS ${SAMPLERATE_INCLUDE_DIRS}) + list(APPEND INC_SYS + ${SAMPLERATE_INCLUDE_DIRS} + ) list(APPEND SRC SRC/AUD_SRCResampleFactory.cpp SRC/AUD_SRCResampleReader.cpp @@ -230,8 +252,12 @@ endif() if(WITH_FFTW3 AND FALSE) add_definitions(-DWITH_FFTW3) - list(APPEND INC fftw) - list(APPEND INC_SYS ${FFTW3_INCLUDE_DIRS}) + list(APPEND INC + fftw + ) + list(APPEND INC_SYS + ${FFTW3_INCLUDE_DIRS} + ) list(APPEND SRC fftw/AUD_BandPassFactory.cpp fftw/AUD_BandPassReader.cpp @@ -242,8 +268,12 @@ if(WITH_FFTW3 AND FALSE) 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} + ) list(APPEND SRC Python/AUD_PyAPI.cpp diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 41c70b7cd16..f49d075d9f9 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -146,7 +146,9 @@ if(WITH_HEADLESS OR WITH_GHOST_SDL) ) endif() - list(APPEND INC_SYS ${SDL_INCLUDE_DIR}) + list(APPEND INC_SYS + ${SDL_INCLUDE_DIR} + ) elseif(APPLE) if(WITH_COCOA) @@ -185,7 +187,9 @@ elseif(UNIX) add_definitions(-DWITH_X11_XINPUT) endif() - list(APPEND INC_SYS ${X11_X11_INCLUDE_PATH}) + list(APPEND INC_SYS + ${X11_X11_INCLUDE_PATH} + ) list(APPEND SRC intern/GHOST_DisplayManagerX11.cpp @@ -205,7 +209,9 @@ elseif(UNIX) if(X11_XF86keysym_INCLUDE_PATH) add_definitions(-DWITH_XF86KEYSYM) - list(APPEND INC_SYS ${X11_XF86keysym_INCLUDE_PATH}) + list(APPEND INC_SYS + ${X11_XF86keysym_INCLUDE_PATH} + ) endif() elseif(WIN32) @@ -213,7 +219,9 @@ elseif(WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") endif() - list(APPEND INC_SYS ${WINTAB_INC}) + list(APPEND INC_SYS + ${WINTAB_INC} + ) list(APPEND SRC intern/GHOST_DisplayManagerWin32.cpp diff --git a/intern/smoke/CMakeLists.txt b/intern/smoke/CMakeLists.txt index 174ee8bc3ed..094d398a83c 100644 --- a/intern/smoke/CMakeLists.txt +++ b/intern/smoke/CMakeLists.txt @@ -89,7 +89,9 @@ endif() if(WITH_FFTW3) add_definitions(-DFFTW3=1) - list(APPEND INC ${FFTW3_INCLUDE_DIRS}) + list(APPEND INC + ${FFTW3_INCLUDE_DIRS} + ) endif() blender_add_lib(bf_intern_smoke "${SRC}" "${INC}" "${INC_SYS}") 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) diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index b6721650bad..6e5d8b9485d 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -128,7 +128,9 @@ set(SRC ) if(WITH_SDL) - list(APPEND INC_SYS ${SDL_INCLUDE_DIR}) + list(APPEND INC_SYS + ${SDL_INCLUDE_DIR} + ) else() add_definitions(-DDISABLE_SDL) endif() diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 7b3906e0846..596a04fa862 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -210,7 +210,9 @@ set(SRC add_definitions(-DGLEW_STATIC) if(WITH_SDL) - list(APPEND INC_SYS ${SDL_INCLUDE_DIR}) + list(APPEND INC_SYS + ${SDL_INCLUDE_DIR} + ) else() add_definitions(-DDISABLE_SDL) endif() -- 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(+) 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. --- extern/binreloc/CMakeLists.txt | 2 +- extern/glew/CMakeLists.txt | 2 +- intern/audaspace/CMakeLists.txt | 2 +- intern/boolop/CMakeLists.txt | 6 +-- intern/bsp/CMakeLists.txt | 4 +- intern/ghost/CMakeLists.txt | 5 +- 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 +- .../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 +- .../blender/editors/space_outliner/CMakeLists.txt | 2 +- source/blender/editors/space_script/CMakeLists.txt | 2 +- .../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 +- .../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 +++---- .../bad_level_call_stubs/CMakeLists.txt | 10 ++-- source/gameengine/BlenderRoutines/CMakeLists.txt | 48 +++++++++--------- source/gameengine/Converter/CMakeLists.txt | 55 ++++++++++---------- source/gameengine/Expressions/CMakeLists.txt | 6 +-- source/gameengine/GameLogic/CMakeLists.txt | 20 ++++---- source/gameengine/GamePlayer/common/CMakeLists.txt | 46 ++++++++--------- source/gameengine/GamePlayer/ghost/CMakeLists.txt | 48 +++++++++--------- source/gameengine/Ketsji/CMakeLists.txt | 59 +++++++++++----------- source/gameengine/Ketsji/KXNetwork/CMakeLists.txt | 12 ++--- source/gameengine/Network/CMakeLists.txt | 2 +- .../Network/LoopBackNetwork/CMakeLists.txt | 4 +- source/gameengine/Physics/Bullet/CMakeLists.txt | 20 ++++---- source/gameengine/Rasterizer/CMakeLists.txt | 12 ++--- .../Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt | 20 ++++---- source/gameengine/VideoTexture/CMakeLists.txt | 36 ++++++------- 73 files changed, 292 insertions(+), 294 deletions(-) diff --git a/extern/binreloc/CMakeLists.txt b/extern/binreloc/CMakeLists.txt index a4f85a2fdfd..753e28091d3 100644 --- a/extern/binreloc/CMakeLists.txt +++ b/extern/binreloc/CMakeLists.txt @@ -19,7 +19,7 @@ # set(INC - ./include + include ) set(INC_SYS diff --git a/extern/glew/CMakeLists.txt b/extern/glew/CMakeLists.txt index a7ebe36f950..87f8bb6e940 100644 --- a/extern/glew/CMakeLists.txt +++ b/extern/glew/CMakeLists.txt @@ -25,7 +25,7 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ./include + include ) set(INC_SYS diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt index 73ad0093c73..7eef13b103b 100644 --- a/intern/audaspace/CMakeLists.txt +++ b/intern/audaspace/CMakeLists.txt @@ -22,9 +22,9 @@ set(INC . - intern FX SRC + intern ../ffmpeg ) diff --git a/intern/boolop/CMakeLists.txt b/intern/boolop/CMakeLists.txt index 7a95d556172..742c0f1d42c 100644 --- a/intern/boolop/CMakeLists.txt +++ b/intern/boolop/CMakeLists.txt @@ -26,11 +26,11 @@ set(INC . - ./intern - ./extern - ../memutil + extern + intern ../container ../guardedalloc + ../memutil ../moto/include ../../source/blender/blenlib ../../source/blender/makesdna diff --git a/intern/bsp/CMakeLists.txt b/intern/bsp/CMakeLists.txt index 792f6aa1327..a844db3257e 100644 --- a/intern/bsp/CMakeLists.txt +++ b/intern/bsp/CMakeLists.txt @@ -25,11 +25,11 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ./intern + intern ../container ../guardedalloc - ../moto/include ../memutil + ../moto/include ) set(INC_SYS diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index f49d075d9f9..ccd763ef42c 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -37,9 +37,8 @@ set(INC_SYS set(SRC intern/GHOST_Buttons.cpp - intern/GHOST_CallbackEventConsumer.cpp intern/GHOST_C-api.cpp - intern/GHOST_Path-api.cpp + intern/GHOST_CallbackEventConsumer.cpp intern/GHOST_DisplayManager.cpp intern/GHOST_EventManager.cpp intern/GHOST_ISystem.cpp @@ -47,6 +46,7 @@ set(SRC intern/GHOST_ModifierKeys.cpp intern/GHOST_NDOFManager.cpp intern/GHOST_Path-api.cpp + intern/GHOST_Path-api.cpp intern/GHOST_Rect.cpp intern/GHOST_System.cpp intern/GHOST_TimerManager.cpp @@ -63,6 +63,7 @@ set(SRC GHOST_Path-api.h GHOST_Rect.h GHOST_Types.h + intern/GHOST_Buttons.h intern/GHOST_CallbackEventConsumer.h intern/GHOST_Debug.h 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 diff --git a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt index 80f3642748a..f852d061cf7 100644 --- a/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt +++ b/source/blenderplayer/bad_level_call_stubs/CMakeLists.txt @@ -29,12 +29,12 @@ remove_strict_flags() set(INC . - .. + .. + ../../blender/blenkernel + ../../blender/blenloader + ../../blender/makesdna + ../../blender/makesrna ../../../intern/guardedalloc - ../../../source/blender/makesdna - ../../../source/blender/blenloader - ../../../source/blender/makesrna - ../../../source/blender/blenkernel ) set(INC_SYS diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt index 28f567cc3cd..5a7304765e4 100644 --- a/source/gameengine/BlenderRoutines/CMakeLists.txt +++ b/source/gameengine/BlenderRoutines/CMakeLists.txt @@ -1,33 +1,33 @@ set(INC . - ../../../intern/string + ../Converter + ../Expressions + ../GameLogic + ../Ketsji + ../Network + ../Network/LoopBackNetwork + ../Physics/Bullet + ../Physics/common + ../Rasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../SceneGraph + ../../blender + ../../blender/blenfont + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/blenloader + ../../blender/editors/include + ../../blender/gpu + ../../blender/imbuf + ../../blender/makesdna + ../../blender/makesrna + ../../blender/windowmanager + ../../../extern/bullet2/src ../../../intern/container ../../../intern/guardedalloc - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/Converter - ../../../source/blender/imbuf ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender/blenfont - ../../../source/blender/editors/include - ../../../source/blender/windowmanager - ../../../source/blender - ../../../source/blender/makesdna - ../../../source/blender/makesrna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Physics/Bullet - ../../../source/gameengine/Network/LoopBackNetwork - ../../../source/blender/blenloader - ../../../source/blender/gpu - ../../../extern/bullet2/src + ../../../intern/string ${GLEW_INCLUDE_PATH} ) diff --git a/source/gameengine/Converter/CMakeLists.txt b/source/gameengine/Converter/CMakeLists.txt index c905b8634a0..45a7701d404 100644 --- a/source/gameengine/Converter/CMakeLists.txt +++ b/source/gameengine/Converter/CMakeLists.txt @@ -26,36 +26,35 @@ set(INC . - ../../../intern/string - ../../../intern/guardedalloc + ../BlenderRoutines + ../Expressions + ../GameLogic + ../Ketsji + ../Ketsji/KXNetwork + ../Network + ../Network/LoopBackNetwork + ../Physics/Bullet + ../Physics/Dummy + ../Physics/common + ../Rasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../SceneGraph + ../../blender + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/blenloader + ../../blender/gpu + ../../blender/ikplugin + ../../blender/imbuf + ../../blender/makesdna + ../../blender/makesrna + ../../blender/windowmanager + ../../../extern/bullet2/src ../../../intern/container - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/Converter - ../../../source/gameengine/BlenderRoutines - ../../../source/blender/imbuf + ../../../intern/guardedalloc ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/gameengine/Ketsji/KXNetwork - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender/windowmanager - ../../../source/blender - ../../../source/blender/makesdna - ../../../source/blender/makesrna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Physics/Bullet - ../../../source/gameengine/Physics/Dummy - ../../../source/gameengine/Network/LoopBackNetwork - ../../../source/blender/blenloader - ../../../source/blender/gpu - ../../../source/blender/ikplugin - ../../../extern/bullet2/src + ../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Expressions/CMakeLists.txt b/source/gameengine/Expressions/CMakeLists.txt index 83d44e1b318..ad987091790 100644 --- a/source/gameengine/Expressions/CMakeLists.txt +++ b/source/gameengine/Expressions/CMakeLists.txt @@ -26,11 +26,11 @@ set(INC . - ../../../intern/string + ../SceneGraph + ../../blender/blenloader ../../../intern/guardedalloc ../../../intern/moto/include - ../../../source/gameengine/SceneGraph - ../../../source/blender/blenloader + ../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/GameLogic/CMakeLists.txt b/source/gameengine/GameLogic/CMakeLists.txt index 6e5d8b9485d..bd417165337 100644 --- a/source/gameengine/GameLogic/CMakeLists.txt +++ b/source/gameengine/GameLogic/CMakeLists.txt @@ -25,13 +25,13 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - . - ../../../intern/string + . + ../Expressions + ../Rasterizer + ../SceneGraph ../../../intern/container - ../../../source/gameengine/Expressions - ../../../source/gameengine/SceneGraph ../../../intern/moto/include - ../../../source/gameengine/Rasterizer + ../../../intern/string ) set(INC_SYS @@ -39,8 +39,6 @@ set(INC_SYS ) set(SRC - Joystick/SCA_Joystick.cpp - Joystick/SCA_JoystickEvents.cpp SCA_2DFilterActuator.cpp SCA_ANDController.cpp SCA_ActuatorEventManager.cpp @@ -81,10 +79,9 @@ set(SRC SCA_TimeEventManager.cpp SCA_XNORController.cpp SCA_XORController.cpp + Joystick/SCA_Joystick.cpp + Joystick/SCA_JoystickEvents.cpp - Joystick/SCA_Joystick.h - Joystick/SCA_JoystickDefines.h - Joystick/SCA_JoystickPrivate.h SCA_2DFilterActuator.h SCA_ANDController.h SCA_ActuatorEventManager.h @@ -125,6 +122,9 @@ set(SRC SCA_TimeEventManager.h SCA_XNORController.h SCA_XORController.h + Joystick/SCA_Joystick.h + Joystick/SCA_JoystickDefines.h + Joystick/SCA_JoystickPrivate.h ) if(WITH_SDL) diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt index d16ec6a2f22..8c5897fa48e 100644 --- a/source/gameengine/GamePlayer/common/CMakeLists.txt +++ b/source/gameengine/GamePlayer/common/CMakeLists.txt @@ -26,31 +26,31 @@ set(INC . - ../../../../intern/string + ../ghost + ../../BlenderRoutines + ../../Converter + ../../Expressions + ../../GameLogic + ../../Ketsji + ../../Network + ../../Network/LoopBackNetwork + ../../Physics/common + ../../Rasterizer + ../../Rasterizer/RAS_OpenGLRasterizer + ../../SceneGraph + ../../../blender + ../../../blender/blenfont + ../../../blender/blenkernel + ../../../blender/blenlib + ../../../blender/blenloader + ../../../blender/gpu + ../../../blender/imbuf + ../../../blender/makesdna + ../../../../intern/container ../../../../intern/ghost ../../../../intern/guardedalloc - ../../../../intern/container ../../../../intern/moto/include - ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../../source/gameengine/Converter - ../../../../source/gameengine/BlenderRoutines - ../../../../source/blender/imbuf - ../../../../source/gameengine/Ketsji - ../../../../source/blender/blenlib - ../../../../source/blender/blenfont - ../../../../source/blender/blenkernel - ../../../../source/blender - ../../../../source/blender/makesdna - ../../../../source/gameengine/Rasterizer - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/Network - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/Physics/common - ../../../../source/gameengine/Network/LoopBackNetwork - ../../../../source/gameengine/GamePlayer/ghost - ../../../../source/blender/blenloader - ../../../../source/blender/gpu + ../../../../intern/string ) set(INC_SYS @@ -61,7 +61,6 @@ set(INC_SYS ) set(SRC - bmfont.cpp GPC_Canvas.cpp GPC_Engine.cpp GPC_KeyboardDevice.cpp @@ -71,6 +70,7 @@ set(SRC GPC_RawLogoArrays.cpp GPC_RenderTools.cpp GPC_System.cpp + bmfont.cpp GPC_Canvas.h GPC_Engine.h diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt index 5ac121099c3..944ec9abd67 100644 --- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt +++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt @@ -26,32 +26,32 @@ set(INC . - ../../../../intern/string + ../common + ../../BlenderRoutines + ../../Converter + ../../Expressions + ../../GameLogic + ../../Ketsji + ../../Network + ../../Network/LoopBackNetwork + ../../Physics/common + ../../Rasterizer + ../../Rasterizer/RAS_OpenGLRasterizer + ../../SceneGraph + ../../../blender + ../../../blender/blenfont + ../../../blender/blenkernel + ../../../blender/blenlib + ../../../blender/blenloader + ../../../blender/gpu + ../../../blender/imbuf + ../../../blender/makesdna + ../../../blender/makesrna + ../../../../intern/container ../../../../intern/ghost ../../../../intern/guardedalloc - ../../../../intern/container ../../../../intern/moto/include - ../../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../../source/gameengine/BlenderRoutines - ../../../../source/gameengine/Converter - ../../../../source/blender/imbuf - ../../../../source/gameengine/Ketsji - ../../../../source/blender/blenfont - ../../../../source/blender/blenlib - ../../../../source/blender/blenkernel - ../../../../source/blender - ../../../../source/blender/makesdna - ../../../../source/blender/makesrna - ../../../../source/gameengine/Rasterizer - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/Network - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/Physics/common - ../../../../source/gameengine/Network/LoopBackNetwork - ../../../../source/gameengine/GamePlayer/common - ../../../../source/blender/blenloader - ../../../../source/blender/gpu + ../../../../intern/string ) set(INC_SYS @@ -62,9 +62,9 @@ set(INC_SYS set(SRC GPG_Application.cpp GPG_Canvas.cpp - GPG_ghost.cpp GPG_KeyboardDevice.cpp GPG_System.cpp + GPG_ghost.cpp GPG_Application.h GPG_Canvas.h diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt index 596a04fa862..8222bf4b65f 100644 --- a/source/gameengine/Ketsji/CMakeLists.txt +++ b/source/gameengine/Ketsji/CMakeLists.txt @@ -26,33 +26,32 @@ set(INC . - ../../../intern/string - ../../../intern/guardedalloc + KXNetwork + ../BlenderRoutines + ../Converter + ../Expressions + ../GameLogic + ../Network + ../Network/LoopBackNetwork + ../Physics/common + ../Rasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../SceneGraph + ../../blender + ../../blender/blenfont + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/blenloader + ../../blender/gpu + ../../blender/imbuf + ../../blender/makesdna + ../../blender/python + ../../blender/python/generic + ../../blender/python/mathutils ../../../intern/container - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/Converter - ../../../source/gameengine/BlenderRoutines - ../../../source/blender/imbuf + ../../../intern/guardedalloc ../../../intern/moto/include - ../../../source/gameengine/Ketsji - ../../../source/blender/blenlib - ../../../source/blender/blenfont - ../../../source/blender/blenkernel - ../../../source/blender/python - ../../../source/blender/python/generic - ../../../source/blender/python/mathutils - ../../../source/blender - ../../../source/blender/makesdna - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/GameLogic - ../../../source/gameengine/Expressions - ../../../source/gameengine/Ketsji/KXNetwork - ../../../source/gameengine/Network - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Physics/common - ../../../source/gameengine/Network/LoopBackNetwork - ../../../source/blender/blenloader - ../../../source/blender/gpu + ../../../intern/string ) set(INC_SYS @@ -129,6 +128,10 @@ set(SRC KX_WorldInfo.cpp KX_WorldIpoController.cpp + BL_BlenderShader.h + BL_Material.h + BL_Shader.h + BL_Texture.h KX_ArmatureSensor.h KX_BlenderMaterial.h KX_BulletPhysicsController.h @@ -201,10 +204,6 @@ set(SRC KX_VisibilityActuator.h KX_WorldInfo.h KX_WorldIpoController.h - BL_BlenderShader.h - BL_Material.h - BL_Shader.h - BL_Texture.h ) add_definitions(-DGLEW_STATIC) @@ -231,7 +230,7 @@ endif() if(WITH_BULLET) list(APPEND INC ../../../extern/bullet2/src - ../../../source/gameengine/Physics/Bullet + ../Physics/Bullet ) add_definitions(-DUSE_BULLET) endif() diff --git a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt index b8149566801..1ebf1153150 100644 --- a/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt +++ b/source/gameengine/Ketsji/KXNetwork/CMakeLists.txt @@ -26,14 +26,14 @@ set(INC . - ../../../../intern/string + .. + ../../Expressions + ../../GameLogic + ../../Network + ../../SceneGraph ../../../../intern/container ../../../../intern/moto/include - ../../../../source/gameengine/Ketsji - ../../../../source/gameengine/GameLogic - ../../../../source/gameengine/Expressions - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/Network + ../../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Network/CMakeLists.txt b/source/gameengine/Network/CMakeLists.txt index e1f3bfaac77..4d6d035c63d 100644 --- a/source/gameengine/Network/CMakeLists.txt +++ b/source/gameengine/Network/CMakeLists.txt @@ -26,9 +26,9 @@ set(INC . - ../../../intern/string ../../../intern/container ../../../intern/moto/include + ../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt index 9c3936987f2..c816a30f1a8 100644 --- a/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt +++ b/source/gameengine/Network/LoopBackNetwork/CMakeLists.txt @@ -26,9 +26,9 @@ set(INC . - ../../../../intern/string + .. ../../../../intern/container - ../../../../source/gameengine/Network + ../../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt index aadd11cc036..971c8f979f3 100644 --- a/source/gameengine/Physics/Bullet/CMakeLists.txt +++ b/source/gameengine/Physics/Bullet/CMakeLists.txt @@ -30,19 +30,19 @@ remove_strict_flags() set(INC . ../common - ../../../../extern/bullet2/src - ../../../../intern/moto/include - ../../../../intern/guardedalloc - ../../../../intern/container - ../../../../intern/string - ../../Rasterizer - ../../Ketsji ../../Expressions ../../GameLogic + ../../Ketsji + ../../Rasterizer ../../SceneGraph - ../../../../source/blender/makesdna - ../../../../source/blender/blenlib - ../../../../source/blender/blenkernel + ../../../blender/blenkernel + ../../../blender/blenlib + ../../../blender/makesdna + ../../../../extern/bullet2/src + ../../../../intern/container + ../../../../intern/guardedalloc + ../../../../intern/moto/include + ../../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt index b705d3151b2..23d746f88bc 100644 --- a/source/gameengine/Rasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/CMakeLists.txt @@ -26,14 +26,14 @@ set(INC . - ../../../source/blender/makesdna - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Ketsji - ../../../intern/string + ../Expressions + ../Ketsji + ../SceneGraph + ../../blender/makesdna ../../../intern/container - ../../../intern/moto/include ../../../intern/guardedalloc - ../Expressions + ../../../intern/moto/include + ../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt index a005bb1108d..b0ef6fab251 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt @@ -25,18 +25,18 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../../../../intern/string + .. + ../../BlenderRoutines + ../../Ketsji + ../../SceneGraph + ../../../blender/blenkernel + ../../../blender/blenlib + ../../../blender/blenloader + ../../../blender/gpu + ../../../blender/makesdna ../../../../intern/container ../../../../intern/moto/include - ../../../../source/gameengine/Rasterizer - ../../../../source/gameengine/Ketsji - ../../../../source/gameengine/SceneGraph - ../../../../source/gameengine/BlenderRoutines - ../../../../source/blender/gpu - ../../../../source/blender/makesdna - ../../../../source/blender/blenkernel - ../../../../source/blender/blenlib - ../../../../source/blender/blenloader + ../../../../intern/string ) set(INC_SYS diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt index c412363dc3b..04683a5f99b 100644 --- a/source/gameengine/VideoTexture/CMakeLists.txt +++ b/source/gameengine/VideoTexture/CMakeLists.txt @@ -26,26 +26,26 @@ set(INC . - ../../../source/gameengine/Ketsji - ../../../source/gameengine/Expressions - ../../../source/gameengine/GameLogic - ../../../source/gameengine/SceneGraph - ../../../source/gameengine/Rasterizer - ../../../source/gameengine/Rasterizer/RAS_OpenGLRasterizer - ../../../source/gameengine/BlenderRoutines - ../../../source/blender/blenlib - ../../../source/blender/blenkernel - ../../../source/blender/makesdna - ../../../source/blender/editors/include - ../../../source/blender/imbuf - ../../../source/blender/python - ../../../source/blender/python/generic - ../../../source/blender/gpu + ../BlenderRoutines + ../Expressions + ../GameLogic + ../Ketsji + ../Rasterizer + ../Rasterizer/RAS_OpenGLRasterizer + ../SceneGraph + ../../blender/blenkernel + ../../blender/blenlib + ../../blender/editors/include + ../../blender/gpu + ../../blender/imbuf + ../../blender/makesdna + ../../blender/python + ../../blender/python/generic ../../../intern/container - ../../../intern/string - ../../../intern/moto/include - ../../../intern/guardedalloc ../../../intern/ffmpeg + ../../../intern/guardedalloc + ../../../intern/moto/include + ../../../intern/string ) set(INC_SYS -- cgit v1.2.3 From 8c11a26285c31eac859cb108ce354a421714d90d Mon Sep 17 00:00:00 2001 From: Jiri Hnidek Date: Sun, 17 Jul 2011 10:28:31 +0000 Subject: Fixed compile error on Fedora 15, when FFMPEG was enabled. --- intern/ffmpeg/ffmpeg_compat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index d8edffbfe0b..fae8590568d 100644 --- a/intern/ffmpeg/ffmpeg_compat.h +++ b/intern/ffmpeg/ffmpeg_compat.h @@ -40,7 +40,7 @@ #define FFMPEG_HAVE_AVIO 1 #endif -#if (LIBAVCODEC_VERSION_MAJOR > 53) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR > 1)) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR == 1) && (LIBAVCODEC_VERSION_MICRO >= 1)) || ((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR >= 122)) +#if (LIBAVCODEC_VERSION_MAJOR > 53) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR > 1)) || ((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR == 1) && (LIBAVCODEC_VERSION_MICRO >= 1)) || ((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR >= 121)) #define FFMPEG_HAVE_DEFAULT_VAL_UNION 1 #endif -- 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(-) 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(+) 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 c7532c5b812d411a8457e0693dc4038b3da9b901 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 17 Jul 2011 12:42:03 +0000 Subject: update to cmake checker script to also check if our include paths are ok --- build_files/cmake/cmake_consistency_check.py | 100 +++++++++++++++++++-------- 1 file changed, 72 insertions(+), 28 deletions(-) diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py index c13da8775b3..4b35e34a5cd 100755 --- a/build_files/cmake/cmake_consistency_check.py +++ b/build_files/cmake/cmake_consistency_check.py @@ -35,6 +35,21 @@ global_c = set() global_refs = {} +def replace_line(f, i, text, keep_indent=True): + file_handle = open(f, 'r') + data = file_handle.readlines() + file_handle.close() + + l = data[i] + ws = l[:len(l) - len(l.lstrip())] + + data[i] = "%s%s\n" % (ws, text) + + file_handle = open(f, 'w') + file_handle.writelines(data) + file_handle.close() + + def source_list(path, filename_check=None): for dirpath, dirnames, filenames in os.walk(path): @@ -77,7 +92,20 @@ def cmake_get_src(f): found = False i = 0 # print(f) + + def is_definition(l, f, i, name): + if ('set(%s' % name) in l or ('set(' in l and l.endswith(name)): + if len(l.split()) > 1: + raise Exception("strict formatting not kept 'set(%s*' %s:%d" % (name, f, i)) + return True + + if ("list(APPEND %s" % name) in l or ('list(APPEND ' in l and l.endswith(name)): + if l.endswith(")"): + raise Exception("strict formatting not kept 'list(APPEND %s...)' on 1 line %s:%d" % (name, f, i)) + return True + while it is not None: + context_name = "" while it is not None: i += 1 try: @@ -87,16 +115,13 @@ def cmake_get_src(f): break l = l.strip() if not l.startswith("#"): - if 'set(SRC' in l or ('set(' in l and l.endswith("SRC")): - if len(l.split()) > 1: - raise Exception("strict formatting not kept 'set(SRC*' %s:%d" % (f, i)) - found = True + found = is_definition(l, f, i, "SRC") + if found: + context_name = "SRC" break - - if "list(APPEND SRC" in l or ('list(APPEND ' in l and l.endswith("SRC")): - if l.endswith(")"): - raise Exception("strict formatting not kept 'list(APPEND SRC...)' on 1 line %s:%d" % (f, i)) - found = True + found = is_definition(l, f, i, "INC") + if found: + context_name = "INC" break if found: @@ -125,30 +150,45 @@ def cmake_get_src(f): if not l: pass elif l.startswith("$"): - # assume if it ends with SRC we know about it - if not l.split("}")[0].endswith("SRC"): - print("Can't use var '%s' %s:%d" % (l, f, i)) + if context_name == "SRC": + # assume if it ends with context_name we know about it + if not l.split("}")[0].endswith(context_name): + print("Can't use var '%s' %s:%d" % (l, f, i)) elif len(l.split()) > 1: raise Exception("Multi-line define '%s' %s:%d" % (l, f, i)) else: new_file = normpath(join(cmake_base, l)) - if is_c_header(new_file): - sources_h.append(new_file) - global_refs.setdefault(new_file, []).append((f, i)) - elif is_c(new_file): - sources_c.append(new_file) - global_refs.setdefault(new_file, []).append((f, i)) - elif l in ("PARENT_SCOPE", ): - # cmake var, ignore - pass - elif new_file.endswith(".list"): - pass - elif new_file.endswith(".def"): - pass - else: - raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file)) - + if context_name == "SRC": + if is_c_header(new_file): + sources_h.append(new_file) + global_refs.setdefault(new_file, []).append((f, i)) + elif is_c(new_file): + sources_c.append(new_file) + global_refs.setdefault(new_file, []).append((f, i)) + elif l in ("PARENT_SCOPE", ): + # cmake var, ignore + pass + elif new_file.endswith(".list"): + pass + elif new_file.endswith(".def"): + pass + else: + raise Exception("unknown file type - not c or h %s -> %s" % (f, new_file)) + + elif context_name == "INC": + if os.path.isdir(new_file): + new_path_rel = os.path.relpath(new_file, cmake_base) + + if new_path_rel != l: + print("overly relative path:\n %s:%d\n %s\n %s" % (f, i, l, new_path_rel)) + + ## Save time. just replace the line + # replace_line(f, i - 1, new_path_rel) + + else: + raise Exception("non existant include %s:%d -> %s" % (f, i, new_file)) + # print(new_file) global_h.update(set(sources_h)) @@ -166,6 +206,10 @@ def cmake_get_src(f): if ff not in sources_c: print(" missing: " + ff) ''' + + # reset + sources_h[:] = [] + sources_c[:] = [] filen.close() -- cgit v1.2.3 From 7e4ccf9349ad7444e43421a012c8b21b23c57ab6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 17 Jul 2011 13:29:50 +0000 Subject: template for patch exporting objects in a scene. --- release/scripts/templates/batch_export.py | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 release/scripts/templates/batch_export.py diff --git a/release/scripts/templates/batch_export.py b/release/scripts/templates/batch_export.py new file mode 100644 index 00000000000..aa0e601725b --- /dev/null +++ b/release/scripts/templates/batch_export.py @@ -0,0 +1,33 @@ +# exports each selected object into its own file + +import bpy +import os + +# export to blend file location +basedir = os.path.dirname(bpy.data.filepath) + +if not basedir: + raise Exception("Blend file is not saved") + +selection = bpy.context.selected_objects + +bpy.ops.object.select_all(action='DESELECT') + +for obj in selection: + + obj.select = True + + name = bpy.path.clean_name(obj.name) + fn = os.path.join(basedir, name) + + bpy.ops.export_scene.fbx(filepath=fn + ".fbx", use_selection=True) + + ## Can be used for multiple formats + # bpy.ops.export_scene.x3d(filepath=fn + ".x3d", use_selection=True) + + obj.select = False + + print("written:", fn) + +for obj in selection: + obj.select = True -- 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(-) 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(-) 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(-) 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(-) 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(-) 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 13e82ff8e1ab8b3fb03da026325a150cb7cf4ea0 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 18 Jul 2011 05:07:54 +0000 Subject: fix [#27971] Blender OBJ export with Z-Up setting produces an error and fails changes to extensions coming up... --- release/scripts/modules/bpy_extras/io_utils.py | 41 +++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index cfa2233f7b6..9545e20b025 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -22,6 +22,7 @@ __all__ = ( "ExportHelper", "ImportHelper", "axis_conversion", + "axis_conversion_ensure", "create_derived_objects", "free_derived_objects", "unpack_list", @@ -154,12 +155,50 @@ def axis_conversion(from_forward='Y', from_up='Z', to_forward='Y', to_up='Z'): if from_forward == to_forward and from_up == to_up: return Matrix().to_3x3() + if from_forward[-1] == from_up[-1] or to_forward[-1] == to_up[-1]: + raise Exception("invalid axis arguments passed, " + "can't use up/forward on the same axis.") + value = reduce(int.__or__, (_axis_convert_num[a] << (i * 3) for i, a in enumerate((from_forward, from_up, to_forward, to_up)))) for i, axis_lut in enumerate(_axis_convert_lut): if value in axis_lut: return Matrix(_axis_convert_matrix[i]) - assert("internal error") + assert(0) + + +def axis_conversion_ensure(operator, forward_attr, up_attr): + """ + Function to ensure an operator has valid axis conversion settings, intended + to be used from :class:`Operator.check`. + + :arg operator: the operator to access axis attributes from. + :type operator: :class:`Operator` + :arg forward_attr: + :type forward_attr: string + :arg up_attr: the directory the *filepath* will be referenced from (normally the export path). + :type up_attr: string + :return: True if the value was modified. + :rtype: boolean + """ + def validate(axis_forward, axis_up): + if axis_forward[-1] == axis_up[-1]: + axis_up = axis_up[0:-1] + 'XYZ'[('XYZ'.index(axis_up[-1]) + 1) % 3] + + return axis_forward, axis_up + + change = False + + axis = getattr(operator, forward_attr), getattr(operator, up_attr) + axis_new = validate(*axis) + + if axis != axis_new: + setattr(operator, forward_attr, axis_new[0]) + setattr(operator, up_attr, axis_new[1]) + + return True + else: + return False # return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() -- cgit v1.2.3 From 8dd72c476e51ee457fdd98625eff7a1afc88f49e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 18 Jul 2011 05:41:46 +0000 Subject: fix [#28005] Python Add-Ons are constantly reloaded if twice in the path Addons are checked for their timestamps and reloaded when it changes but this failed when, 2 addons had the same name since different times caused 2 reloads on every redraw. Now when duplicate addons are in the path now give a error message in the UI and print path conflict in the console and don't thrash reloading. --- release/scripts/modules/addon_utils.py | 12 +++++++++++- release/scripts/startup/bl_ui/space_userpref.py | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 07f1dc618dc..cf74282d064 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -31,6 +31,8 @@ __all__ = ( import bpy as _bpy +error_duplicates = False + def paths(): # RELEASE SCRIPTS: official scripts distributed in Blender releases paths = _bpy.utils.script_paths("addons") @@ -47,8 +49,11 @@ def paths(): def modules(module_cache): + global error_duplicates import os + error_duplicates = False + path_list = paths() # fake module importing @@ -117,7 +122,12 @@ def modules(module_cache): modules_stale -= {mod_name} mod = module_cache.get(mod_name) if mod: - if mod.__time__ != os.path.getmtime(mod_path): + if mod.__file__ != mod_path: + print("multiple addons with the same name:\n %r\n %r" % + (mod.__file__, mod_path)) + error_duplicates = True + + elif mod.__time__ != os.path.getmtime(mod_path): print("reloading addon:", mod_name, mod.__time__, os.path.getmtime(mod_path), mod_path) del module_cache[mod_name] mod = None diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 6a809aefb9d..139b3205835 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -889,6 +889,16 @@ class USERPREF_PT_addons(bpy.types.Panel): return True return False + @staticmethod + def draw_error(layout, message): + lines = message.split("\n") + box = layout.box() + rowsub = box.row() + rowsub.label(lines[0]) + rowsub.label(icon='ERROR') + for l in lines[1:]: + box.label(l) + def draw(self, context): layout = self.layout @@ -909,6 +919,14 @@ class USERPREF_PT_addons(bpy.types.Panel): col = split.column() + # set in addon_utils.modules(...) + if addon_utils.error_duplicates: + self.draw_error(col, + "Multiple addons using the same name found!\n" + "likely a problem with the script search path.\n" + "(see console for details)", + ) + filter = context.window_manager.addon_filter search = context.window_manager.addon_search.lower() support = context.window_manager.addon_support -- cgit v1.2.3 From ce00a32f05c6429b7bffd80365a94a71755a55f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 18 Jul 2011 06:44:41 +0000 Subject: fix [#27996] Smart UV Unwrap Still Results in Overlaps real fix this time :S, I thought using old code from 2.4x would fix but quaternion needed to be inverted. --- release/scripts/startup/bl_operators/uvcalc_smart_project.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 7ea89cfa479..9c3be84b807 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -747,14 +747,8 @@ def packIslands(islandList): def VectoQuat(vec): - a3 = vec.normalized() - up = Vector((0.0, 0.0, 1.0)) - if abs(a3.dot(up)) == 1.0: - up = Vector((0.0, 1.0, 0.0)) - - a1 = a3.cross(up).normalized() - a2 = a3.cross(a1) - return Matrix((a1, a2, a3)).to_quaternion() + vec = vec.normalized() + return vec.to_track_quat('Z', 'X' if abs(vec.x) > 0.5 else 'Y').inverted() class thickface(object): -- 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(-) 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. --- GNUmakefile | 8 +- source/blender/python/generic/bgl.c | 2 +- source/blender/python/intern/bpy_rna.c | 2 +- source/tests/check_deprecated.py | 144 +++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 source/tests/check_deprecated.py diff --git a/GNUmakefile b/GNUmakefile index b55890f9271..d1a60ce5e37 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -99,14 +99,18 @@ test: # run pep8 check check on scripts we distribute. test_pep8: - python source/tests/pep8.py > test_pep8.log 2>&1 + python3 source/tests/pep8.py > test_pep8.log 2>&1 @echo "written: test_pep8.log" # run some checks on our cmakefiles. test_cmake: - python build_files/cmake/cmake_consistency_check.py > test_cmake_consistency.log 2>&1 + python3 build_files/cmake/cmake_consistency_check.py > test_cmake_consistency.log 2>&1 @echo "written: test_cmake_consistency.log" +# run deprecation tests, see if we have anything to remove. +test_deprecated: + python3 source/tests/check_deprecated.py + clean: make -C $(BUILD_DIR) clean 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 */ diff --git a/source/tests/check_deprecated.py b/source/tests/check_deprecated.py new file mode 100644 index 00000000000..11c7ce646b9 --- /dev/null +++ b/source/tests/check_deprecated.py @@ -0,0 +1,144 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +import os +from os.path import splitext + +DEPRECATE_DAYS = 120 + +SKIP_DIRS = ("extern", + "scons", + os.path.join("source", "tests"), # not this dir + ) + +def is_c_header(filename): + ext = splitext(filename)[1] + return (ext in (".h", ".hpp", ".hxx")) + + +def is_c(filename): + ext = splitext(filename)[1] + return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc")) + + +def is_c_any(filename): + return is_c(filename) or is_c_header(filename) + +def is_py(filename): + ext = splitext(filename)[1] + return (ext == ".py") + +def is_source_any(filename): + return is_c_any(filename) or is_py(filename) + +def source_list(path, filename_check=None): + for dirpath, dirnames, filenames in os.walk(path): + + # skip '.svn' + if dirpath.startswith("."): + continue + + for filename in filenames: + if filename_check is None or filename_check(filename): + yield os.path.join(dirpath, filename) + + +def deprecations(): + """ + Searches out source code for lines like + + /* *DEPRECATED* 2011/7/17 bgl.Buffer.list info text */ + + Or... + + # *DEPRECATED* 2010/12/22 some.py.func more info */ + + """ + import datetime + SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..")))) + + SKIP_DIRS_ABS = [os.path.join(SOURCE_DIR, p) for p in SKIP_DIRS] + + deprecations_ls = [] + + scan_tot = 0 + + print("scanning in %r for '*DEPRECATED* YYYY/MM/DD info'" % SOURCE_DIR) + + for fn in source_list(SOURCE_DIR, is_source_any): + # print(fn) + skip = False + for p in SKIP_DIRS_ABS: + if fn.startswith(p): + skip = True + break + if skip: + continue + + file = open(fn, 'r', encoding="utf8") + for i, l in enumerate(file): + # logic for deprecation warnings + if '*DEPRECATED*' in l: + try: + l = l.strip() + data = l.split('*DEPRECATED*', 1)[-1].strip().strip() + data = [w.strip() for w in data.split('/', 2)] + data[-1], info = data[-1].split(' ', 1) + info = info.split("*/", 1)[0] + if len(data) != 3: + print(" poorly formatting line:\n" + " %r:%d\n" + " %s"% + (fn, i + 1, l) + ) + else: + data = datetime.datetime(*tuple([int(w) for w in data])) + + deprecations_ls.append((data, (fn, i + 1), info)) + except: + print("Error file - %r:%d" % (fn, i + 1)) + import traceback + traceback.print_exc() + + scan_tot += 1 + + print(" scanned %d files" % scan_tot) + + return deprecations_ls + +def main(): + import datetime + now = datetime.datetime.now()\ + + deps = deprecations() + + print("\nAll deprecations...") + for data, fileinfo, info in deps: + days_old = (now - data).days + if days_old > DEPRECATE_DAYS: + info = "*** REMOVE! *** " + info + print(" %r, days-old(%.2d), %s:%d - %s" % (data, days_old, fileinfo[0], fileinfo[1], info)) + if deps: + print("\ndone!") + else: + print("\nnone found!") + +if __name__ == '__main__': + main() -- 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(-) 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(-) 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 1f5d60ba01526cb1e5a22e10030a4d1ec8ff2727 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 18 Jul 2011 22:28:42 +0000 Subject: patch: [#27783] "Problem with clock" at 18:39:00 by Daniel Dionne (mrzeon) the overflow of the clock was causing crash in the game engine in Linux. (on June 11 2011, 18:39:00 GMT) running to the "where is waldo (wally)" bug award of 2011. --- intern/ghost/intern/GHOST_SystemX11.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index 3ebd24c008b..dd296fa979c 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -150,8 +150,9 @@ GHOST_SystemX11( if (gettimeofday(&tv,NULL) == -1) { GHOST_ASSERT(false,"Could not instantiate timer!"); } - - m_start_time = GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000); + + // Taking care not to overflow the tv.tv_sec*1000 + m_start_time = GHOST_TUns64(tv.tv_sec)*1000 + tv.tv_usec/1000; /* use detectable autorepeate, mac and windows also do this */ @@ -199,7 +200,8 @@ getMilliSeconds( GHOST_ASSERT(false,"Could not compute time!"); } - return GHOST_TUns64(tv.tv_sec*1000 + tv.tv_usec/1000) - m_start_time; + // Taking care not to overflow the tv.tv_sec*1000 + return GHOST_TUns64(tv.tv_sec)*1000 + tv.tv_usec/1000 - m_start_time; } GHOST_TUns8 -- 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(-) 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 f2e055f4a480e5f8cc143b6252cd6a5f6cea05c4 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 19 Jul 2011 01:41:45 +0000 Subject: bugfix: [#27348] blenderplayer showing a different viewport size in 2.57b I believe this bug was there since we (me) moved the game settings to scene->gm Since I was here I added support for x/y non square aspect pixels (i.e. anamorphic) we were already using it for videotexture so I don't know why we were not here. Tested in OSX, but it should be working in all OSs. --- source/gameengine/Converter/BL_BlenderDataConversion.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index af114457663..7b9c5d4b4d6 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1976,8 +1976,8 @@ void BL_ConvertBlenderObjects(struct Main* maggie, frame_type = RAS_FrameSettings::e_frame_scale; } - aspect_width = blenderscene->gm.xsch; - aspect_height = blenderscene->gm.ysch; + aspect_width = blenderscene->r.xsch*blenderscene->r.xasp; + aspect_height = blenderscene->r.ysch*blenderscene->r.yasp; } RAS_FrameSettings frame_settings( -- 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(-) 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 f4b6d00926cb3ff847ac843a692ef858bccf769d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 19 Jul 2011 05:05:54 +0000 Subject: fix for bpy.path.abspath(), if a path was passed it would get the last directory cut off, broke copying images on export. --- release/scripts/modules/bpy/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index 5e95428f641..74d043f8a54 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -35,7 +35,7 @@ def abspath(path, start=None): :type start: string """ if path.startswith("//"): - return _os.path.join(_os.path.dirname(_bpy.data.filepath if start is None else start), path[2:]) + return _os.path.join(_os.path.dirname(_bpy.data.filepath) if start is None else start, path[2:]) return path -- 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 --- release/scripts/startup/bl_ui/properties_material.py | 5 ++++- source/blender/nodes/intern/SHD_util.c | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_material.py b/release/scripts/startup/bl_ui/properties_material.py index 45c15bd1ce6..2a52ae23782 100644 --- a/release/scripts/startup/bl_ui/properties_material.py +++ b/release/scripts/startup/bl_ui/properties_material.py @@ -174,6 +174,7 @@ class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): row.prop(mat, "use_transparency") sub = row.column() sub.prop(mat, "offset_z") + sub.active = mat_type and mat.use_transparency and mat.transparency_method == 'Z_TRANSPARENCY' row = layout.row() @@ -199,6 +200,7 @@ class MATERIAL_PT_pipeline(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "shadow_cast_alpha", text="Casting Alpha") col.prop(mat, "use_cast_buffer_shadows") col.prop(mat, "use_cast_approximate") + col.prop(mat, "pass_index") class MATERIAL_PT_diffuse(MaterialButtonsPanel, bpy.types.Panel): @@ -729,7 +731,8 @@ class MATERIAL_PT_options(MaterialButtonsPanel, bpy.types.Panel): col.prop(mat, "use_vertex_color_paint") col.prop(mat, "use_vertex_color_light") col.prop(mat, "use_object_color") - col.prop(mat, "pass_index") + if simple_material(base_mat): + col.prop(mat, "pass_index") class MATERIAL_PT_shadow(MaterialButtonsPanel, bpy.types.Panel): 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 c7d8d289396e969b8a58e87d1dbcac7d81ddba0c Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Tue, 19 Jul 2011 13:27:05 +0000 Subject: Object Align operator now correctly computes a *global* bounding box for all objects. This makes rotated or scaled objects work like they should. Now it's still derived from object's bounding box so it will not be completly acurate on complex objects.. to solve this Id need to cycle over all verts. Don't think that's a good idea to do in py --- .../scripts/startup/bl_operators/object_align.py | 134 ++++++++++++++------- 1 file changed, 88 insertions(+), 46 deletions(-) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 3202a717001..8bf5cc9e8fb 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -21,13 +21,52 @@ import bpy from mathutils import Vector +def GlobalBB(bb_world): + # Initialize the variables with the 8th vertex + left, right, front, back, down, up =\ + bb_world[7][0],\ + bb_world[7][0],\ + bb_world[7][1],\ + bb_world[7][1],\ + bb_world[7][2],\ + bb_world[7][2] + + # Test against the other 7 verts + for i in range (7): + + # X Range + val = bb_world[i][0] + if val < left: + left = val + + if val > right: + right = val + + # Y Range + val = bb_world[i][1] + if val < front: + front = val + + if val > back: + back = val + + # Z Range + val = bb_world[i][2] + if val < down: + down = val + + if val > up: + up = val + + return (Vector((left, front, up)), Vector((right, back, down))) + def align_objects(align_x, align_y, align_z, align_mode, relative_to): cursor = bpy.context.scene.cursor_location - Left_Up_Front_SEL = [0.0, 0.0, 0.0] - Right_Down_Back_SEL = [0.0, 0.0, 0.0] + Left_Front_Up_SEL = [0.0, 0.0, 0.0] + Right_Back_Down_SEL = [0.0, 0.0, 0.0] flag_first = True @@ -42,78 +81,81 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): return False for obj, bb_world in objs: - Left_Up_Front = bb_world[1] - Right_Down_Back = bb_world[7] + + GBB = GlobalBB(bb_world) + Left_Front_Up = GBB[0] + Right_Back_Down = GBB[1] # Active Center if obj == bpy.context.active_object: - center_active_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0 - center_active_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0 - center_active_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0 + center_active_x = (Left_Front_Up[0] + Right_Back_Down[0]) / 2.0 + center_active_y = (Left_Front_Up[1] + Right_Back_Down[1]) / 2.0 + center_active_z = (Left_Front_Up[2] + Right_Back_Down[2]) / 2.0 - size_active_x = (Right_Down_Back[0] - Left_Up_Front[0]) / 2.0 - size_active_y = (Right_Down_Back[1] - Left_Up_Front[1]) / 2.0 - size_active_z = (Left_Up_Front[2] - Right_Down_Back[2]) / 2.0 + size_active_x = (Right_Back_Down[0] - Left_Front_Up[0]) / 2.0 + size_active_y = (Right_Back_Down[1] - Left_Front_Up[1]) / 2.0 + size_active_z = (Left_Front_Up[2] - Right_Back_Down[2]) / 2.0 # Selection Center if flag_first: flag_first = False - Left_Up_Front_SEL[0] = Left_Up_Front[0] - Left_Up_Front_SEL[1] = Left_Up_Front[1] - Left_Up_Front_SEL[2] = Left_Up_Front[2] + Left_Front_Up_SEL[0] = Left_Front_Up[0] + Left_Front_Up_SEL[1] = Left_Front_Up[1] + Left_Front_Up_SEL[2] = Left_Front_Up[2] - Right_Down_Back_SEL[0] = Right_Down_Back[0] - Right_Down_Back_SEL[1] = Right_Down_Back[1] - Right_Down_Back_SEL[2] = Right_Down_Back[2] + Right_Back_Down_SEL[0] = Right_Back_Down[0] + Right_Back_Down_SEL[1] = Right_Back_Down[1] + Right_Back_Down_SEL[2] = Right_Back_Down[2] else: # X axis - if Left_Up_Front[0] < Left_Up_Front_SEL[0]: - Left_Up_Front_SEL[0] = Left_Up_Front[0] + if Left_Front_Up[0] < Left_Front_Up_SEL[0]: + Left_Front_Up_SEL[0] = Left_Front_Up[0] # Y axis - if Left_Up_Front[1] < Left_Up_Front_SEL[1]: - Left_Up_Front_SEL[1] = Left_Up_Front[1] + if Left_Front_Up[1] < Left_Front_Up_SEL[1]: + Left_Front_Up_SEL[1] = Left_Front_Up[1] # Z axis - if Left_Up_Front[2] > Left_Up_Front_SEL[2]: - Left_Up_Front_SEL[2] = Left_Up_Front[2] + if Left_Front_Up[2] > Left_Front_Up_SEL[2]: + Left_Front_Up_SEL[2] = Left_Front_Up[2] # X axis - if Right_Down_Back[0] > Right_Down_Back_SEL[0]: - Right_Down_Back_SEL[0] = Right_Down_Back[0] + if Right_Back_Down[0] > Right_Back_Down_SEL[0]: + Right_Back_Down_SEL[0] = Right_Back_Down[0] # Y axis - if Right_Down_Back[1] > Right_Down_Back_SEL[1]: - Right_Down_Back_SEL[1] = Right_Down_Back[1] + if Right_Back_Down[1] > Right_Back_Down_SEL[1]: + Right_Back_Down_SEL[1] = Right_Back_Down[1] # Z axis - if Right_Down_Back[2] < Right_Down_Back_SEL[2]: - Right_Down_Back_SEL[2] = Right_Down_Back[2] + if Right_Back_Down[2] < Right_Back_Down_SEL[2]: + Right_Back_Down_SEL[2] = Right_Back_Down[2] - center_sel_x = (Left_Up_Front_SEL[0] + Right_Down_Back_SEL[0]) / 2.0 - center_sel_y = (Left_Up_Front_SEL[1] + Right_Down_Back_SEL[1]) / 2.0 - center_sel_z = (Left_Up_Front_SEL[2] + Right_Down_Back_SEL[2]) / 2.0 + center_sel_x = (Left_Front_Up_SEL[0] + Right_Back_Down_SEL[0]) / 2.0 + center_sel_y = (Left_Front_Up_SEL[1] + Right_Back_Down_SEL[1]) / 2.0 + center_sel_z = (Left_Front_Up_SEL[2] + Right_Back_Down_SEL[2]) / 2.0 # Main Loop for obj, bb_world in objs: bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] - - Left_Up_Front = bb_world[1] - Right_Down_Back = bb_world[7] - - center_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0 - center_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0 - center_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0 - - positive_x = Right_Down_Back[0] - positive_y = Right_Down_Back[1] - positive_z = Left_Up_Front[2] - - negative_x = Left_Up_Front[0] - negative_y = Left_Up_Front[1] - negative_z = Right_Down_Back[2] + + GBB = GlobalBB(bb_world) + Left_Front_Up = GBB[0] + Right_Back_Down = GBB[1] + + center_x = (Left_Front_Up[0] + Right_Back_Down[0]) / 2.0 + center_y = (Left_Front_Up[1] + Right_Back_Down[1]) / 2.0 + center_z = (Left_Front_Up[2] + Right_Back_Down[2]) / 2.0 + + positive_x = Right_Back_Down[0] + positive_y = Right_Back_Down[1] + positive_z = Left_Front_Up[2] + + negative_x = Left_Front_Up[0] + negative_y = Left_Front_Up[1] + negative_z = Right_Back_Down[2] obj_loc = obj.location -- cgit v1.2.3 From 1191c1ead90928485f90faa201c296e857ffd050 Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Tue, 19 Jul 2011 15:07:29 +0000 Subject: Object Align operator: coudn't resist and added a high quality (slower) option to get perfect alighment on complex shapes with rotation/scaling :D sexy example: http://www.pasteall.org/pic/show.php?id=15171 --- .../scripts/startup/bl_operators/object_align.py | 75 ++++++++++++++++++++-- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 8bf5cc9e8fb..aefc12ed8df 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -21,7 +21,8 @@ import bpy from mathutils import Vector -def GlobalBB(bb_world): +def GlobalBB_LQ(bb_world): + # Initialize the variables with the 8th vertex left, right, front, back, down, up =\ bb_world[7][0],\ @@ -57,11 +58,58 @@ def GlobalBB(bb_world): if val > up: up = val + + return (Vector((left, front, up)), Vector((right, back, down))) + +def GlobalBB_HQ(obj): + + # Initialize the variables with the last vertex + + verts = obj.data.vertices + + val = verts[-1].co * obj.matrix_world + + left, right, front, back, down, up =\ + val[0],\ + val[0],\ + val[1],\ + val[1],\ + val[2],\ + val[2] + + # Test against all other verts + for i in range (len(verts)-1): + + vco = verts[i].co * obj.matrix_world + + # X Range + val = vco[0] + if val < left: + left = val + if val > right: + right = val + + # Y Range + val = vco[1] + if val < front: + front = val + + if val > back: + back = val + + # Z Range + val = vco[2] + if val < down: + down = val + + if val > up: + up = val + return (Vector((left, front, up)), Vector((right, back, down))) -def align_objects(align_x, align_y, align_z, align_mode, relative_to): +def align_objects(align_x, align_y, align_z, align_mode, relative_to, bb_quality): cursor = bpy.context.scene.cursor_location @@ -82,7 +130,11 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): for obj, bb_world in objs: - GBB = GlobalBB(bb_world) + if bb_quality: + GBB = GlobalBB_HQ(obj) + else: + GBB = GlobalBB_LQ(bb_world) + Left_Front_Up = GBB[0] Right_Back_Down = GBB[1] @@ -141,7 +193,11 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): for obj, bb_world in objs: bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] - GBB = GlobalBB(bb_world) + if bb_quality: + GBB = GlobalBB_HQ(obj) + else: + GBB = GlobalBB_LQ(bb_world) + Left_Front_Up = GBB[0] Right_Back_Down = GBB[1] @@ -270,7 +326,7 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to): return True -from bpy.props import EnumProperty +from bpy.props import EnumProperty, BoolProperty class AlignObjects(bpy.types.Operator): @@ -279,6 +335,11 @@ class AlignObjects(bpy.types.Operator): bl_label = "Align Objects" bl_options = {'REGISTER', 'UNDO'} + bb_quality = BoolProperty( + name="High Quality", + description="Enables high quality calculation of the bounding box for perfect results on complex shape meshes with rotation/scale (Slow)", + default=False) + align_mode = EnumProperty(items=( ('OPT_1', "Negative Sides", ""), ('OPT_2', "Centers", ""), @@ -311,10 +372,10 @@ class AlignObjects(bpy.types.Operator): def execute(self, context): align_axis = self.align_axis - ret = align_objects('X' in align_axis, 'Y' in align_axis, 'Z' in align_axis, self.align_mode, self.relative_to) + ret = align_objects('X' in align_axis, 'Y' in align_axis, 'Z' in align_axis, self.align_mode, self.relative_to, self.bb_quality) if not ret: self.report({'WARNING'}, "No objects with bound-box selected") return {'CANCELLED'} else: - return {'FINISHED'} + return {'FINISHED'} \ No newline at end of file -- 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(-) 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 fd7825e7dce2803c7864303d5346027d60d212ee Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Tue, 19 Jul 2011 15:30:19 +0000 Subject: Speedup, do only one global matrix grab per obj --- release/scripts/startup/bl_operators/object_align.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index aefc12ed8df..d215f3476cf 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -63,11 +63,13 @@ def GlobalBB_LQ(bb_world): def GlobalBB_HQ(obj): + matrix_world = obj.matrix_world.copy() + # Initialize the variables with the last vertex verts = obj.data.vertices - val = verts[-1].co * obj.matrix_world + val = verts[-1].co * matrix_world left, right, front, back, down, up =\ val[0],\ @@ -80,7 +82,7 @@ def GlobalBB_HQ(obj): # Test against all other verts for i in range (len(verts)-1): - vco = verts[i].co * obj.matrix_world + vco = verts[i].co * matrix_world # X Range val = vco[0] -- 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(-) 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) --- GNUmakefile | 4 ++-- source/blender/blenlib/intern/path_util.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index d1a60ce5e37..b6741d7e5f0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -73,7 +73,7 @@ all: @echo @echo Building Blender ... - make -C $(BUILD_DIR) -s -j $(NPROCS) install + $(MAKE) -C $(BUILD_DIR) -s -j $(NPROCS) install @echo @echo edit build configuration with: "$(BUILD_DIR)/CMakeCache.txt" run make again to rebuild. @echo blender installed, run from: "$(BUILD_DIR)/bin/blender" @@ -112,6 +112,6 @@ test_deprecated: python3 source/tests/check_deprecated.py clean: - make -C $(BUILD_DIR) clean + $(MAKE) -C $(BUILD_DIR) clean .PHONY: all 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 60ae40a0ed320cef275c2fd05eed97bd125d9a6e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 06:22:16 +0000 Subject: patch [#28030] SCONS Build: Build Date reflects "1" instead of actual date of build by Scott Giese (sgiese) This bug effected windows and linux. --- build_files/scons/tools/Blender.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py index d8f5ba9e115..75af7e47edd 100644 --- a/build_files/scons/tools/Blender.py +++ b/build_files/scons/tools/Blender.py @@ -320,11 +320,7 @@ def creator(env): defs.append('WITH_PYTHON') if env['BF_DEBUG']: defs.append('_DEBUG') - - if env['BF_BUILDINFO']: - defs.append('BUILD_DATE') - defs.append('NAN_BUILDINFO') - + if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc'): incs.append(env['BF_PTHREADS_INC']) -- 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(-) 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 4ad43aaf16951ff3b916497509b1499734f38d0b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 08:10:01 +0000 Subject: added bpy.path.basename because "//" prefix breaks os.path.basename. --- release/scripts/modules/bpy/path.py | 11 ++++++++++- release/scripts/modules/bpy_extras/image_utils.py | 6 ++++-- release/scripts/startup/bl_operators/image.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index 74d043f8a54..f6254efac2e 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -117,7 +117,7 @@ def display_name_from_filepath(name): """ Returns the path stripped of directort and extension, ensured to be utf8 compatible. """ - return _os.path.splitext(_os.path.basename(name))[0].encode("utf8", "replace").decode("utf8") + return _os.path.splitext(basename(name))[0].encode("utf8", "replace").decode("utf8") def resolve_ncase(path): @@ -231,3 +231,12 @@ def module_names(path, recursive=False): modules.append(("%s.%s" % (filename, mod_name), mod_path)) return modules + + +def basename(path): + """ + Equivalent to os.path.basename, but skips a "//" suffix. + + Use for Windows compatibility. + """ + return _os.path.basename(path[2:] if path.startswith("//") else path) diff --git a/release/scripts/modules/bpy_extras/image_utils.py b/release/scripts/modules/bpy_extras/image_utils.py index f91535a0ad4..e56c1c651c4 100644 --- a/release/scripts/modules/bpy_extras/image_utils.py +++ b/release/scripts/modules/bpy_extras/image_utils.py @@ -86,7 +86,9 @@ def load_image(imagepath, variants = [imagepath] if dirname: - variants += [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))] + variants += [os.path.join(dirname, imagepath), + os.path.join(dirname, bpy.path.basename(imagepath)), + ] for filepath_test in variants: if ncase_cmp: @@ -99,7 +101,7 @@ def load_image(imagepath, return _image_load(nfilepath) if place_holder: - image = bpy.data.images.new(os.path.basename(imagepath), 128, 128) + image = bpy.data.images.new(bpy.path.basename(imagepath), 128, 128) # allow the path to be resolved later image.filepath = imagepath return image diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 34c5b0d922a..4bb53f776ba 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -163,7 +163,7 @@ class ProjectEdit(bpy.types.Operator): filepath_final = filepath + ("%.3d.%s" % (i, EXT)) i += 1 - image_new.name = os.path.basename(filepath_final) + image_new.name = bpy.path.basename(filepath_final) ProjectEdit._proj_hack[0] = image_new.name image_new.filepath_raw = filepath_final # TODO, filepath raw is crummy -- cgit v1.2.3 From 76e91d7a5f8c253543bd1c938c8e74872d7a6c81 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 20 Jul 2011 15:33:27 +0000 Subject: fix [#27922] using preset_paths() with an absolute path returns twice the same thing raise an error when an invalid subdir is passed to preset_paths() --- release/scripts/modules/bpy/utils.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 7c0d3d24cba..57d3e6dd703 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -298,11 +298,18 @@ _presets = _os.path.join(_scripts[0], "presets") # FIXME - multiple paths def preset_paths(subdir): """ Returns a list of paths for a specific preset. + + :arg subdir: preset subdirectory (must not be an absolute path). + :type subdir: string + :return: script paths. + :rtype: list """ dirs = [] for path in script_paths("presets", all=True): directory = _os.path.join(path, subdir) - if _os.path.isdir(directory): + if not directory.startswith(path): + raise Exception("invalid subdir given %r" % subdir) + elif _os.path.isdir(directory): dirs.append(directory) return dirs -- 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(-) 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(-) 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(-) 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(-) 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(+) 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(-) 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(-) 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) --- release/scripts/startup/bl_ui/space_image.py | 4 ++++ source/blender/editors/transform/transform_ops.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 722b46aba11..fa5579ea2e0 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -198,6 +198,10 @@ class IMAGE_MT_uvs_transform(bpy.types.Menu): layout.operator("transform.rotate") layout.operator("transform.resize") + layout.separator() + + layout.operator("transform.shear") + class IMAGE_MT_uvs_snap(bpy.types.Menu): bl_label = "Snap" 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 --- CMakeLists.txt | 1 + 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 ++ 7 files changed, 16 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ebf7aa8a6c0..d4489a8c76b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,6 +155,7 @@ option(WITH_IMAGE_DDS "Enable DDS Image Support" ON) option(WITH_IMAGE_CINEON "Enable CINEON and DPX Image Support" ON) option(WITH_IMAGE_HDR "Enable HDR Image Support" ON) option(WITH_IMAGE_REDCODE "Enable RedCode Image Support" OFF) +option(WITH_IMAGE_FRAMESERVER "Enable image FrameServer Support for rendering" ON) # Audio/Video format support option(WITH_CODEC_FFMPEG "Enable FFMPeg Support (http://ffmpeg.org)" OFF) 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(-) 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(-) 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(-) 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(+) 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(-) 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 382050501dc0036dc28434b205215ebc21a0cf1b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 22 Jul 2011 11:21:01 +0000 Subject: remove duplicate function for printing the current file:line of a python script in the BGE. --- source/gameengine/Expressions/PyObjectPlus.cpp | 38 +------------------------- source/gameengine/Expressions/PyObjectPlus.h | 1 + 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp index 3a25df73f9b..92be769ed71 100644 --- a/source/gameengine/Expressions/PyObjectPlus.cpp +++ b/source/gameengine/Expressions/PyObjectPlus.cpp @@ -1184,46 +1184,10 @@ void PyObjectPlus::SetDeprecationWarnings(bool ignoreDeprecationWarnings) m_ignore_deprecation_warnings = ignoreDeprecationWarnings; } -void PyDebugLine() -{ - // import sys; print '\t%s:%d' % (sys._getframe(0).f_code.co_filename, sys._getframe(0).f_lineno) - - PyObject *getframe, *frame; - PyObject *f_lineno, *f_code, *co_filename; - - getframe = PySys_GetObject((char *)"_getframe"); // borrowed - if (getframe) { - frame = PyObject_CallObject(getframe, NULL); - if (frame) { - f_lineno= PyObject_GetAttrString(frame, "f_lineno"); - f_code= PyObject_GetAttrString(frame, "f_code"); - if (f_lineno && f_code) { - co_filename= ((PyCodeObject *)f_code)->co_filename; /* borrow */ - if (co_filename) { - - printf("\t%s:%d\n", _PyUnicode_AsString(co_filename), (int)PyLong_AsSsize_t(f_lineno)); - - Py_DECREF(f_lineno); - Py_DECREF(f_code); - Py_DECREF(frame); - return; - } - } - - Py_XDECREF(f_lineno); - Py_XDECREF(f_code); - Py_DECREF(frame); - } - - } - PyErr_Clear(); - printf("\tERROR - Could not access sys._getframe(0).f_lineno or sys._getframe().f_code.co_filename\n"); -} - void PyObjectPlus::ShowDeprecationWarning_func(const char* old_way,const char* new_way) { printf("Method %s is deprecated, please use %s instead.\n", old_way, new_way); - PyDebugLine(); + PyC_LineSpit(); } void PyObjectPlus::ClearDeprecationWarning() diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h index 587f3e4ef35..51cfb5471c0 100644 --- a/source/gameengine/Expressions/PyObjectPlus.h +++ b/source/gameengine/Expressions/PyObjectPlus.h @@ -55,6 +55,7 @@ #ifdef USE_MATHUTILS extern "C" { #include "../../blender/python/mathutils/mathutils.h" /* so we can have mathutils callbacks */ +#include "../../blender/python/generic/py_capi_utils.h" /* for PyC_LineSpit only */ } #endif -- 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(-) 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 89c062038aaa43e14bc280062fe94e13435bef46 Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Fri, 22 Jul 2011 15:54:54 +0000 Subject: Let's try default High Quality for object align, it's slow but it's simply the correct way, users can disable while tweaking the align modes and then enable again for final result IF they are working on *dense* meshes --- release/scripts/startup/bl_operators/object_align.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index d215f3476cf..952a2328ca9 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -340,7 +340,7 @@ class AlignObjects(bpy.types.Operator): bb_quality = BoolProperty( name="High Quality", description="Enables high quality calculation of the bounding box for perfect results on complex shape meshes with rotation/scale (Slow)", - default=False) + default=True) align_mode = EnumProperty(items=( ('OPT_1', "Negative Sides", ""), @@ -380,4 +380,4 @@ class AlignObjects(bpy.types.Operator): self.report({'WARNING'}, "No objects with bound-box selected") return {'CANCELLED'} else: - return {'FINISHED'} \ No newline at end of file + return {'FINISHED'} -- 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(-) 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(-) 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 8cbd88aeef2ece7fc1c436db5284ac115b230c57 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 23 Jul 2011 15:36:51 +0000 Subject: 2.5 UI: * Added back icon to open the Splash Screen in the info header, next to version string info. * Removed an unnecessary toggle argument for particle mode select buttons. The Toggle argument is only intended for booleans, not enums. --- release/scripts/startup/bl_ui/space_info.py | 6 ++++-- release/scripts/startup/bl_ui/space_view3d.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 2b12e75564c..cda37b3119a 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -60,8 +60,10 @@ class INFO_HT_header(bpy.types.Header): layout.template_running_jobs() layout.template_reports_banner() - - layout.label(text=scene.statistics()) + + row = layout.row(align=True) + row.operator("wm.splash", text="", icon='BLENDER', emboss=False) + row.label(text=scene.statistics()) # XXX: this should be right-aligned to the RHS of the region layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index aef6accb4e1..b5e813d16e7 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -68,7 +68,7 @@ class VIEW3D_HT_header(bpy.types.Header): if obj: # Particle edit if obj.mode == 'PARTICLE_EDIT': - row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True, toggle=True) + row.prop(toolsettings.particle_edit, "select_mode", text="", expand=True) # Occlude geometry if view.viewport_shade in {'SOLID', 'SHADED', 'TEXTURED'} and (obj.mode == 'PARTICLE_EDIT' or (obj.mode == 'EDIT' and obj.type == 'MESH')): -- cgit v1.2.3 From f4a30e473b23425c13a755854cf7b22c22cca259 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sat, 23 Jul 2011 16:08:37 +0000 Subject: =?UTF-8?q?Cherry=20pick=20merge:=20/branches/soc-2011-pepper/inte?= =?UTF-8?q?rn/audaspace/OpenAL:r38630=20Original=20log:=20Corrected=20the?= =?UTF-8?q?=20OpenAL=20device's=20threading=20code.=20This=20is=20a=20bugf?= =?UTF-8?q?ix=20for=20#27913,=20thanks=20to=20Juha=20M=C3=A4ki-Kanto=20for?= =?UTF-8?q?=20helping=20to=20resolve=20this.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- intern/audaspace/OpenAL/AUD_OpenALDevice.cpp | 18 +++++++++--------- intern/audaspace/OpenAL/AUD_OpenALDevice.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp index b9e30bbf62a..71e7b7677e8 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp @@ -105,12 +105,15 @@ void* AUD_openalRunThread(void* device) return NULL; } -void AUD_OpenALDevice::start() +void AUD_OpenALDevice::start(bool join) { lock(); if(!m_playing) { + if(join) + pthread_join(m_thread, NULL); + pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); @@ -271,8 +274,8 @@ void AUD_OpenALDevice::updateStreams() // stop thread if(m_playingSounds->empty() || (cerr != ALC_NO_ERROR)) { - unlock(); m_playing = false; + unlock(); pthread_exit(NULL); } @@ -366,6 +369,8 @@ AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize) pthread_mutex_init(&m_mutex, &attr); pthread_mutexattr_destroy(&attr); + + start(false); } AUD_OpenALDevice::~AUD_OpenALDevice() @@ -414,13 +419,8 @@ AUD_OpenALDevice::~AUD_OpenALDevice() alcProcessContext(m_context); // wait for the thread to stop - if(m_playing) - { - unlock(); - pthread_join(m_thread, NULL); - } - else - unlock(); + unlock(); + pthread_join(m_thread, NULL); delete m_playingSounds; delete m_pausedSounds; diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.h b/intern/audaspace/OpenAL/AUD_OpenALDevice.h index 3bbbe85d7e6..127f69beca8 100644 --- a/intern/audaspace/OpenAL/AUD_OpenALDevice.h +++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.h @@ -106,7 +106,7 @@ private: /** * Starts the streaming thread. */ - void start(); + void start(bool join = true); /** * Checks if a handle is valid. -- 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(-) 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 39edc5355893e7582cab8960feb7b70a0de0be31 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sat, 23 Jul 2011 21:45:22 +0000 Subject: 2.5 External animation player: * Fixed an error when "Custom" was used and the path was empty (variable reference before assignment) * The Operator now raises an error if there is no path or the path given is not available. --- .../startup/bl_operators/screen_play_rendered_anim.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 910ccf96c0e..8699862d24b 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -59,6 +59,9 @@ def guess_player_path(preset): elif preset == 'MPLAYER': player_path = "mplayer" + + else: + player_path = "" return player_path @@ -131,12 +134,14 @@ class PlayRenderedAnim(bpy.types.Operator): cmd.extend(opts) else: # 'CUSTOM' cmd.append(file) - - # launch it - try: - process = subprocess.Popen(cmd) - except: - pass - #raise OSError("Couldn't find an external animation player.") + + if (player_path == "") or (os.path.exists(player_path)==False): + self.report({'ERROR'}, "Couldn't find an external animation player") + else: + # launch it + try: + process = subprocess.Popen(cmd) + except: + pass return {'FINISHED'} -- 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. --- release/scripts/startup/bl_ui/space_view3d.py | 12 ++---------- source/blender/editors/space_view3d/view3d_header.c | 11 ----------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index b5e813d16e7..7d35ca9ddb8 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -54,16 +54,8 @@ class VIEW3D_HT_header(bpy.types.Header): sub.menu("VIEW3D_MT_object") row = layout.row() - row.template_header_3D() - - # do in C for now since these buttons cant be both toggle AND exclusive. - ''' - if obj and obj.mode == 'EDIT' and obj.type == 'MESH': - row_sub = row.row(align=True) - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=0, icon='VERTEXSEL') - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=1, icon='EDGESEL') - row_sub.prop(toolsettings, "mesh_select_mode", text="", index=2, icon='FACESEL') - ''' + # Contains buttons like Mode, Pivot, Manipulator, Layer, Mesh Select Mode... + row.template_header_3D() if obj: # Particle edit 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 cb2423e849d03cf1d288df94401cfd8d49c8ff56 Mon Sep 17 00:00:00 2001 From: Daniel Salazar Date: Sun, 24 Jul 2011 00:59:03 +0000 Subject: Add Push/Pull to toolbar --- release/scripts/startup/bl_ui/space_view3d_toolbar.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index e1efeed87ea..19c3224f138 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -116,7 +116,8 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel): col.operator("transform.translate") col.operator("transform.rotate") col.operator("transform.resize", text="Scale") - col.operator("transform.shrink_fatten", text="Along Normal") + col.operator("transform.shrink_fatten", text="Shrink/Fatten") + col.operator("transform.push_pull", text="Push/Pull") col = layout.column(align=True) col.label(text="Deform:") -- 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(-) 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(-) 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 4ab7c6ae1a6d9867d30d5eb960aece38bb0233f7 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Sun, 24 Jul 2011 11:24:30 +0000 Subject: 2.5 World Buttons: * Exposure and Color Range buttons were missing, added them back. --- release/scripts/startup/bl_ui/properties_world.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_world.py b/release/scripts/startup/bl_ui/properties_world.py index 4f398c9fbd9..0272667e754 100644 --- a/release/scripts/startup/bl_ui/properties_world.py +++ b/release/scripts/startup/bl_ui/properties_world.py @@ -20,8 +20,6 @@ import bpy from rna_prop_ui import PropertyPanel -# TODO, "color_range" not in the UI - class WorldButtonsPanel(): bl_space_type = 'PROPERTIES' @@ -95,6 +93,10 @@ class WORLD_PT_world(WorldButtonsPanel, bpy.types.Panel): col.prop(world, "zenith_color") col.active = world.use_sky_blend row.column().prop(world, "ambient_color") + + row = layout.row() + row.prop(world, "exposure") + row.prop(world, "color_range") class WORLD_PT_ambient_occlusion(WorldButtonsPanel, bpy.types.Panel): -- 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(-) 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. --- .../startup/bl_operators/uvcalc_smart_project.py | 4 +- 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 +++++++++++++++++++++- 5 files changed, 120 insertions(+), 6 deletions(-) diff --git a/release/scripts/startup/bl_operators/uvcalc_smart_project.py b/release/scripts/startup/bl_operators/uvcalc_smart_project.py index 9c3be84b807..851f33bde11 100644 --- a/release/scripts/startup/bl_operators/uvcalc_smart_project.py +++ b/release/scripts/startup/bl_operators/uvcalc_smart_project.py @@ -243,7 +243,7 @@ def testNewVecLs2DRotIsBetter(vecs, mat=-1, bestAreaSoFar = -1): # Do this allong the way if mat != -1: - v = vecs[i] = v*mat + v = vecs[i] = mat * v x= v.x y= v.y if xsize, 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 7f60ee6cb5f3a483cb244ab640967131017f3bcc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 03:59:01 +0000 Subject: reverse vector multiplication order for some internal functions. --- release/scripts/modules/bpy_extras/view3d_utils.py | 10 +++++----- release/scripts/modules/bpy_types.py | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/release/scripts/modules/bpy_extras/view3d_utils.py b/release/scripts/modules/bpy_extras/view3d_utils.py index c0c0f9186bd..5796abce72c 100644 --- a/release/scripts/modules/bpy_extras/view3d_utils.py +++ b/release/scripts/modules/bpy_extras/view3d_utils.py @@ -50,11 +50,11 @@ def region_2d_to_vector_3d(region, rv3d, coord): -0.5 )) - w = (out[0] * persinv[0][3]) + \ - (out[1] * persinv[1][3]) + \ - (out[2] * persinv[2][3]) + persinv[3][3] + w = ((out[0] * persinv[0][3]) + + (out[1] * persinv[1][3]) + + (out[2] * persinv[2][3]) + persinv[3][3]) - return ((out * persinv) / w) - rv3d.view_matrix.inverted()[3].xyz + return ((persinv * out) / w) - rv3d.view_matrix.inverted()[3].xyz else: return rv3d.view_matrix.inverted()[2].xyz.normalized() @@ -116,7 +116,7 @@ def location_3d_to_region_2d(region, rv3d, coord): """ from mathutils import Vector - prj = Vector((coord[0], coord[1], coord[2], 1.0)) * rv3d.perspective_matrix + prj = rv3d.perspective_matrix * Vector((coord[0], coord[1], coord[2], 1.0)) if prj.w > 0.0: width_half = region.width / 2.0 height_half = region.height / 2.0 diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index f2cd46b20ae..8766c873dd8 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -144,21 +144,21 @@ class _GenericBone: """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((1.0, 0.0, 0.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((1.0, 0.0, 0.0)) @property def y_axis(self): """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((0.0, 1.0, 0.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((0.0, 1.0, 0.0)) @property def z_axis(self): """ Vector pointing down the x-axis of the bone. """ from mathutils import Vector - return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() + return self.matrix.to_3x3() * Vector((0.0, 0.0, 1.0)) @property def basename(self): @@ -294,9 +294,9 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): :type roll: bool """ from mathutils import Vector - z_vec = Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3() - self.tail = self.tail * matrix - self.head = self.head * matrix + z_vec = self.matrix.to_3x3() * Vector((0.0, 0.0, 1.0)) + self.tail = matrix * self.tail + self.head = matrix * self.head if scale: scalar = matrix.median_scale @@ -304,7 +304,7 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaPropGroup): self.tail_radius *= scalar if roll: - self.align_roll(z_vec * matrix) + self.align_roll(matrix * z_vec) def ord_ind(i1, i2): -- cgit v1.2.3 From 5132be21d1697a636e62b9b71b9741e1b6c5e0b3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 04:00:11 +0000 Subject: fix [#28075] After the correction of No.38528 is applied, the following phenomenon has been generated. own fault in recent addition of bpy.path.basename() not supporting byte paths. --- release/scripts/modules/bpy/path.py | 2 +- source/tests/CMakeLists.txt | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py index f6254efac2e..eb1a5ffc455 100644 --- a/release/scripts/modules/bpy/path.py +++ b/release/scripts/modules/bpy/path.py @@ -239,4 +239,4 @@ def basename(path): Use for Windows compatibility. """ - return _os.path.basename(path[2:] if path.startswith("//") else path) + return _os.path.basename(path[2:] if path[:2] in {"//", b"//"} else path) diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt index d1696223ec6..8fd0d6e7099 100644 --- a/source/tests/CMakeLists.txt +++ b/source/tests/CMakeLists.txt @@ -196,7 +196,7 @@ add_test(export_x3d_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\) --md5_source=${TEST_OUT_DIR}/export_x3d_cube.x3d - --md5=6ae36be272d6f84c697e84a8b6463273 --md5_method=FILE + --md5=5e804c689896116331fa190a9fabbad4 --md5_method=FILE ) add_test(export_x3d_nurbs ${TEST_BLENDER_EXE} @@ -212,7 +212,7 @@ add_test(export_x3d_all_objects ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\) --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d - --md5=bba48ca191e8891adb27c59ed4ce4735 --md5_method=FILE + --md5=2809ec13a4cab55d265ce7525c5db1b7 --md5_method=FILE ) @@ -261,7 +261,7 @@ add_test(export_3ds_all_objects ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\) --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds - --md5=cdf8fa8475fda0b9ef565ac09339254b --md5_method=FILE + --md5=0940ea889498cd437d503670738639ae --md5_method=FILE ) @@ -273,7 +273,7 @@ add_test(export_fbx_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\) --md5_source=${TEST_OUT_DIR}/export_fbx_cube.fbx - --md5=642a5a1fa199d5b9bbf1643519ae974d --md5_method=FILE + --md5=83dca99a0cb338852b8c85951a44c68a --md5_method=FILE ) add_test(export_fbx_nurbs ${TEST_BLENDER_EXE} @@ -281,7 +281,7 @@ add_test(export_fbx_nurbs ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\) --md5_source=${TEST_OUT_DIR}/export_fbx_nurbs.fbx - --md5=ec1e8965bdbc3bf70707d77f82c2cb9c --md5_method=FILE + --md5=c7d9491ffa6264e820ed1e12df63f871 --md5_method=FILE ) add_test(export_fbx_all_objects ${TEST_BLENDER_EXE} @@ -289,5 +289,5 @@ add_test(export_fbx_all_objects ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\) --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx - --md5=af3b65665687ac92e4aba07b017d87fe --md5_method=FILE + --md5=22867f82e1615fd1eae18cfaac8ba035 --md5_method=FILE ) -- cgit v1.2.3 From 3e91de7ffd80dfc236fb16cb440bb77f53c36f0c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 05:10:44 +0000 Subject: External image operators. - use bpy.data.is_saved (was using a workaround from when before this attribute was added) - fixed a bug where editing relative paths could fail. --- release/scripts/startup/bl_operators/image.py | 34 ++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index 4bb53f776ba..23bafe2eaae 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy from bpy.props import StringProperty @@ -28,7 +28,11 @@ class EditExternally(bpy.types.Operator): bl_label = "Image Edit Externally" bl_options = {'REGISTER'} - filepath = StringProperty(name="File Path", description="Path to an image file", maxlen=1024, default="") + filepath = StringProperty( + name="File Path", + description="Path to an image file", + maxlen=1024, + ) def _editor_guess(self, context): import sys @@ -57,10 +61,13 @@ class EditExternally(bpy.types.Operator): def execute(self, context): import os import subprocess - filepath = bpy.path.abspath(self.filepath) + filepath = os.path.normpath(bpy.path.abspath(self.filepath)) if not os.path.exists(filepath): - self.report({'ERROR'}, "Image path %r not found, image may be packed or unsaved." % filepath) + self.report({'ERROR'}, + "Image path %r not found, image may be packed or " + "unsaved." % filepath) + return {'CANCELLED'} cmd = self._editor_guess(context) + [filepath] @@ -70,7 +77,10 @@ class EditExternally(bpy.types.Operator): except: import traceback traceback.print_exc() - self.report({'ERROR'}, "Image editor not found, please specify in User Preferences > File") + self.report({'ERROR'}, + "Image editor not found, " + "please specify in User Preferences > File") + return {'CANCELLED'} return {'FINISHED'} @@ -104,7 +114,9 @@ class SaveDirty(bpy.types.Operator): if "\\" not in filepath and "/" not in filepath: self.report({'WARNING'}, "Invalid path: " + filepath) elif filepath in unique_paths: - self.report({'WARNING'}, "Path used by more then one image: " + filepath) + self.report({'WARNING'}, + "Path used by more then one image: %r" % + filepath) else: unique_paths.add(filepath) image.save() @@ -142,14 +154,14 @@ class ProjectEdit(bpy.types.Operator): filepath = os.path.basename(bpy.data.filepath) filepath = os.path.splitext(filepath)[0] - # filepath = bpy.path.clean_name(filepath) # fixes rubbish, needs checking + # fixes rubbish, needs checking + # filepath = bpy.path.clean_name(filepath) - if filepath.startswith(".") or filepath == "": - # TODO, have a way to check if the file is saved, assume startup.blend + if bpy.data.is_saved: + filepath = "//" + filepath + else: tmpdir = context.user_preferences.filepaths.temporary_directory filepath = os.path.join(tmpdir, "project_edit") - else: - filepath = "//" + filepath obj = context.object -- cgit v1.2.3 From d4552034c679fc5d052f1aedc6b224940dd4cb70 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 05:54:32 +0000 Subject: edits to quick effects scripts - use uv layer data api rather then operator. - switch vector rotation order. - made some style changes, use 80 width. --- .../startup/bl_operators/object_quick_effects.py | 134 +++++++++++++-------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 074f204d50e..ef10bfd737d 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -16,11 +16,16 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# from mathutils import Vector import bpy -from bpy.props import BoolProperty, EnumProperty, IntProperty, FloatProperty, FloatVectorProperty +from bpy.props import (BoolProperty, + EnumProperty, + IntProperty, + FloatProperty, + FloatVectorProperty, + ) def object_ensure_material(obj, mat_name): @@ -61,7 +66,8 @@ class QuickFur(bpy.types.Operator): def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] + mesh_objects = [obj for obj in context.selected_objects + if obj.type == 'MESH'] if not mesh_objects: self.report({'ERROR'}, "Select at least one mesh object.") @@ -92,7 +98,8 @@ class QuickFur(bpy.types.Operator): psys.settings.child_type = 'INTERPOLATED' obj.data.materials.append(mat) - obj.particle_systems[-1].settings.material = len(obj.data.materials) + obj.particle_systems[-1].settings.material = \ + len(obj.data.materials) return {'FINISHED'} @@ -149,7 +156,10 @@ class QuickExplode(bpy.types.Operator): for obj in mesh_objects: if obj.particle_systems: - self.report({'ERROR'}, "Object %r already has a particle system" % obj.name) + self.report({'ERROR'}, + "Object %r already has a " + "particle system" % obj.name) + return {'CANCELLED'} if self.fade: @@ -184,9 +194,7 @@ class QuickExplode(bpy.types.Operator): if self.fade: explode.show_dead = False - bpy.ops.mesh.uv_texture_add(fake_context) - uv = obj.data.uv_textures[-1] - uv.name = "Explode fade" + uv = obj.data.uv_textures.new("Explode fade") explode.particle_uv = uv.name mat = object_ensure_material(obj, "Explode Fade") @@ -247,7 +255,7 @@ class QuickExplode(bpy.types.Operator): def obj_bb_minmax(obj, min_co, max_co): for i in range(0, 8): - bb_vec = Vector(obj.bound_box[i]) * obj.matrix_world + bb_vec = obj.matrix_world * Vector(obj.bound_box[i]) min_co[0] = min(bb_vec[0], min_co[0]) min_co[1] = min(bb_vec[1], min_co[1]) @@ -262,21 +270,26 @@ class QuickSmoke(bpy.types.Operator): bl_label = "Quick Smoke" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty(items=( - ('STREAM', "Stream", ""), - ('PUFF', "Puff", ""), - ('FIRE', "Fire", "")), - name="Smoke Style", - description="", - default='STREAM') - - show_flows = BoolProperty(name="Render Smoke Objects", - description="Keep the smoke objects visible during rendering.", - default=False) + style = EnumProperty( + items=(('STREAM', "Stream", ""), + ('PUFF', "Puff", ""), + ('FIRE', "Fire", ""), + ), + name="Smoke Style", + description="", + default='STREAM', + ) + + show_flows = BoolProperty( + name="Render Smoke Objects", + description="Keep the smoke objects visible during rendering.", + default=False, + ) def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] + mesh_objects = [obj for obj in context.selected_objects + if obj.type == 'MESH'] min_co = Vector((100000.0, 100000.0, 100000.0)) max_co = -min_co @@ -336,21 +349,25 @@ class QuickSmoke(bpy.types.Operator): mat.volume.density = 0 mat.volume.density_scale = 5 - mat.texture_slots.add() - mat.texture_slots[0].texture = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA') - mat.texture_slots[0].texture.voxel_data.domain_object = obj - mat.texture_slots[0].use_map_color_emission = False - mat.texture_slots[0].use_map_density = True + tex = bpy.data.textures.new("Smoke Density", 'VOXEL_DATA') + tex.voxel_data.domain_object = obj + + tex_slot = mat.texture_slots.add() + tex_slot.texture = tex + tex_slot.use_map_color_emission = False + tex_slot.use_map_density = True # for fire add a second texture for emission and emission color if self.style == 'FIRE': mat.volume.emission = 5 - mat.texture_slots.add() - mat.texture_slots[1].texture = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA') - mat.texture_slots[1].texture.voxel_data.domain_object = obj - mat.texture_slots[1].texture.use_color_ramp = True + tex = bpy.data.textures.new("Smoke Heat", 'VOXEL_DATA') + tex.voxel_data.domain_object = obj + tex.use_color_ramp = True + + tex_slot = mat.texture_slots.add() + tex_slot.texture = tex - ramp = mat.texture_slots[1].texture.color_ramp + ramp = tex.color_ramp elem = ramp.elements.new(0.333) elem.color[0] = elem.color[3] = 1 @@ -371,28 +388,38 @@ class QuickFluid(bpy.types.Operator): bl_label = "Quick Fluid" bl_options = {'REGISTER', 'UNDO'} - style = EnumProperty(items=( - ('INFLOW', "Inflow", ""), - ('BASIC', "Basic", "")), + style = EnumProperty( + items=(('INFLOW', "Inflow", ""), + ('BASIC', "Basic", ""), + ), name="Fluid Style", description="", - default='BASIC') - - initial_velocity = FloatVectorProperty(name="Initial Velocity", - description="Initial velocity of the fluid", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='VELOCITY') - - show_flows = BoolProperty(name="Render Fluid Objects", - description="Keep the fluid objects visible during rendering.", - default=False) - - start_baking = BoolProperty(name="Start Fluid Bake", - description="Start baking the fluid immediately after creating the domain object.", - default=False) + default='BASIC', + ) + initial_velocity = FloatVectorProperty( + name="Initial Velocity", + description="Initial velocity of the fluid", + default=(0.0, 0.0, 0.0), + min=-100.0, + max=100.0, + subtype='VELOCITY', + ) + show_flows = BoolProperty( + name="Render Fluid Objects", + description="Keep the fluid objects visible during rendering.", + default=False, + ) + start_baking = BoolProperty( + name="Start Fluid Bake", + description=("Start baking the fluid immediately " + "after creating the domain object"), + default=False, + ) def execute(self, context): fake_context = bpy.context.copy() - mesh_objects = [obj for obj in context.selected_objects if (obj.type == 'MESH' and not 0 in obj.dimensions)] + mesh_objects = [obj for obj in context.selected_objects + if (obj.type == 'MESH' and not 0.0 in obj.dimensions)] min_co = Vector((100000, 100000, 100000)) max_co = Vector((-100000, -100000, -100000)) @@ -405,7 +432,8 @@ class QuickFluid(bpy.types.Operator): # make each selected object a fluid bpy.ops.object.modifier_add(fake_context, type='FLUID_SIMULATION') - # fluid has to be before constructive modifiers, so it might not be the last modifier + # fluid has to be before constructive modifiers, + # so it might not be the last modifier for mod in obj.modifiers: if mod.type == 'FLUID_SIMULATION': break @@ -429,10 +457,14 @@ class QuickFluid(bpy.types.Operator): obj = context.active_object obj.name = "Fluid Domain" - # give the fluid some room below the flows and scale with initial velocity + # give the fluid some room below the flows + # and scale with initial velocity v = 0.5 * self.initial_velocity obj.location = 0.5 * (max_co + min_co) + Vector((0.0, 0.0, -1.0)) + v - obj.scale = 0.5 * (max_co - min_co) + Vector((1.0, 1.0, 2.0)) + Vector((abs(v[0]), abs(v[1]), abs(v[2]))) + obj.scale = (0.5 * (max_co - min_co) + + Vector((1.0, 1.0, 2.0)) + + Vector((abs(v[0]), abs(v[1]), abs(v[2]))) + ) # setup smoke domain bpy.ops.object.modifier_add(type='FLUID_SIMULATION') -- cgit v1.2.3 From a07d7edb8220b6b5d06aa415d236cd35cf0535ca Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 06:09:39 +0000 Subject: swap vertor multiplication order for add torus. --- release/scripts/startup/bl_operators/add_mesh_torus.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 6ab803cc469..27a6d21d519 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy import mathutils @@ -40,8 +40,10 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): for minor_index in range(minor_seg): angle = 2 * pi * minor_index / minor_seg - vec = Vector((major_rad + (cos(angle) * minor_rad), 0.0, - (sin(angle) * minor_rad))) * quat + vec = quat * Vector((major_rad + (cos(angle) * minor_rad), + 0.0, + (sin(angle) * minor_rad), + )) verts.extend(vec[:]) @@ -72,7 +74,11 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): return verts, faces -from bpy.props import FloatProperty, IntProperty, BoolProperty, FloatVectorProperty +from bpy.props import (FloatProperty, + IntProperty, + BoolProperty, + FloatVectorProperty, + ) class AddTorus(bpy.types.Operator): @@ -82,7 +88,8 @@ class AddTorus(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} major_radius = FloatProperty(name="Major Radius", - description="Radius from the origin to the center of the cross sections", + description=("Radius from the origin to the " + "center of the cross sections"), default=1.0, min=0.01, max=100.0) minor_radius = FloatProperty(name="Minor Radius", description="Radius of the torus' cross section", -- cgit v1.2.3 From 6065390f4ccae14cabc1bac294d34598a7e90dbf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 06:38:21 +0000 Subject: fix for DingTo's recent commit with the animation player, it ignored the case where the player is not an absolute path but found in the users $PATH (as is common on *nix systems). now try and execute player, reporting the exception rather then checking the player file exists. also made some pep8-80 style edits. --- .../bl_operators/screen_play_rendered_anim.py | 35 ++++++++++++---------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 8699862d24b..bab74962f31 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -18,7 +18,7 @@ # # ***** END GPL LICENCE BLOCK ***** -# +# # History # @@ -46,8 +46,10 @@ def guess_player_path(preset): player_path = "djv_view" if sys.platform == "darwin": - # TODO, crummy supporting only 1 version, could find the newest installed version - test_path = '/Applications/djv-0.8.2.app/Contents/Resources/bin/djv_view' + # TODO, crummy supporting only 1 version, + # could find the newest installed version + test_path = ("/Applications/djv-0.8.2.app" + "/Contents/Resources/bin/djv_view") if os.path.exists(test_path): player_path = test_path @@ -59,7 +61,7 @@ def guess_player_path(preset): elif preset == 'MPLAYER': player_path = "mplayer" - + else: player_path = "" @@ -85,10 +87,10 @@ class PlayRenderedAnim(bpy.types.Operator): is_movie = rd.is_movie_format # try and guess a command line if it doesn't exist - if player_path == '': + if player_path == "": player_path = guess_player_path(preset) - if is_movie == False and preset in ('FRAMECYCLER', 'RV', 'MPLAYER'): + if is_movie == False and preset in {'FRAMECYCLER', 'RV', 'MPLAYER'}: # replace the number with '#' file_a = rd.frame_path(frame=0) @@ -102,7 +104,8 @@ class PlayRenderedAnim(bpy.types.Operator): file_b = rd.frame_path(frame=frame_tmp) file_b = rd.frame_path(frame=int(frame_tmp / 10)) - file = "".join((c if file_b[i] == c else "#") for i, c in enumerate(file_a)) + file = ("".join((c if file_b[i] == c else "#") + for i, c in enumerate(file_a))) else: # works for movies and images file = rd.frame_path(frame=scene.frame_start) @@ -134,14 +137,14 @@ class PlayRenderedAnim(bpy.types.Operator): cmd.extend(opts) else: # 'CUSTOM' cmd.append(file) - - if (player_path == "") or (os.path.exists(player_path)==False): - self.report({'ERROR'}, "Couldn't find an external animation player") - else: - # launch it - try: - process = subprocess.Popen(cmd) - except: - pass + + # launch it + try: + process = subprocess.Popen(cmd) + except Exception as e: + import traceback + self.report({'ERROR'}, + "Couldn't run external animation player with command " + "%r\n%s" % (" ".join(cmd), str(e))) return {'FINISHED'} -- cgit v1.2.3 From 4f4eeb826aaae7ed5909fd6e5f718c0fb3b3a441 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 06:40:16 +0000 Subject: style changes for operator scripts & some pep8 edits. --- release/scripts/startup/bl_operators/mesh.py | 8 +- release/scripts/startup/bl_operators/object.py | 125 +++++++++++++++------ .../scripts/startup/bl_operators/object_align.py | 104 +++++++++-------- .../bl_operators/object_randomize_transform.py | 89 ++++++++++----- release/scripts/startup/bl_operators/presets.py | 53 +++++++-- 5 files changed, 254 insertions(+), 125 deletions(-) diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index 03b0e469310..344b238709f 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy @@ -111,7 +111,8 @@ class MeshMirrorUV(bpy.types.Operator): #for i, v in enumerate(mesh.vertices): vmap = {} - for mirror_a, mirror_b in (mirror_gt, mirror_lt), (mirror_lt, mirror_gt): + for mirror_a, mirror_b in ((mirror_gt, mirror_lt), + (mirror_lt, mirror_gt)): for co, i in mirror_a.items(): nco = (-co[0], co[1], co[2]) j = mirror_b.get(nco) @@ -120,7 +121,8 @@ class MeshMirrorUV(bpy.types.Operator): active_uv_layer = mesh.uv_textures.active.data fuvs = [(uv.uv1, uv.uv2, uv.uv3, uv.uv4) for uv in active_uv_layer] - fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) for uv in fuvs] + fuvs_cpy = [(uv[0].copy(), uv[1].copy(), uv[2].copy(), uv[3].copy()) + for uv in fuvs] # as a list faces = mesh.faces[:] diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 0342a14a1b2..c8ed3f532fd 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -28,9 +28,22 @@ class SelectPattern(bpy.types.Operator): bl_label = "Select Pattern" bl_options = {'REGISTER', 'UNDO'} - pattern = StringProperty(name="Pattern", description="Name filter using '*' and '?' wildcard chars", maxlen=32, default="*") - case_sensitive = BoolProperty(name="Case Sensitive", description="Do a case sensitive compare", default=False) - extend = BoolProperty(name="Extend", description="Extend the existing selection", default=True) + pattern = StringProperty( + name="Pattern", + description="Name filter using '*' and '?' wildcard chars", + maxlen=32, + default="*", + ) + case_sensitive = BoolProperty( + name="Case Sensitive", + description="Do a case sensitive compare", + default=False, + ) + extend = BoolProperty( + name="Extend", + description="Extend the existing selection", + default=True, + ) def execute(self, context): @@ -39,7 +52,8 @@ class SelectPattern(bpy.types.Operator): if self.case_sensitive: pattern_match = fnmatch.fnmatchcase else: - pattern_match = lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper()) + pattern_match = (lambda a, b: + fnmatch.fnmatchcase(a.upper(), b.upper())) obj = context.object if obj and obj.mode == 'POSE': @@ -98,14 +112,19 @@ class SelectHierarchy(bpy.types.Operator): bl_label = "Select Hierarchy" bl_options = {'REGISTER', 'UNDO'} - direction = EnumProperty(items=( - ('PARENT', "Parent", ""), - ('CHILD', "Child", "")), - name="Direction", - description="Direction to select in the hierarchy", - default='PARENT') + direction = EnumProperty( + items=(('PARENT', "Parent", ""), + ('CHILD', "Child", ""), + ), + name="Direction", + description="Direction to select in the hierarchy", + default='PARENT') - extend = BoolProperty(name="Extend", description="Extend the existing selection", default=False) + extend = BoolProperty( + name="Extend", + description="Extend the existing selection", + default=False, + ) @classmethod def poll(cls, context): @@ -163,7 +182,12 @@ class SubdivisionSet(bpy.types.Operator): level = IntProperty(name="Level", default=1, min=-100, max=100, soft_min=-6, soft_max=6) - relative = BoolProperty(name="Relative", description="Apply the subsurf level as an offset relative to the current level", default=False) + relative = BoolProperty( + name="Relative", + description=("Apply the subsurf level as an offset " + "relative to the current level"), + default=False, + ) @classmethod def poll(cls, context): @@ -215,7 +239,8 @@ class SubdivisionSet(bpy.types.Operator): mod = obj.modifiers.new("Subsurf", 'SUBSURF') mod.levels = level except: - self.report({'WARNING'}, "Modifiers cannot be added to object: " + obj.name) + self.report({'WARNING'}, + "Modifiers cannot be added to object: " + obj.name) for obj in context.selected_editable_objects: set_object_subd(obj) @@ -224,23 +249,37 @@ class SubdivisionSet(bpy.types.Operator): class ShapeTransfer(bpy.types.Operator): - '''Copy another selected objects active shape to this one by applying the relative offsets''' + '''Copy another selected objects active shape to this one by ''' \ + '''applying the relative offsets''' bl_idname = "object.shape_key_transfer" bl_label = "Transfer Shape Key" bl_options = {'REGISTER', 'UNDO'} - mode = EnumProperty(items=( - ('OFFSET', "Offset", "Apply the relative positional offset"), - ('RELATIVE_FACE', "Relative Face", "Calculate the geometricly relative position (using faces)."), - ('RELATIVE_EDGE', "Relative Edge", "Calculate the geometricly relative position (using edges).")), - name="Transformation Mode", - description="Method to apply relative shape positions to the new shape", - default='OFFSET') - - use_clamp = BoolProperty(name="Clamp Offset", - description="Clamp the transformation to the distance each vertex moves in the original shape.", - default=False) + mode = EnumProperty( + items=(('OFFSET', + "Offset", + "Apply the relative positional offset", + ), + ('RELATIVE_FACE', + "Relative Face", + "Calculate relative position (using faces).", + ), + ('RELATIVE_EDGE', + "Relative Edge", + "Calculate relative position (using edges).", + ), + ), + name="Transformation Mode", + description="Relative shape positions to the new shape method", + default='OFFSET', + ) + use_clamp = BoolProperty( + name="Clamp Offset", + description=("Clamp the transformation to the distance each " + "vertex moves in the original shape."), + default=False, + ) def _main(self, ob_act, objects, mode='OFFSET', use_clamp=False): @@ -272,13 +311,16 @@ class ShapeTransfer(bpy.types.Operator): orig_shape_coords = me_cos(ob_act.active_shape_key.data) orig_normals = me_nos(me.vertices) - # orig_coords = me_cos(me.vertices) # the actual mverts location isnt as relyable as the base shape :S + # the actual mverts location isnt as relyable as the base shape :S + # orig_coords = me_cos(me.vertices) orig_coords = me_cos(me.shape_keys.key_blocks[0].data) for ob_other in objects: me_other = ob_other.data if len(me_other.vertices) != len(me.vertices): - self.report({'WARNING'}, "Skipping '%s', vertex count differs" % ob_other.name) + self.report({'WARNING'}, + ("Skipping '%s', " + "vertex count differs") % ob_other.name) continue target_normals = me_nos(me_other.vertices) @@ -395,7 +437,10 @@ class ShapeTransfer(bpy.types.Operator): if 1: # swap from/to, means we cant copy to many at once. if len(objects) != 1: - self.report({'ERROR'}, "Expected one other selected mesh object to copy from") + self.report({'ERROR'}, + ("Expected one other selected " + "mesh object to copy from")) + return {'CANCELLED'} ob_act, objects = objects[0], [ob_act] @@ -429,11 +474,14 @@ class JoinUVs(bpy.types.Operator): bpy.ops.object.mode_set(mode='OBJECT', toggle=False) if not mesh.uv_textures: - self.report({'WARNING'}, "Object: %s, Mesh: '%s' has no UVs\n" % (obj.name, mesh.name)) + self.report({'WARNING'}, + "Object: %s, Mesh: '%s' has no UVs" + % (obj.name, mesh.name)) else: len_faces = len(mesh.faces) - uv_array = array.array('f', [0.0] * 8) * len_faces # seems to be the fastest way to create an array + # seems to be the fastest way to create an array + uv_array = array.array('f', [0.0] * 8) * len_faces mesh.uv_textures.active.data.foreach_get("uv_raw", uv_array) objects = context.selected_editable_objects[:] @@ -454,7 +502,8 @@ class JoinUVs(bpy.types.Operator): else: uv_other = mesh_other.uv_textures.active if not uv_other: - uv_other = mesh_other.uv_textures.new() # should return the texture it adds + # should return the texture it adds + uv_other = mesh_other.uv_textures.new() # finally do the copy uv_other.data.foreach_set("uv_raw", uv_array) @@ -482,7 +531,11 @@ class MakeDupliFace(bpy.types.Operator): SCALE_FAC = 0.01 offset = 0.5 * SCALE_FAC - base_tri = Vector((-offset, -offset, 0.0)), Vector((offset, -offset, 0.0)), Vector((offset, offset, 0.0)), Vector((-offset, offset, 0.0)) + base_tri = (Vector((-offset, -offset, 0.0)), + Vector((+offset, -offset, 0.0)), + Vector((+offset, +offset, 0.0)), + Vector((-offset, +offset, 0.0)), + ) def matrix_to_quat(matrix): # scale = matrix.median_scale @@ -498,7 +551,10 @@ class MakeDupliFace(bpy.types.Operator): linked.setdefault(data, []).append(obj) for data, objects in linked.items(): - face_verts = [axis for obj in objects for v in matrix_to_quat(obj.matrix_world) for axis in v] + face_verts = [axis for obj in objects + for v in matrix_to_quat(obj.matrix_world) + for axis in v] + faces = list(range(len(face_verts) // 3)) mesh = bpy.data.meshes.new(data.name + "_dupli") @@ -535,7 +591,8 @@ class MakeDupliFace(bpy.types.Operator): class IsolateTypeRender(bpy.types.Operator): - '''Hide unselected render objects of same type as active by setting the hide render flag''' + '''Hide unselected render objects of same type as active ''' \ + '''by setting the hide render flag''' bl_idname = "object.isolate_type_render" bl_label = "Restrict Render Unselected" bl_options = {'REGISTER', 'UNDO'} diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 952a2328ca9..2a7ae0c993b 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -16,102 +16,107 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy from mathutils import Vector def GlobalBB_LQ(bb_world): - + # Initialize the variables with the 8th vertex - left, right, front, back, down, up =\ - bb_world[7][0],\ - bb_world[7][0],\ - bb_world[7][1],\ - bb_world[7][1],\ - bb_world[7][2],\ - bb_world[7][2] - + left, right, front, back, down, up = (bb_world[7][0], + bb_world[7][0], + bb_world[7][1], + bb_world[7][1], + bb_world[7][2], + bb_world[7][2], + ) + # Test against the other 7 verts for i in range (7): - + # X Range val = bb_world[i][0] if val < left: left = val - + if val > right: right = val - + # Y Range val = bb_world[i][1] if val < front: front = val - + if val > back: back = val - + # Z Range val = bb_world[i][2] if val < down: down = val - + if val > up: up = val - + return (Vector((left, front, up)), Vector((right, back, down))) def GlobalBB_HQ(obj): - + matrix_world = obj.matrix_world.copy() - + # Initialize the variables with the last vertex - + verts = obj.data.vertices - + val = verts[-1].co * matrix_world - - left, right, front, back, down, up =\ - val[0],\ - val[0],\ - val[1],\ - val[1],\ - val[2],\ - val[2] - + + left, right, front, back, down, up = (val[0], + val[0], + val[1], + val[1], + val[2], + val[2], + ) + # Test against all other verts for i in range (len(verts)-1): - + vco = verts[i].co * matrix_world - + # X Range val = vco[0] if val < left: left = val - + if val > right: right = val - + # Y Range val = vco[1] if val < front: front = val - + if val > back: back = val - + # Z Range val = vco[2] if val < down: down = val - + if val > up: up = val - - return (Vector((left, front, up)), Vector((right, back, down))) + return Vector((left, front, up)), Vector((right, back, down)) -def align_objects(align_x, align_y, align_z, align_mode, relative_to, bb_quality): + +def align_objects(align_x, + align_y, + align_z, + align_mode, + relative_to, + bb_quality): cursor = bpy.context.scene.cursor_location @@ -131,12 +136,12 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to, bb_quality return False for obj, bb_world in objs: - + if bb_quality: GBB = GlobalBB_HQ(obj) else: GBB = GlobalBB_LQ(bb_world) - + Left_Front_Up = GBB[0] Right_Back_Down = GBB[1] @@ -194,12 +199,12 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to, bb_quality for obj, bb_world in objs: bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] - + if bb_quality: GBB = GlobalBB_HQ(obj) else: GBB = GlobalBB_LQ(bb_world) - + Left_Front_Up = GBB[0] Right_Back_Down = GBB[1] @@ -339,7 +344,9 @@ class AlignObjects(bpy.types.Operator): bb_quality = BoolProperty( name="High Quality", - description="Enables high quality calculation of the bounding box for perfect results on complex shape meshes with rotation/scale (Slow)", + description=("Enables high quality calculation of the " + "bounding box for perfect results on complex " + "shape meshes with rotation/scale (Slow)"), default=True) align_mode = EnumProperty(items=( @@ -374,7 +381,12 @@ class AlignObjects(bpy.types.Operator): def execute(self, context): align_axis = self.align_axis - ret = align_objects('X' in align_axis, 'Y' in align_axis, 'Z' in align_axis, self.align_mode, self.relative_to, self.bb_quality) + ret = align_objects('X' in align_axis, + 'Y' in align_axis, + 'Z' in align_axis, + self.align_mode, + self.relative_to, + self.bb_quality) if not ret: self.report({'WARNING'}, "No objects with bound-box selected") diff --git a/release/scripts/startup/bl_operators/object_randomize_transform.py b/release/scripts/startup/bl_operators/object_randomize_transform.py index 9dc5086086f..b94c4f06cd3 100644 --- a/release/scripts/startup/bl_operators/object_randomize_transform.py +++ b/release/scripts/startup/bl_operators/object_randomize_transform.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy @@ -93,40 +93,69 @@ class RandomizeLocRotSize(bpy.types.Operator): bl_label = "Randomize Transform" bl_options = {'REGISTER', 'UNDO'} - random_seed = IntProperty(name="Random Seed", - description="Seed value for the random generator", - default=0, min=0, max=1000) - - use_delta = BoolProperty(name="Transform Delta", - description="Randomize delta transform values instead of regular transform", default=False) - - use_loc = BoolProperty(name="Randomize Location", - description="Randomize the location values", default=True) - - loc = FloatVectorProperty(name="Location", - description="Maximun distance the objects can spread over each axis", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='TRANSLATION') - - use_rot = BoolProperty(name="Randomize Rotation", - description="Randomize the rotation values", default=True) - - rot = FloatVectorProperty(name="Rotation", - description="Maximun rotation over each axis", - default=(0.0, 0.0, 0.0), min=-180.0, max=180.0, subtype='TRANSLATION') - - use_scale = BoolProperty(name="Randomize Scale", - description="Randomize the scale values", default=True) - - scale_even = BoolProperty(name="Scale Even", - description="Use the same scale value for all axis", default=False) + random_seed = IntProperty( + name="Random Seed", + description="Seed value for the random generator", + min=0, + max=1000, + default=0, + ) + use_delta = BoolProperty( + name="Transform Delta", + description=("Randomize delta transform values " + "instead of regular transform"), + default=False, + ) + use_loc = BoolProperty( + name="Randomize Location", + description="Randomize the location values", + default=True, + ) + loc = FloatVectorProperty( + name="Location", + description=("Maximun distance the objects " + "can spread over each axis"), + min=-100.0, + max=100.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) + use_rot = BoolProperty( + name="Randomize Rotation", + description="Randomize the rotation values", + default=True, + ) + rot = FloatVectorProperty( + name="Rotation", + description="Maximun rotation over each axis", + min=-180.0, + max=180.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) + use_scale = BoolProperty( + name="Randomize Scale", + description="Randomize the scale values", + default=True, + ) + scale_even = BoolProperty( + name="Scale Even", + description="Use the same scale value for all axis", + default=False, + ) '''scale_min = FloatProperty(name="Minimun Scale Factor", description="Lowest scale percentage possible", default=0.15, min=-1.0, max=1.0, precision=3)''' - scale = FloatVectorProperty(name="Scale", - description="Maximum scale randomization over each axis", - default=(0.0, 0.0, 0.0), min=-100.0, max=100.0, subtype='TRANSLATION') + scale = FloatVectorProperty( + name="Scale", + description="Maximum scale randomization over each axis", + min=-100.0, + max=100.0, + default=(0.0, 0.0, 0.0), + subtype='TRANSLATION', + ) def execute(self, context): from math import radians diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index f3c799c9ac2..fbcc327c3bd 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy @@ -30,8 +30,15 @@ class AddPresetBase(): # bl_label = "Add a Python Preset" bl_options = {'REGISTER'} # only because invoke_props_popup requires. - name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="") - remove_active = bpy.props.BoolProperty(default=False, options={'HIDDEN'}) + name = bpy.props.StringProperty( + name="Name", + description="Name of the preset, used to make the path name", + maxlen=64, + ) + remove_active = bpy.props.BoolProperty( + default=False, + options={'HIDDEN'}, + ) @staticmethod def as_filename(name): # could reuse for other presets @@ -54,7 +61,10 @@ class AddPresetBase(): filename = self.as_filename(name) - target_path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", self.preset_subdir), create=True) + target_path = os.path.join("presets", self.preset_subdir) + target_path = bpy.utils.user_resource('SCRIPTS', + target_path, + create=True) if not target_path: self.report({'WARNING'}, "Failed to create presets path") @@ -95,7 +105,9 @@ class AddPresetBase(): filepath = bpy.utils.preset_find(preset_active, self.preset_subdir) if not filepath: - filepath = bpy.utils.preset_find(preset_active, self.preset_subdir, display_name=True) + filepath = bpy.utils.preset_find(preset_active, + self.preset_subdir, + display_name=True) if not filepath: return {'CANCELLED'} @@ -133,8 +145,15 @@ class ExecutePreset(bpy.types.Operator): bl_idname = "script.execute_preset" bl_label = "Execute a Python Preset" - filepath = bpy.props.StringProperty(name="Path", description="Path of the Python file to execute", maxlen=512, default="") - menu_idname = bpy.props.StringProperty(name="Menu ID Name", description="ID name of the menu this was called from", default="") + filepath = bpy.props.StringProperty( + name="Path", + description="Path of the Python file to execute", + maxlen=512, + ) + menu_idname = bpy.props.StringProperty( + name="Menu ID Name", + description="ID name of the menu this was called from", + ) def execute(self, context): from os.path import basename @@ -182,7 +201,10 @@ class AddPresetSSS(AddPresetBase, bpy.types.Operator): preset_menu = "MATERIAL_MT_sss_presets" preset_defines = [ - "material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)" + ("material = " + "bpy.context.material.active_node_material " + "if bpy.context.material.active_node_material " + "else bpy.context.material") ] preset_values = [ @@ -306,7 +328,11 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): bl_label = "Operator Preset" preset_menu = "WM_MT_operator_presets" - operator = bpy.props.StringProperty(name="Operator", maxlen=64, options={'HIDDEN'}) + operator = bpy.props.StringProperty( + name="Operator", + maxlen=64, + options={'HIDDEN'}, + ) # XXX, not ideal preset_defines = [ @@ -322,12 +348,15 @@ class AddPresetOperator(AddPresetBase, bpy.types.Operator): properties_blacklist = bpy.types.Operator.bl_rna.properties.keys() prefix, suffix = self.operator.split("_OT_", 1) - operator_rna = getattr(getattr(bpy.ops, prefix.lower()), suffix).get_rna().bl_rna + op = getattr(getattr(bpy.ops, prefix.lower()), suffix) + operator_rna = op.get_rna().bl_rna + del op ret = [] for prop_id, prop in operator_rna.properties.items(): - if (not (prop.is_hidden or prop.is_skip_save)) and prop_id not in properties_blacklist: - ret.append("op.%s" % prop_id) + if not (prop.is_hidden or prop.is_skip_save): + if prop_id not in properties_blacklist: + ret.append("op.%s" % prop_id) return ret -- cgit v1.2.3 From 799714fbc9e3769f431fd8e53dcf6f725daa6bae Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 07:14:54 +0000 Subject: minor edits to animation playback operator - remove own copyright from script - print command before executing (helps troubleshooting) --- .../bl_operators/screen_play_rendered_anim.py | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index bab74962f31..4b3435eacbe 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -1,27 +1,23 @@ -# ***** BEGIN GPL LICENSE BLOCK ***** +# ##### BEGIN GPL LICENSE BLOCK ##### # -# Script copyright (C) Campbell J Barton +# 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 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. # -# 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. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# ***** END GPL LICENCE BLOCK ***** +# ##### END GPL LICENSE BLOCK ##### # -# History -# # Originally written by Matt Ebb import bpy @@ -100,7 +96,6 @@ class PlayRenderedAnim(bpy.types.Operator): while len(file_a) == len(file_b): frame_tmp = (frame_tmp * 10) + 9 - print(frame_tmp) file_b = rd.frame_path(frame=frame_tmp) file_b = rd.frame_path(frame=int(frame_tmp / 10)) @@ -118,7 +113,7 @@ class PlayRenderedAnim(bpy.types.Operator): opts = ["-a", "-f", str(rd.fps), str(rd.fps_base), file] cmd.extend(opts) elif preset == 'DJV': - opts = [file, "-playback_speed", str(rd.fps)] + opts = [file, "-playback_speed", "%d" % int(rd.fps / rd.fps_base)] cmd.extend(opts) elif preset == 'FRAMECYCLER': opts = [file, "%d-%d" % (scene.frame_start, scene.frame_end)] @@ -131,14 +126,19 @@ class PlayRenderedAnim(bpy.types.Operator): if is_movie: opts.append(file) else: - opts.append("mf://%s" % file.replace("#", "?")) - opts += ["-mf", "fps=%.4f" % (rd.fps / rd.fps_base)] + opts += [("mf://%s" % file.replace("#", "?")), + "-mf", + "fps=%.4f" % (rd.fps / rd.fps_base), + ] + opts += ["-loop", "0", "-really-quiet", "-fs"] cmd.extend(opts) else: # 'CUSTOM' cmd.append(file) # launch it + print("Executing command:\n %r" % " ".join(cmd)) + try: process = subprocess.Popen(cmd) except Exception as e: -- cgit v1.2.3 From e882925b49f57a9e8fe59c37a0eb00d2498a4e87 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 25 Jul 2011 09:31:39 +0000 Subject: more vector order switching. --- release/scripts/startup/bl_operators/object.py | 2 +- release/scripts/startup/bl_operators/object_align.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index c8ed3f532fd..0f0491e249e 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -542,7 +542,7 @@ class MakeDupliFace(bpy.types.Operator): trans = matrix.to_translation() rot = matrix.to_3x3() # also contains scale - return [(b * rot) + trans for b in base_tri] + return [(rot * b) + trans for b in base_tri] scene = bpy.context.scene linked = {} for obj in bpy.context.selected_objects: diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py index 2a7ae0c993b..8fe606399b4 100644 --- a/release/scripts/startup/bl_operators/object_align.py +++ b/release/scripts/startup/bl_operators/object_align.py @@ -69,7 +69,7 @@ def GlobalBB_HQ(obj): verts = obj.data.vertices - val = verts[-1].co * matrix_world + val = matrix_world * verts[-1].co left, right, front, back, down, up = (val[0], val[0], @@ -82,7 +82,7 @@ def GlobalBB_HQ(obj): # Test against all other verts for i in range (len(verts)-1): - vco = verts[i].co * matrix_world + vco = matrix_world * verts[i].co # X Range val = vco[0] @@ -128,8 +128,8 @@ def align_objects(align_x, objs = [] for obj in bpy.context.selected_objects: - matrix_world = obj.matrix_world - bb_world = [Vector(v[:]) * matrix_world for v in obj.bound_box] + matrix_world = obj.matrix_world.copy() + bb_world = [matrix_world * Vector(v[:]) for v in obj.bound_box] objs.append((obj, bb_world)) if not objs: @@ -198,7 +198,8 @@ def align_objects(align_x, # Main Loop for obj, bb_world in objs: - bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box] + matrix_world = obj.matrix_world.copy() + bb_world = [matrix_world * Vector(v[:]) for v in obj.bound_box] if bb_quality: GBB = GlobalBB_HQ(obj) -- cgit v1.2.3 From fee1594a650175babe009005c4d4f6ad5da20a03 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 25 Jul 2011 15:37:55 +0000 Subject: BGE BugFix for: [#23874] Custom projection matrix doesn't work in custom viewport This was never highly tested, that's why I never committed (my patch for this was from September 2010). But once again I got a report that this bug was a deal-break and the patch seems to work for this artist. I believe it's working, but I will keep my eyes open for this. --- source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index ea0b00e52fd..0aa36b4cd5f 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -1220,7 +1220,7 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) projmat.setValue(m_overrideCamProjMat.getPointer()); cam->SetProjectionMatrix(projmat); } - } else if (cam->hasValidProjectionMatrix() && !cam->GetViewport() ) + } else if (cam->hasValidProjectionMatrix()) { m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix()); } else -- cgit v1.2.3 From 62415cab0520c70b4af874def93897c42d17e3d1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 25 Jul 2011 15:44:41 +0000 Subject: Fix #28014: joystick sensor not working. Broke this with an earlier commit trying to fix blenderplayer startup warnings. It seems we do need to init the SDL video subsystem even if we only want events, thanks Juha Maki-Kanto for pointing this out. --- source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp index 0e08f157a6a..48ba09e67d2 100644 --- a/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp +++ b/source/gameengine/GameLogic/Joystick/SCA_Joystick.cpp @@ -89,7 +89,7 @@ SCA_Joystick *SCA_Joystick::GetInstance( short int joyindex ) { int i; // do this once only - if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) == -1 ){ + if(SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO) == -1 ){ echo("Error-Initializing-SDL: " << SDL_GetError()); return NULL; } @@ -124,7 +124,7 @@ void SCA_Joystick::ReleaseInstance() m_instance[i]= NULL; } - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_VIDEO); #endif } } -- 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(-) 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(+) 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 71692e802fc50ad9dd76659d2868843e708dbd40 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jul 2011 07:39:00 +0000 Subject: py api: - added menu templates - move template menu into the header of the text editor (so users will find more easily) - updated mathutils examples, switching the order of multiplication. --- doc/python_api/examples/mathutils.Vector.py | 13 +++--- release/scripts/startup/bl_ui/space_text.py | 43 ++++++++++++-------- release/scripts/templates/panel_simple.py | 33 --------------- release/scripts/templates/ui_menu.py | 49 +++++++++++++++++++++++ release/scripts/templates/ui_menu_simple.py | 26 ++++++++++++ release/scripts/templates/ui_panel_simple.py | 34 ++++++++++++++++ source/blenderplayer/bad_level_call_stubs/stubs.c | 1 - 7 files changed, 142 insertions(+), 57 deletions(-) delete mode 100644 release/scripts/templates/panel_simple.py create mode 100644 release/scripts/templates/ui_menu.py create mode 100644 release/scripts/templates/ui_menu_simple.py create mode 100644 release/scripts/templates/ui_panel_simple.py diff --git a/doc/python_api/examples/mathutils.Vector.py b/doc/python_api/examples/mathutils.Vector.py index 880b4ef2590..bf1fc70353f 100644 --- a/doc/python_api/examples/mathutils.Vector.py +++ b/doc/python_api/examples/mathutils.Vector.py @@ -1,15 +1,15 @@ import mathutils # zero length vector -vec = mathutils.Vector((0, 0, 1)) +vec = mathutils.Vector((0.0, 0.0, 1.0)) # unit length vector vec_a = vec.copy().normalize() -vec_b = mathutils.Vector((0, 1, 2)) +vec_b = mathutils.Vector((0.0, 1.0, 2.0)) -vec2d = mathutils.Vector((1, 2)) -vec3d = mathutils.Vector((1, 0, 0)) +vec2d = mathutils.Vector((1.0, 2.0)) +vec3d = mathutils.Vector((1.0, 0.0, 0.0)) vec4d = vec_a.to_4d() # other mathutuls types @@ -34,9 +34,9 @@ vec_a + vec_b vec_a - vec_b vec_a * vec_b vec_a * 10.0 -vec_a * matrix +matrix * vec_a +quat * vec_a vec_a * vec_b -vec_a * quat -vec_a @@ -44,6 +44,7 @@ vec_a * quat x = vec_a[0] len(vec) vec_a[:] = vec_b +vec_a[:] = 1.0, 2.0, 3.0 vec2d[:] = vec3d[:2] diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 0fc8d937f66..582c9442a4a 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy @@ -36,10 +36,13 @@ class TEXT_HT_header(bpy.types.Header): sub = row.row(align=True) sub.menu("TEXT_MT_view") sub.menu("TEXT_MT_text") + if text: sub.menu("TEXT_MT_edit") sub.menu("TEXT_MT_format") + sub.menu("TEXT_MT_templates") + if text and text.is_modified: row = layout.row() row.alert = True @@ -63,11 +66,13 @@ class TEXT_HT_header(bpy.types.Header): row = layout.row() if text.filepath: if text.is_dirty: - row.label(text="File: *%s (unsaved)" % text.filepath) + row.label(text="File: *%r (unsaved)" % text.filepath) else: - row.label(text="File: %s" % text.filepath) + row.label(text="File: %r" % text.filepath) else: - row.label(text="Text: External" if text.library else "Text: Internal") + row.label(text="Text: External" + if text.library + else "Text: Internal") class TEXT_PT_properties(bpy.types.Panel): @@ -150,8 +155,12 @@ class TEXT_MT_view(bpy.types.Menu): layout.separator() - layout.operator("text.move", text="Top of File").type = 'FILE_TOP' - layout.operator("text.move", text="Bottom of File").type = 'FILE_BOTTOM' + layout.operator("text.move", + text="Top of File", + ).type = 'FILE_TOP' + layout.operator("text.move", + text="Bottom of File", + ).type = 'FILE_BOTTOM' class TEXT_MT_text(bpy.types.Menu): @@ -185,19 +194,15 @@ class TEXT_MT_text(bpy.types.Menu): # XXX uiMenuItemO(head, 0, "text.refresh_pyconstraints"); #endif - layout.separator() - - layout.menu("TEXT_MT_templates") - class TEXT_MT_templates(bpy.types.Menu): - ''' - Creates the menu items by scanning scripts/templates - ''' - bl_label = "Script Templates" + bl_label = "Templates" def draw(self, context): - self.path_menu(bpy.utils.script_paths("templates"), "text.open", {"internal": True}) + self.path_menu(bpy.utils.script_paths("templates"), + "text.open", + {"internal": True}, + ) class TEXT_MT_edit_select(bpy.types.Menu): @@ -246,8 +251,12 @@ class TEXT_MT_edit_to3d(bpy.types.Menu): def draw(self, context): layout = self.layout - layout.operator("text.to_3d_object", text="One Object").split_lines = False - layout.operator("text.to_3d_object", text="One Object Per Line").split_lines = True + layout.operator("text.to_3d_object", + text="One Object", + ).split_lines = False + layout.operator("text.to_3d_object", + text="One Object Per Line", + ).split_lines = True class TEXT_MT_edit(bpy.types.Menu): diff --git a/release/scripts/templates/panel_simple.py b/release/scripts/templates/panel_simple.py deleted file mode 100644 index e5bf70cb654..00000000000 --- a/release/scripts/templates/panel_simple.py +++ /dev/null @@ -1,33 +0,0 @@ -import bpy - - -class OBJECT_PT_hello(bpy.types.Panel): - bl_label = "Hello World Panel" - bl_space_type = "PROPERTIES" - bl_region_type = "WINDOW" - bl_context = "object" - - def draw(self, context): - layout = self.layout - - obj = context.object - - row = layout.row() - row.label(text="Hello world!", icon='WORLD_DATA') - - row = layout.row() - row.label(text="Active object is: " + obj.name) - row = layout.row() - row.prop(obj, "name") - - -def register(): - bpy.utils.register_class(OBJECT_PT_hello) - - -def unregister(): - bpy.utils.unregister_class(OBJECT_PT_hello) - - -if __name__ == "__main__": - register() diff --git a/release/scripts/templates/ui_menu.py b/release/scripts/templates/ui_menu.py new file mode 100644 index 00000000000..aa6b172abd4 --- /dev/null +++ b/release/scripts/templates/ui_menu.py @@ -0,0 +1,49 @@ +import bpy + + +class CustomMenu(bpy.types.Menu): + bl_label = "Custom Menu" + bl_idname = "OBJECT_MT_custom_menu" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.open_mainfile") + layout.operator("wm.save_as_mainfile").copy = True + + layout.operator("object.shade_smooth") + + layout.label(text="Hello world!", icon='WORLD_DATA') + + # use an operator enum property to populate a submenu + layout.operator_menu_enum("object.select_by_type", + property="type", + text="Select All by Type...", + ) + + # call another menu + layout.operator("wm.call_menu", text="Unwrap").name = "VIEW3D_MT_uv_map" + + +def draw_item(self, context): + layout = self.layout + layout.menu(CustomMenu.bl_idname) + + +def register(): + bpy.utils.register_class(CustomMenu) + + # lets add ourselves to the file menu + bpy.types.INFO_HT_header.append(draw_item) + + +def unregister(): + bpy.utils.unregister_class(CustomMenu) + + bpy.types.INFO_HT_header.remove(draw_item) + +if __name__ == "__main__": + register() + + # The menu can also be called from scripts + bpy.ops.wm.call_menu(name=CustomMenu.bl_idname) diff --git a/release/scripts/templates/ui_menu_simple.py b/release/scripts/templates/ui_menu_simple.py new file mode 100644 index 00000000000..2129dfd81a4 --- /dev/null +++ b/release/scripts/templates/ui_menu_simple.py @@ -0,0 +1,26 @@ +import bpy + + +class SimpleCustomMenu(bpy.types.Menu): + bl_label = "Simple Custom Menu" + bl_idname = "OBJECT_MT_simple_custom_menu" + + def draw(self, context): + layout = self.layout + + layout.operator("wm.open_mainfile") + layout.operator("wm.save_as_mainfile") + + +def register(): + bpy.utils.register_class(SimpleCustomMenu) + + +def unregister(): + bpy.utils.unregister_class(SimpleCustomMenu) + +if __name__ == "__main__": + register() + + # The menu can also be called from scripts + bpy.ops.wm.call_menu(name=SimpleCustomMenu.bl_idname) diff --git a/release/scripts/templates/ui_panel_simple.py b/release/scripts/templates/ui_panel_simple.py new file mode 100644 index 00000000000..cde6126b626 --- /dev/null +++ b/release/scripts/templates/ui_panel_simple.py @@ -0,0 +1,34 @@ +import bpy + + +class HelloWorldPanel(bpy.types.Panel): + bl_label = "Hello World Panel" + bl_idname = "OBJECT_PT_hello" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + + def draw(self, context): + layout = self.layout + + obj = context.object + + row = layout.row() + row.label(text="Hello world!", icon='WORLD_DATA') + + row = layout.row() + row.label(text="Active object is: " + obj.name) + row = layout.row() + row.prop(obj, "name") + + +def register(): + bpy.utils.register_class(HelloWorldPanel) + + +def unregister(): + bpy.utils.unregister_class(HelloWorldPanel) + + +if __name__ == "__main__": + register() diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 7bf5fe9dde3..548d272ffd2 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -136,7 +136,6 @@ int RE_RenderInProgress(struct Render *re){return 0;} struct Scene *RE_GetScene(struct Render *re){return (struct Scene *) NULL;} void RE_Database_Free(struct Render *re){} void RE_FreeRender(struct Render *re){} -void RE_shade_external(struct Render *re, struct ShadeInput *shi, struct ShadeResult *shr){} void RE_DataBase_GetView(struct Render *re, float mat[][4]){} int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta){return 0;} float texture_value_blend(float tex, float out, float fact, float facg, int blendtype, int flip){return 0.0f;} -- 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'. --- release/scripts/templates/ui_menu.py | 2 +- source/blender/blenkernel/BKE_blender.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/templates/ui_menu.py b/release/scripts/templates/ui_menu.py index aa6b172abd4..d3923b5b083 100644 --- a/release/scripts/templates/ui_menu.py +++ b/release/scripts/templates/ui_menu.py @@ -33,7 +33,7 @@ def draw_item(self, context): def register(): bpy.utils.register_class(CustomMenu) - # lets add ourselves to the file menu + # lets add ourselves to the main header bpy.types.INFO_HT_header.append(draw_item) 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(-) 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(-) 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(-) 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(-) 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(-) 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(-) 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 9a250bea61340cb8b3625345df6560ba3e7b878f Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Tue, 26 Jul 2011 20:05:17 +0000 Subject: Fix part of [#28088] bad button spacing with layout engine for menu items. * Fixed a cut off text. * small cleanup --- release/scripts/startup/bl_ui/space_text.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 582c9442a4a..b787fc5cf75 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -33,22 +33,21 @@ class TEXT_HT_header(bpy.types.Header): row.template_header() if context.area.show_menus: - sub = row.row(align=True) - sub.menu("TEXT_MT_view") - sub.menu("TEXT_MT_text") + row.menu("TEXT_MT_view") + row.menu("TEXT_MT_text") if text: - sub.menu("TEXT_MT_edit") - sub.menu("TEXT_MT_format") + row.menu("TEXT_MT_edit") + row.menu("TEXT_MT_format") - sub.menu("TEXT_MT_templates") + row.menu("TEXT_MT_templates") if text and text.is_modified: - row = layout.row() - row.alert = True - row.operator("text.resolve_conflict", text="", icon='HELP') + sub = row.row() + sub.alert = True + sub.operator("text.resolve_conflict", text="", icon='HELP') - layout.template_ID(st, "text", new="text.new", unlink="text.unlink") + row.template_ID(st, "text", new="text.new", unlink="text.unlink") row = layout.row(align=True) row.prop(st, "show_line_numbers", text="") -- 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(-) 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(-) 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. --- release/scripts/startup/bl_ui/space_view3d.py | 17 ++++++++++------- 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 +++--- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 7d35ca9ddb8..acb0499c40f 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -79,19 +79,22 @@ class VIEW3D_HT_header(bpy.types.Header): row.prop(toolsettings, "proportional_edit_falloff", text="", icon_only=True) # Snap + snap_element = toolsettings.snap_element row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") row.prop(toolsettings, "snap_element", text="", icon_only=True) - if toolsettings.snap_element != 'INCREMENT': + if snap_element != 'INCREMENT': row.prop(toolsettings, "snap_target", text="") - if obj and obj.mode == 'OBJECT': - row.prop(toolsettings, "use_snap_align_rotation", text="") - if toolsettings.snap_element == 'VOLUME': + if obj: + if obj.mode == 'OBJECT': + row.prop(toolsettings, "use_snap_align_rotation", text="") + elif obj.mode == 'EDIT': + row.prop(toolsettings, "use_snap_self", text="") + + if snap_element == 'VOLUME': row.prop(toolsettings, "use_snap_peel_object", text="") - elif toolsettings.snap_element == 'FACE': + elif snap_element == 'FACE': row.prop(toolsettings, "use_snap_project", text="") - if toolsettings.use_snap_project and obj.mode == 'EDIT': - row.prop(toolsettings, "use_snap_project_self", text="") # OpenGL render row = layout.row(align=True) 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(-) 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(-) 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(-) 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(-) 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(-) 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 0facd795f8d3f7af32df6c7492a9a13afb6196ff Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 03:08:35 +0000 Subject: automatically update the redirect from http://www.blender.org/documentation/250PythonDoc/ when uploading docs --- doc/python_api/sphinx_doc_gen.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh index 5f23ca395b6..a3befe1b7cb 100755 --- a/doc/python_api/sphinx_doc_gen.sh +++ b/doc/python_api/sphinx_doc_gen.sh @@ -38,8 +38,11 @@ cp $SPHINXBASE/sphinx-out/contents.html $SPHINXBASE/sphinx-out/index.html ssh $SSH_USER@emo.blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*' rsync --progress -avze "ssh -p 22" $SPHINXBASE/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/ -# symlink the dir to a static URL -ssh $SSH_USER@emo.blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc' +## symlink the dir to a static URL +#ssh $SSH_USER@emo.blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc' + +# better redirect +ssh $SSH_USER@emo.blender.org 'echo "Redirecting...Redirecting..." > '$SSH_UPLOAD'/250PythonDoc/index.html' # pdf sphinx-build -b latex $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out -- 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(-) 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 e2522cead2271522c71a14ce45cae407a32606ec Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 05:09:31 +0000 Subject: report an error when user blender versions other then 2.4x for animation playback. --- .../bl_operators/screen_play_rendered_anim.py | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 4b3435eacbe..a38d817d738 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -110,6 +110,31 @@ class PlayRenderedAnim(bpy.types.Operator): cmd = [player_path] # extra options, fps controls etc. if preset == 'BLENDER24': + # ----------------------------------------------------------------- + # Check blender is not 2.5x until it supports playback again + try: + process = subprocess.Popen([player_path, '--version'], + stdout=subprocess.PIPE, + ) + except: + # ignore and allow the main execution to catch the problem. + process = None + + if process is not None: + process.wait() + out = process.stdout.read() + process.stdout.close() + out_split = out.strip().split() + if out_split[0] == b'Blender': + if not out_split[1].startswith(b'2.4'): + self.report({'ERROR'}, + "Blender %s doesn't support playback: %r" % + (out_split[1].decode(), player_path)) + return {'CANCELLED'} + del out, out_split + del process + # ----------------------------------------------------------------- + opts = ["-a", "-f", str(rd.fps), str(rd.fps_base), file] cmd.extend(opts) elif preset == 'DJV': @@ -146,5 +171,6 @@ class PlayRenderedAnim(bpy.types.Operator): self.report({'ERROR'}, "Couldn't run external animation player with command " "%r\n%s" % (" ".join(cmd), str(e))) + return {'CANCELLED'} return {'FINISHED'} -- cgit v1.2.3 From b71ccf3e06c3eb809ce548663a963df50468bed9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 07:10:39 +0000 Subject: fix error in writing dupligroups for X3D export, may have effected other exporters too. --- release/scripts/modules/bpy_extras/io_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index 9545e20b025..bd01897c639 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -203,7 +203,7 @@ def axis_conversion_ensure(operator, forward_attr, up_attr): # return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects() def create_derived_objects(scene, ob): - if ob.parent and ob.parent.dupli_type != 'NONE': + if ob.parent and ob.parent.dupli_type in {'VERTS', 'FACES'}: return False, None if ob.dupli_type != 'NONE': -- cgit v1.2.3 From 722474a7eadd3d7c384419756ce58307060d71be Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 28 Jul 2011 07:55:09 +0000 Subject: fix [#28095] Select Pattern don't select all the bone in edit mode & some style changes. --- release/scripts/startup/bl_operators/object.py | 105 +++++++++++++++++++------ 1 file changed, 82 insertions(+), 23 deletions(-) diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index 0f0491e249e..627a1530fe1 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -# +# import bpy from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty @@ -54,21 +54,35 @@ class SelectPattern(bpy.types.Operator): else: pattern_match = (lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper())) - + is_ebone = False obj = context.object if obj and obj.mode == 'POSE': items = obj.data.bones + if not self.extend: + bpy.ops.pose.select_all(action='DESELECT') elif obj and obj.type == 'ARMATURE' and obj.mode == 'EDIT': items = obj.data.edit_bones + if not self.extend: + bpy.ops.armature.select_all(action='DESELECT') + is_ebone = True else: items = context.visible_objects + if not self.extend: + bpy.ops.object.select_all(action='DESELECT') # Can be pose bones or objects for item in items: if pattern_match(item.name, self.pattern): item.select = True - elif not self.extend: - item.select = False + + # hrmf, perhaps there should be a utility function for this. + if is_ebone: + item.select_head = True + item.select_tail = True + if item.use_connect: + item_parent = item.parent + if item_parent is not None: + item_parent.select_tail = True return {'FINISHED'} @@ -107,7 +121,8 @@ class SelectCamera(bpy.types.Operator): class SelectHierarchy(bpy.types.Operator): - '''Select object relative to the active objects position in the hierarchy''' + '''Select object relative to the active objects position''' \ + '''in the hierarchy''' bl_idname = "object.select_hierarchy" bl_label = "Select Hierarchy" bl_options = {'REGISTER', 'UNDO'} @@ -332,53 +347,90 @@ class ShapeTransfer(bpy.types.Operator): ob_add_shape(ob_other, orig_key_name) # editing the final coords, only list that stores wrapped coords - target_shape_coords = [v.co for v in ob_other.active_shape_key.data] + target_shape_coords = [v.co for v in + ob_other.active_shape_key.data] median_coords = [[] for i in range(len(me.vertices))] # Method 1, edge if mode == 'OFFSET': for i, vert_cos in enumerate(median_coords): - vert_cos.append(target_coords[i] + (orig_shape_coords[i] - orig_coords[i])) + vert_cos.append(target_coords[i] + + (orig_shape_coords[i] - orig_coords[i])) elif mode == 'RELATIVE_FACE': for face in me.faces: i1, i2, i3, i4 = face.vertices_raw if i4 != 0: pt = barycentric_transform(orig_shape_coords[i1], - orig_coords[i4], orig_coords[i1], orig_coords[i2], - target_coords[i4], target_coords[i1], target_coords[i2]) + orig_coords[i4], + orig_coords[i1], + orig_coords[i2], + target_coords[i4], + target_coords[i1], + target_coords[i2], + ) median_coords[i1].append(pt) pt = barycentric_transform(orig_shape_coords[i2], - orig_coords[i1], orig_coords[i2], orig_coords[i3], - target_coords[i1], target_coords[i2], target_coords[i3]) + orig_coords[i1], + orig_coords[i2], + orig_coords[i3], + target_coords[i1], + target_coords[i2], + target_coords[i3], + ) median_coords[i2].append(pt) pt = barycentric_transform(orig_shape_coords[i3], - orig_coords[i2], orig_coords[i3], orig_coords[i4], - target_coords[i2], target_coords[i3], target_coords[i4]) + orig_coords[i2], + orig_coords[i3], + orig_coords[i4], + target_coords[i2], + target_coords[i3], + target_coords[i4], + ) median_coords[i3].append(pt) pt = barycentric_transform(orig_shape_coords[i4], - orig_coords[i3], orig_coords[i4], orig_coords[i1], - target_coords[i3], target_coords[i4], target_coords[i1]) + orig_coords[i3], + orig_coords[i4], + orig_coords[i1], + target_coords[i3], + target_coords[i4], + target_coords[i1], + ) median_coords[i4].append(pt) else: pt = barycentric_transform(orig_shape_coords[i1], - orig_coords[i3], orig_coords[i1], orig_coords[i2], - target_coords[i3], target_coords[i1], target_coords[i2]) + orig_coords[i3], + orig_coords[i1], + orig_coords[i2], + target_coords[i3], + target_coords[i1], + target_coords[i2], + ) median_coords[i1].append(pt) pt = barycentric_transform(orig_shape_coords[i2], - orig_coords[i1], orig_coords[i2], orig_coords[i3], - target_coords[i1], target_coords[i2], target_coords[i3]) + orig_coords[i1], + orig_coords[i2], + orig_coords[i3], + target_coords[i1], + target_coords[i2], + target_coords[i3], + ) median_coords[i2].append(pt) pt = barycentric_transform(orig_shape_coords[i3], - orig_coords[i2], orig_coords[i3], orig_coords[i1], - target_coords[i2], target_coords[i3], target_coords[i1]) + orig_coords[i2], + orig_coords[i3], + orig_coords[i1], + target_coords[i2], + target_coords[i3], + target_coords[i1], + ) median_coords[i3].append(pt) elif mode == 'RELATIVE_EDGE': @@ -416,7 +468,8 @@ class ShapeTransfer(bpy.types.Operator): if use_clamp: # clamp to the same movement as the original # breaks copy between different scaled meshes. - len_from = (orig_shape_coords[i] - orig_coords[i]).length + len_from = (orig_shape_coords[i] - + orig_coords[i]).length ofs = co - target_coords[i] ofs.length = len_from co = target_coords[i] + ofs @@ -498,7 +551,13 @@ class JoinUVs(bpy.types.Operator): mesh_other.tag = True if len(mesh_other.faces) != len_faces: - self.report({'WARNING'}, "Object: %s, Mesh: '%s' has %d faces, expected %d\n" % (obj_other.name, mesh_other.name, len(mesh_other.faces), len_faces)) + self.report({'WARNING'}, "Object: %s, Mesh: " + "'%s' has %d faces, expected %d\n" + % (obj_other.name, + mesh_other.name, + len(mesh_other.faces), + len_faces), + ) else: uv_other = mesh_other.uv_textures.active if not uv_other: -- 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. --- .../scripts/startup/bl_ui/properties_data_modifier.py | 1 + source/blender/blenkernel/intern/multires.c | 18 ++++++++++-------- source/blender/makesdna/DNA_modifier_types.h | 1 + source/blender/makesrna/intern/rna_modifier.c | 5 +++++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index ce6d0990f05..0a4d0b60514 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -394,6 +394,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel): col.operator("object.multires_higher_levels_delete", text="Delete Higher") col.operator("object.multires_reshape", text="Reshape") col.operator("object.multires_base_apply", text="Apply Base") + col.prop(md, "use_subsurf_uv") col.prop(md, "show_only_control_edges") layout.separator() 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(-) 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