[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [20043] trunk/blender/source: [#18678] Swizzle properties for Mathutils.Vector

Campbell Barton ideasman42 at gmail.com
Sun May 3 19:52:03 CEST 2009


Revision: 20043
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=20043
Author:   campbellbarton
Date:     2009-05-03 19:52:03 +0200 (Sun, 03 May 2009)

Log Message:
-----------
[#18678] Swizzle properties for Mathutils.Vector
patch from Alex Fraser (z0r)

eg.
  - vec.xyz = vec.zyx
  - vec.xy = vec.zw
  - vec.xxy = vec.wzz
  - vec.yzyz = vec.yxyx

See http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)

made some minor modifications to this patch.

tested access times and adding 336 attributes to vectors doesn't make a noticeable differences to speed of existing axis attributes (x,y,z,w) - thanks to python dict lookups.

Modified Paths:
--------------
    trunk/blender/source/blender/python/BPY_interface.c
    trunk/blender/source/blender/python/api2_2x/Mathutils.c
    trunk/blender/source/blender/python/api2_2x/Mathutils.h
    trunk/blender/source/blender/python/api2_2x/doc/Mathutils.py
    trunk/blender/source/blender/python/api2_2x/vector.c
    trunk/blender/source/blender/python/api2_2x/vector.h
    trunk/blender/source/gameengine/Ketsji/KX_PythonInit.cpp

Modified: trunk/blender/source/blender/python/BPY_interface.c
===================================================================
--- trunk/blender/source/blender/python/BPY_interface.c	2009-05-03 17:48:32 UTC (rev 20042)
+++ trunk/blender/source/blender/python/BPY_interface.c	2009-05-03 17:52:03 UTC (rev 20043)
@@ -286,6 +286,8 @@
 		free_libblock( &G.main->script, script );
 	}
 
+	Mathutils_Free(NULL);
+	
 	Py_Finalize(  );
 
 	BPyMenu_RemoveAllEntries(  );	/* freeing bpymenu mem */

Modified: trunk/blender/source/blender/python/api2_2x/Mathutils.c
===================================================================
--- trunk/blender/source/blender/python/api2_2x/Mathutils.c	2009-05-03 17:48:32 UTC (rev 20042)
+++ trunk/blender/source/blender/python/api2_2x/Mathutils.c	2009-05-03 17:52:03 UTC (rev 20043)
@@ -107,6 +107,11 @@
 /*----------------------------MODULE INIT-------------------------*/
 /* from can be Blender.Mathutils or GameLogic.Mathutils for the BGE */
 
+void Mathutils_Free(void * closure)
+{
+	Vector_Free();
+}
+
 #if (PY_VERSION_HEX >= 0x03000000)
 static struct PyModuleDef M_Mathutils_module_def = {
 	{}, /* m_base */
@@ -117,7 +122,7 @@
 	0,  /* m_reload */
 	0,  /* m_traverse */
 	0,  /* m_clear */
-	0,  /* m_free */
+	Mathutils_Free,  /* m_free */
 };
 #endif
 
@@ -126,10 +131,13 @@
 	PyObject *submodule;
 
 	//seed the generator for the rand function
-	BLI_srand((unsigned int) (PIL_check_seconds_timer() *
-				      0x7FFFFFFF));
+	BLI_srand((unsigned int) (PIL_check_seconds_timer() * 0x7FFFFFFF));
 	
 	/* needed for getseters */
+	if(!(vector_Type.tp_flags & Py_TPFLAGS_READY))
+		if (Vector_Init() != 0) /* setup dynamic getset array */
+			return NULL;
+		
 	if( PyType_Ready( &vector_Type ) < 0 )
 		return NULL;
 	if( PyType_Ready( &matrix_Type ) < 0 )
@@ -147,6 +155,7 @@
 	
 	return (submodule);
 }
+
 //-----------------------------METHODS----------------------------
 //----------------column_vector_multiplication (internal)---------
 //COLUMN VECTOR Multiplication (Matrix X Vector)

Modified: trunk/blender/source/blender/python/api2_2x/Mathutils.h
===================================================================
--- trunk/blender/source/blender/python/api2_2x/Mathutils.h	2009-05-03 17:48:32 UTC (rev 20042)
+++ trunk/blender/source/blender/python/api2_2x/Mathutils.h	2009-05-03 17:52:03 UTC (rev 20043)
@@ -38,6 +38,8 @@
 #include "euler.h"
 
 PyObject *Mathutils_Init( const char * from );
+void	  Mathutils_Free(void *);
+
 PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat);
 PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec);
 PyObject *quat_rotation(PyObject *arg1, PyObject *arg2);

Modified: trunk/blender/source/blender/python/api2_2x/doc/Mathutils.py
===================================================================
--- trunk/blender/source/blender/python/api2_2x/doc/Mathutils.py	2009-05-03 17:48:32 UTC (rev 20042)
+++ trunk/blender/source/blender/python/api2_2x/doc/Mathutils.py	2009-05-03 17:52:03 UTC (rev 20043)
@@ -400,6 +400,7 @@
   The Vector object
   =================
     This object gives access to Vectors in Blender.
+  @group Axises: x, y, z, w
   @ivar x: The x value.
   @ivar y: The y value.
   @ivar z: The z value (if any).
@@ -420,6 +421,16 @@
       - -vec
   @note: You can access a vector object like a sequence
       - x = vector[0]
+      - vec_a[:] vec_b
+      - vec2d[:] vec3d[:2]
+  @note: Vectors support 'swizzle' operations
+      - vec.xyz = vec.zyx
+      - vec.xy = vec.zw
+      - vec.xxy = vec.wzz
+      - vec.yzyz = vec.yxyx
+
+      See U{http://en.wikipedia.org/wiki/Swizzling_(computer_graphics)}
+  
   @attention: Vector data can be wrapped or non-wrapped. When a object is wrapped it
   means that the object will give you direct access to the data inside of blender. Modification
   of this object will directly change the data inside of blender. To copy a wrapped object
@@ -535,6 +546,7 @@
   The Euler object
   ================
     This object gives access to Eulers in Blender.
+  @group Axises: x, y, z, w
   @ivar x: The heading value in degrees.
   @ivar y: The pitch value in degrees.
   @ivar z: The roll value in degrees.
@@ -596,7 +608,7 @@
     """
     Return a matrix representation of the euler.
     @rtype: Matrix object
-    @return: A roation matrix representation of the euler.
+    @return: A 3x3 roation matrix representation of the euler.
     """
 
   def toQuat():
@@ -611,6 +623,7 @@
   The Quaternion object
   =====================
     This object gives access to Quaternions in Blender.
+  @group Axises: x, y, z, w
   @ivar w: The w value.
   @ivar x: The x value.
   @ivar y: The y value.
@@ -716,7 +729,7 @@
     """
     Return a matrix representation of the quaternion.
     @rtype: Matrix object
-    @return: A rotation matrix representation of the quaternion.
+    @return: A 3x3 rotation matrix representation of the quaternion.
     """
 
 class Matrix:

Modified: trunk/blender/source/blender/python/api2_2x/vector.c
===================================================================
--- trunk/blender/source/blender/python/api2_2x/vector.c	2009-05-03 17:48:32 UTC (rev 20042)
+++ trunk/blender/source/blender/python/api2_2x/vector.c	2009-05-03 17:52:03 UTC (rev 20043)
@@ -20,7 +20,7 @@
  * All rights reserved.
  *
  * 
- * Contributor(s): Willian P. Germano & Joseph Gilbert, Ken Hughes
+ * Contributor(s): Willian P. Germano, Joseph Gilbert, Ken Hughes, Alex Fraser, Campbell Barton
  *
  * ***** END GPL LICENSE BLOCK *****
  */
@@ -31,7 +31,25 @@
 #include "BKE_utildefines.h"
 #include "BLI_arithb.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
 
+
+/* An array of getseters, some of which have members on the stack and some on
+   the heap.
+
+   Vector_dyn_getseters: The getseter structures. Terminated with a NULL sentinel.
+   Vector_dyn_names:     All the names of the getseters that were allocated on the heap.
+              Each name is terminated with a null character, but there is
+              currently no way to find the length of this array. */
+PyGetSetDef*	Vector_dyn_getseters = NULL; 
+char*			Vector_dyn_names = NULL;
+
 /*-------------------------DOC STRINGS ---------------------------*/
 char Vector_Zero_doc[] = "() - set all values in the vector to 0";
 char Vector_Normalize_doc[] = "() - normalize the vector";
@@ -42,6 +60,7 @@
 char Vector_ToTrackQuat_doc[] = "(track, up) - extract a quaternion from the vector and the track and up axis";
 char Vector_reflect_doc[] = "(mirror) - return a vector reflected on the mirror normal";
 char Vector_copy_doc[] = "() - return a copy of the vector";
+char Vector_swizzle_doc[] = "Swizzle: Get or set axes in specified order";
 /*-----------------------METHOD DEFINITIONS ----------------------*/
 struct PyMethodDef Vector_methods[] = {
 	{"zero", (PyCFunction) Vector_Zero, METH_NOARGS, Vector_Zero_doc},
@@ -1121,8 +1140,288 @@
 	{NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
 };
 
+/* 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 axisA;
+	size_t axisB;
+	float vec[MAX_DIMENSIONS];
+	unsigned int swizzleClosure;
+	
+	/* Unpack the axes from the closure into an array. */
+	axisA = 0;
+	swizzleClosure = (unsigned int) closure;
+	while (swizzleClosure & SWIZZLE_VALID_AXIS)
+	{
+		axisB = swizzleClosure & SWIZZLE_AXIS;
+		vec[axisA] = self->vec[axisB];
+		swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
+		axisA++;
+	}
+	
+	return newVectorObject(vec, axisA, Py_NEW);
+}
 
+/* 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 occurrance 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)
+{
+	VectorObject *vecVal;
+	PyObject *item;
+	size_t listLen;
+	float scalarVal;
+
+	size_t axisB;
+	size_t axisA;
+	unsigned int swizzleClosure;
+	
+	float vecTemp[MAX_DIMENSIONS];
+	
+	/* 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 = (unsigned int) closure;
+	while (swizzleClosure & SWIZZLE_VALID_AXIS)
+	{
+		axisA = swizzleClosure & SWIZZLE_AXIS;
+		if (axisA >= self->size)
+		{
+			PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n");
+			return -1;
+		}
+		swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
+	}
+	
+	if (VectorObject_Check(value))
+	{
+		/* Copy vector contents onto swizzled axes. */
+		vecVal = (VectorObject*) value;
+		axisB = 0;
+		swizzleClosure = (unsigned int) closure;
+		while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < vecVal->size)
+		{
+			axisA = swizzleClosure & SWIZZLE_AXIS;
+			vecTemp[axisA] = vecVal->vec[axisB];
+			
+			swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
+			axisB++;
+		}
+		memcpy(self->vec, vecTemp, axisB * sizeof(float));
+		return 0;
+	}
+	else if (PyList_Check(value))
+	{
+		/* Copy list contents onto swizzled axes. */
+		listLen = PyList_Size(value);
+		swizzleClosure = (unsigned int) closure;
+		axisB = 0;
+		while (swizzleClosure & SWIZZLE_VALID_AXIS && axisB < listLen)
+		{
+			item = PyList_GetItem(value, axisB);
+			if (!PyNumber_Check(item))
+			{
+				PyErr_SetString(PyExc_AttributeError, "Error: vector does not have specified axis.\n");
+				return -1;
+			}
+			scalarVal = (float)PyFloat_AsDouble(item);
+			
+			axisA = swizzleClosure & SWIZZLE_AXIS;
+			vecTemp[axisA] = scalarVal;
+			
+			swizzleClosure = swizzleClosure >> SWIZZLE_BITS_PER_AXIS;
+			axisB++;
+		}

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list