[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [11653] trunk/blender: == PyConstraints ==

Joshua Leung aligorith at gmail.com
Sat Aug 18 08:17:50 CEST 2007


Revision: 11653
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=11653
Author:   aligorith
Date:     2007-08-18 08:17:50 +0200 (Sat, 18 Aug 2007)

Log Message:
-----------
== PyConstraints ==

I've added the ability for PyConstraints to define a function (doDriver) that is able to directly modify values of the owner/target, so that certain setups can be created reliably. Users should take note that this is against the basic concept of what a constraint does, and that under no circumstances may they set the values of any variables controlling the transforms. For more details, check out the information in the PyConstraint template script.

I've also updated PyConstraints to be aware of geometry targets. The script template has been updated with this information.

Modified Paths:
--------------
    trunk/blender/release/scripts/scripttemplate_pyconstraint.py
    trunk/blender/source/blender/blenkernel/bad_level_call_stubs/stubs.c
    trunk/blender/source/blender/blenkernel/intern/constraint.c
    trunk/blender/source/blender/python/BPY_extern.h
    trunk/blender/source/blender/python/BPY_interface.c

Modified: trunk/blender/release/scripts/scripttemplate_pyconstraint.py
===================================================================
--- trunk/blender/release/scripts/scripttemplate_pyconstraint.py	2007-08-18 05:09:33 UTC (rev 11652)
+++ trunk/blender/release/scripts/scripttemplate_pyconstraint.py	2007-08-18 06:17:50 UTC (rev 11653)
@@ -16,8 +16,8 @@
 PyConstraints are text buffers that start with #BPYCONSTRAINT.
 
 They must define a doConstraint function.  The doConstraint 
-function is called with the world-space matrix of the parent object/posebone
-as the first argument, the world-space matrix of the target object/posebone as
+function is called with the matrix of the parent object/posebone
+as the first argument, the matrix of the target object/posebone as
 the second, and an ID property that's attached to the current constraint
 instance.  The function then must return a 4x4 Mathutils.Matrix() object.
 
@@ -30,6 +30,13 @@
 below must be present. Also, if any special matrix creation needs to be performed
 for the target, a doTarget function must also be defined.
 
+Optionally, a doDriver function may be defined. This function is used
+to get and/or modify settings of the owner and target, and as such, should
+be used with caution. Under no circumstances, should you modify the transforms
+of either the owner or the target in this function, as they will either have 
+no effect, or will result in other things not being updated correctly. Therefore,
+it should be used sparringly.
+
 <------- End removable description section -----------> """
 
 # Add a licence here if you wish to re-distribute, we recommend the GPL
@@ -64,12 +71,37 @@
 
 # this optional function performs special actions that only require
 # access to the target data - calculation of special information
+#	targetobject: (Object) wrapped data referring to the target object
+#	subtarget: (String/PoseChannel) 
+#			- If the target is a PoseChannel in an armature, then this
+#			  is a wrapped copy of that PoseChannel.
+#			- Otherwise, this field will either be an empty string or the
+#			  name of the vertex group
+#	targetmatrix: (Matrix) matrix that will be used as the target matrix
+#	idprop: (IDProperties) wrapped data referring to this 
+#			constraint instance's idproperties
 """	
 def doTarget (targetobject, subtarget, targetmatix, idproperty):
 	# return a 4x4 matrix (which acts as the matrix of the target)
 	return targetmatrix;
 """
 
+# This optional function is used to modify/get values on the owner and the
+# target for creating certain setups. It should be used sparingly
+#	ownerobject: (Object) wrapped data referring to the owning object
+#	subowner: (PoseChannel) wrapped data referring to the PoseChannel that
+#			owns the constraint (where applicable)
+#	target: (Object) wrapped data referring to the target
+#	subtarget: (String/PoseChannel) 
+#			- If the target is a PoseChannel in an armature, then this
+#			  is a wrapped copy of that PoseChannel.
+#			- Otherwise, this field will either be an empty string or the
+#			  name of the vertex group
+"""
+def doDriver (ownerobject, subowner, targetobject, subtarget, idproperty):
+	pass;
+"""
+
 '''
 
 new_text = bpy.data.texts.new('pyconstraint_template.py')

Modified: trunk/blender/source/blender/blenkernel/bad_level_call_stubs/stubs.c
===================================================================
--- trunk/blender/source/blender/blenkernel/bad_level_call_stubs/stubs.c	2007-08-18 05:09:33 UTC (rev 11652)
+++ trunk/blender/source/blender/blenkernel/bad_level_call_stubs/stubs.c	2007-08-18 06:17:50 UTC (rev 11653)
@@ -125,10 +125,13 @@
 	return 0;
 }
 
-/* constraint.c */
+/* PyConstraints - BPY_interface.c */
 void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4])
 {
 }
+void BPY_pyconstraint_driver(struct bPythonConstraint *con, struct bConstraintOb *cob, struct Object *target, char subtarget[])
+{
+}
 int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4])
 {
 	return 0;

Modified: trunk/blender/source/blender/blenkernel/intern/constraint.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/constraint.c	2007-08-18 05:09:33 UTC (rev 11652)
+++ trunk/blender/source/blender/blenkernel/intern/constraint.c	2007-08-18 06:17:50 UTC (rev 11653)
@@ -2815,16 +2815,29 @@
 		/* value should have been set from IPO's/Constraint Channels already */
 		enf = con->enforce;
 		
-		/* move owner into right space */
+		/* move owner matrix into right space */
 		constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace);
+		Mat4CpyMat4(oldmat, cob->matrix);
 		
-		/* Get the target matrix - in right space to be used */
+		/* get the target matrix - in right space to be used */
 		ownerdata= ((cob->pchan)? (void *)cob->pchan : (void *)cob->ob);
 		get_constraint_target_matrix(con, cob->type, ownerdata, tarmat, ctime);
 		
-		Mat4CpyMat4(oldmat, cob->matrix);
 		
-		/* solve the constraint */
+		/* Special Hack for PyConstraints to be able to set settings on the owner and/or
+		 * target. Technically, this violates the design of constraints (as constraints should
+		 * only act on matrices to alter the final transform of an owner), but on the other
+		 * hand, this makes PyConstraints more powerful as it enables certain setups to be created
+		 * and work reliably. 
+		 */
+		if (con->type == CONSTRAINT_TYPE_PYTHON) {
+			bPythonConstraint *pycon= (bPythonConstraint *)con->data;
+			
+			/* as usual, the function for this is defined in BPY_interface.c  */
+			BPY_pyconstraint_driver(pycon, cob, pycon->tar, pycon->subtarget);
+		}
+		
+		/* Solve the constraint */
 		evaluate_constraint(con, cob->matrix, tarmat);
 		
 		/* Interpolate the enforcement, to blend result of constraint into final owner transform */

Modified: trunk/blender/source/blender/python/BPY_extern.h
===================================================================
--- trunk/blender/source/blender/python/BPY_extern.h	2007-08-18 05:09:33 UTC (rev 11652)
+++ trunk/blender/source/blender/python/BPY_extern.h	2007-08-18 06:17:50 UTC (rev 11653)
@@ -47,6 +47,7 @@
 struct ScrArea; /* DNA_screen_types.h */
 struct bScreen; /* DNA_screen_types.h */
 struct bPythonConstraint; /* DNA_constraint_types.h */
+struct bConstraintOb; /* BKE_constraint.h */
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -71,6 +72,7 @@
 	void BPy_Free_DrawButtonsList(void);
 	
 	void BPY_pyconstraint_eval(struct bPythonConstraint *con, float ownermat[][4], float targetmat[][4]);
+	void BPY_pyconstraint_driver(struct bPythonConstraint *con, struct bConstraintOb *cob, struct Object *target, char subtarget[]);
 	void BPY_pyconstraint_settings(void *arg1, void *arg2);
 	int BPY_pyconstraint_targets(struct bPythonConstraint *con, float targetmat[][4]);
 	int BPY_is_pyconstraint(struct Text *text);

Modified: trunk/blender/source/blender/python/BPY_interface.c
===================================================================
--- trunk/blender/source/blender/python/BPY_interface.c	2007-08-18 05:09:33 UTC (rev 11652)
+++ trunk/blender/source/blender/python/BPY_interface.c	2007-08-18 06:17:50 UTC (rev 11653)
@@ -44,6 +44,7 @@
 #include "BKE_library.h"
 #include "BKE_object.h"		/* during_scriptlink() */
 #include "BKE_text.h"
+#include "BKE_constraint.h" /* for bConstraintOb */
 
 #include "DNA_curve_types.h" /* for struct IpoDriver */
 #include "DNA_ID.h" /* ipo driver */
@@ -1163,7 +1164,9 @@
 	return 0;
 }
 
-/* This evals py constraints. It is passed all the arguments the normal constraints recieve */
+/* PyConstraints Evaluation Function (only called from evaluate_constraint)
+ * This function is responsible for modifying the ownermat that it is passed. 
+ */
 void BPY_pyconstraint_eval(bPythonConstraint *con, float ownermat[][4], float targetmat[][4])
 {
 	PyObject *srcmat, *tarmat, *idprop;
@@ -1290,6 +1293,110 @@
 	Py_XDECREF( retval );
 }
 
+/* PyConstraints 'Driver' Function
+ * This function is responsible for running any code that requires full access to the owner and the target
+ * It should be used sparringly, and only for doing 'hacks' which are not possible any other way.
+ */
+void BPY_pyconstraint_driver(bPythonConstraint *con, bConstraintOb *cob, Object *target, char subtarget[])
+{
+	PyObject *owner, *subowner, *tar, *subtar; 
+	PyObject *idprop;
+	PyObject *globals, *gval;
+	PyObject *pyargs, *retval;
+	
+	if ( !con->text ) return;
+	if ( con->flag & PYCON_SCRIPTERROR) return;
+	
+	globals = CreateGlobalDictionary();
+	
+	owner = Object_CreatePyObject( cob->ob );
+	subowner = PyPoseBone_FromPosechannel( cob->pchan );
+	
+	tar = Object_CreatePyObject( target );
+	if ( (target) && (target->type==OB_ARMATURE) ) {
+		bPoseChannel *pchan;
+		pchan = get_pose_channel( target->pose, subtarget );
+		subtar = PyPoseBone_FromPosechannel( pchan );
+	}
+	else
+		subtar = PyString_FromString(subtarget);
+	
+	idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+	
+/*  since I can't remember what the armature weakrefs do, I'll just leave this here
+    commented out.  This function was based on pydrivers, and it might still be relevent.
+	if( !setup_armature_weakrefs()){
+		fprintf( stderr, "Oops - weakref dict setup\n");
+		return result;
+	}
+*/
+	retval = RunPython( con->text, globals );
+
+	if ( retval == NULL ) {
+		BPY_Err_Handle(con->text->id.name);
+		ReleaseGlobalDictionary( globals );
+		con->flag |= PYCON_SCRIPTERROR;
+	
+		/* free temp objects */
+		Py_XDECREF( idprop );
+		Py_XDECREF( owner );
+		Py_XDECREF( subowner );
+		Py_XDECREF( tar );
+		Py_XDECREF( subtar );
+		return;
+	}
+
+	if (retval) {Py_XDECREF( retval );}
+	retval = NULL;
+	
+	gval = PyDict_GetItemString(globals, "doDriver");
+	if (!gval) {
+		ReleaseGlobalDictionary( globals );
+	
+		/* free temp objects */
+		Py_XDECREF( idprop );
+		Py_XDECREF( owner );
+		Py_XDECREF( subowner );
+		Py_XDECREF( tar );
+		Py_XDECREF( subtar );
+		return;
+	}
+	
+	/* Now for the fun part! Try and find the functions we need. */
+	if (PyFunction_Check(gval) ) {
+		pyargs = Py_BuildValue("OOOOO", owner, subowner, tar, subtar, idprop);
+		retval = PyObject_CallObject(gval, pyargs);
+		Py_XDECREF( pyargs );
+	} else {
+		printf("ERROR: doDriver is supposed to be a function!\n");
+		con->flag |= PYCON_SCRIPTERROR;
+		ReleaseGlobalDictionary( globals );
+		
+		Py_XDECREF( idprop );
+		Py_XDECREF( owner );

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list