[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [20937] trunk/blender/source: BGE Action Actuator setChannel() function was broken in a number of ways.

Campbell Barton ideasman42 at gmail.com
Tue Jun 16 20:25:48 CEST 2009


Revision: 20937
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=20937
Author:   campbellbarton
Date:     2009-06-16 20:25:48 +0200 (Tue, 16 Jun 2009)

Log Message:
-----------
BGE Action Actuator setChannel() function was broken in a number of ways. 
* extract_pose_from_pose only checked one of the list items for NULL when looping over them yet its possible they are different sizes.
* game_free_pose needed to be used rather then MEM_freeN, channels would never be freed leaking memory.
* setChannel() would make a new pose that wasnt aligned with the existing pose, the lists are assumed aligned so when extracting the channels its unlikely this was ever useful.
* Added getChannel() - returns pose loc/size/quat
* Added option args for setChannel(channel, matrix) or setChannel(channel, loc, size, quat)

Modified Paths:
--------------
    trunk/blender/source/blender/blenkernel/intern/action.c
    trunk/blender/source/gameengine/Converter/BL_ActionActuator.cpp
    trunk/blender/source/gameengine/Converter/BL_ActionActuator.h
    trunk/blender/source/gameengine/PyDoc/GameTypes.py

Modified: trunk/blender/source/blender/blenkernel/intern/action.c
===================================================================
--- trunk/blender/source/blender/blenkernel/intern/action.c	2009-06-16 18:02:38 UTC (rev 20936)
+++ trunk/blender/source/blender/blenkernel/intern/action.c	2009-06-16 18:25:48 UTC (rev 20937)
@@ -798,6 +798,7 @@
 /* Copy the data from the action-pose (src) into the pose */
 /* both args are assumed to be valid */
 /* exported to game engine */
+/* Note! this assumes both poses are aligned, this isnt always true when dealing with user poses */
 void extract_pose_from_pose(bPose *pose, const bPose *src)
 {
 	const bPoseChannel *schan;
@@ -808,7 +809,7 @@
 		return;
 	}
 
-	for (schan=src->chanbase.first; schan; schan=schan->next, pchan= pchan->next) {
+	for (schan=src->chanbase.first; (schan && pchan); schan=schan->next, pchan= pchan->next) {
 		copy_pose_channel_data(pchan, schan);
 	}
 }

Modified: trunk/blender/source/gameengine/Converter/BL_ActionActuator.cpp
===================================================================
--- trunk/blender/source/gameengine/Converter/BL_ActionActuator.cpp	2009-06-16 18:02:38 UTC (rev 20936)
+++ trunk/blender/source/gameengine/Converter/BL_ActionActuator.cpp	2009-06-16 18:25:48 UTC (rev 20937)
@@ -50,6 +50,7 @@
 #include "BKE_utildefines.h"
 #include "FloatValue.h"
 #include "PyObjectPlus.h"
+#include "KX_PyMath.h"
 #include "blendef.h"
 
 #ifdef HAVE_CONFIG_H
@@ -366,8 +367,7 @@
 			/* Perform the user override (if any) */
 			if (m_userpose){
 				extract_pose_from_pose(m_pose, m_userpose);
-//				clear_pose(m_userpose);
-				MEM_freeN(m_userpose);
+				game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too.
 				m_userpose = NULL;
 			}
 #if 1
@@ -767,22 +767,55 @@
 	Py_RETURN_NONE;
 }
 
-/*
-PyObject* BL_ActionActuator::PyGetChannel(PyObject* args, 
-										   PyObject* kwds) {
-	char *string;
+PyObject* BL_ActionActuator::PyGetChannel(PyObject* value) {
+	char *string= PyString_AsString(value);
 	
-	if (PyArg_ParseTuple(args,"s:getChannel",&string))
+	if (!string) {
+		PyErr_SetString(PyExc_TypeError, "expected a single string");
+		return NULL;
+	}
+	
+	bPoseChannel *pchan;
+	
+	
+	// get_pose_channel accounts for NULL pose, run on both incase one exists but
+	// the channel doesnt
+	if(		!(pchan=get_pose_channel(m_userpose, string)) &&
+			!(pchan=get_pose_channel(m_pose, string))  )
 	{
-		m_propname = string;
-	}
-	else {
+		PyErr_SetString(PyExc_ValueError, "channel doesnt exist");
 		return NULL;
 	}
+
+	PyObject *ret = PyTuple_New(3);
 	
-	Py_RETURN_NONE;
+	PyObject *list = PyList_New(3); 
+	PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->loc[0]));
+	PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->loc[1]));
+	PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->loc[2]));
+	PyTuple_SET_ITEM(ret, 0, list);
+	
+	list = PyList_New(3);
+	PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->size[0]));
+	PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->size[1]));
+	PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->size[2]));
+	PyTuple_SET_ITEM(ret, 1, list);
+	
+	list = PyList_New(4);
+	PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->quat[0]));
+	PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->quat[1]));
+	PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->quat[2]));
+	PyList_SET_ITEM(list, 3, PyFloat_FromDouble(pchan->quat[3]));
+	PyTuple_SET_ITEM(ret, 2, list);
+
+	return ret;
+/*
+	return Py_BuildValue("([fff][fff][ffff])",
+		pchan->loc[0], pchan->loc[1], pchan->loc[2],
+		pchan->size[0], pchan->size[1], pchan->size[2],
+		pchan->quat[0], pchan->quat[1], pchan->quat[2], pchan->quat[3] );
+*/
 }
-*/
 
 /* getType */
 const char BL_ActionActuator::GetType_doc[] =
@@ -857,76 +890,69 @@
 "\t - matrix    : A 4x4 matrix specifying the overriding transformation\n"
 "\t               as an offset from the bone's rest position.\n")
 {
-	float matrix[4][4];
+	BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
 	char *string;
-	PyObject* pylist;
-	bool	error = false;
-	int row,col;
-	int	mode = 0;	/* 0 for bone space, 1 for armature/world space */
+	PyObject *pymat= NULL;
+	PyObject *pyloc= NULL, *pysize= NULL, *pyquat= NULL;
+	bPoseChannel *pchan;
 	
-	if (!PyArg_ParseTuple(args,"sO|i:setChannel", &string, &pylist, &mode))
+	if(PyTuple_Size(args)==2) {
+		if (!PyArg_ParseTuple(args,"sO:setChannel", &string, &pymat)) // matrix
+			return NULL;
+	}
+	else if(PyTuple_Size(args)==4) {
+		if (!PyArg_ParseTuple(args,"sOOO:setChannel", &string, &pyloc, &pysize, &pyquat)) // loc/size/quat
+			return NULL;
+	}
+	else {
+		PyErr_SetString(PyExc_ValueError, "Expected a string and a 4x4 matrix (2 args) or a string and loc/size/quat sequences (4 args)");
 		return NULL;
+	}
 	
-	if (pylist->ob_type == &CListValue::Type)
-	{
-		CListValue* listval = (CListValue*) pylist;
-		if (listval->GetCount() == 4)
-		{
-			for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w]
-			{
-				CListValue* vecval = (CListValue*)listval->GetValue(row);
-				for (col=0;col<4;col++)
-				{
-					matrix[row][col] = vecval->GetValue(col)->GetNumber();
-					
-				}
-			}
+	if(pymat) {
+		float matrix[4][4];
+		MT_Matrix4x4 mat;
+		
+		if(!PyMatTo(pymat, mat))
+			return NULL;
+		
+		mat.setValue((const float *)matrix);
+		
+		BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
+		obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
+		
+		if (!m_userpose) {
+			obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
+			game_copy_pose(&m_userpose, m_pose);
 		}
-		else
-		{
-			error = true;
-		}
+		pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there.
+		
+		VECCOPY (pchan->loc, matrix[3]);
+		Mat4ToSize(matrix, pchan->size);
+		Mat4ToQuat(matrix, pchan->quat);
 	}
-	else
-	{
-		// assert the list is long enough...
-		int numitems = PyList_Size(pylist);
-		if (numitems == 4)
-		{
-			for (row=0;row<4;row++) // each row has a 4-vector [x,y,z, w]
-			{
-				
-				PyObject* veclist = PyList_GetItem(pylist,row); // here we have a vector4 list
-				for (col=0;col<4;col++)
-				{
-					matrix[row][col] =  PyFloat_AsDouble(PyList_GetItem(veclist,col));
-					
-				}
-			}
+	else {
+		MT_Vector3 loc;
+		MT_Vector3 size;
+		MT_Vector4 quat;
+		
+		if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyVecTo(pyquat, quat))
+			return NULL;
+		
+		// same as above
+		if (!m_userpose) {
+			obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
+			game_copy_pose(&m_userpose, m_pose);
 		}
-		else
-		{
-			error = true;
-		}
-	}
-	
-	if (!error)
-	{
-
-/*	DO IT HERE */
-		bPoseChannel *pchan= verify_pose_channel(m_userpose, string);
-
-		Mat4ToQuat(matrix, pchan->quat);
-		Mat4ToSize(matrix, pchan->size);
-		VECCOPY (pchan->loc, matrix[3]);
+		pchan= verify_pose_channel(m_userpose, string);
 		
-		pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE;
-
-		if (!m_userpose){
-			m_userpose = (bPose*)MEM_callocN(sizeof(bPose), "userPose");
-		}
+		// for some reason loc.setValue(pchan->loc) fails
+		pchan->loc[0]= loc[0]; pchan->loc[1]= loc[1]; pchan->loc[2]= loc[2];
+		pchan->size[0]= size[0]; pchan->size[1]= size[1]; pchan->size[2]= size[2];
+		pchan->quat[0]= quat[0]; pchan->quat[1]= quat[1]; pchan->quat[2]= quat[2]; pchan->quat[3]= quat[3];
 	}
 	
+	pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE;
 	Py_RETURN_NONE;
 }
 
@@ -986,7 +1012,7 @@
 	{"getFrame", (PyCFunction) BL_ActionActuator::sPyGetFrame, METH_VARARGS, (PY_METHODCHAR)GetFrame_doc},
 	{"getProperty", (PyCFunction) BL_ActionActuator::sPyGetProperty, METH_VARARGS, (PY_METHODCHAR)GetProperty_doc},
 	{"getFrameProperty", (PyCFunction) BL_ActionActuator::sPyGetFrameProperty, METH_VARARGS, (PY_METHODCHAR)GetFrameProperty_doc},
-//	{"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_VARARGS},
+	{"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_O},
 	{"getType", (PyCFunction) BL_ActionActuator::sPyGetType, METH_VARARGS, (PY_METHODCHAR)GetType_doc},
 	{"setType", (PyCFunction) BL_ActionActuator::sPySetType, METH_VARARGS, (PY_METHODCHAR)SetType_doc},
 	{"getContinue", (PyCFunction) BL_ActionActuator::sPyGetContinue, METH_NOARGS, 0},	

Modified: trunk/blender/source/gameengine/Converter/BL_ActionActuator.h
===================================================================
--- trunk/blender/source/gameengine/Converter/BL_ActionActuator.h	2009-06-16 18:02:38 UTC (rev 20936)
+++ trunk/blender/source/gameengine/Converter/BL_ActionActuator.h	2009-06-16 18:25:48 UTC (rev 20937)
@@ -104,7 +104,7 @@
 	KX_PYMETHOD_DOC(BL_ActionActuator,GetFrame);
 	KX_PYMETHOD_DOC(BL_ActionActuator,GetProperty);
 	KX_PYMETHOD_DOC(BL_ActionActuator,GetFrameProperty);
-//	KX_PYMETHOD(BL_ActionActuator,GetChannel);
+	KX_PYMETHOD_O(BL_ActionActuator,GetChannel);
 	KX_PYMETHOD_DOC(BL_ActionActuator,GetType);
 	KX_PYMETHOD_DOC(BL_ActionActuator,SetType);
 	KX_PYMETHOD_NOARGS(BL_ActionActuator,GetContinue);

Modified: trunk/blender/source/gameengine/PyDoc/GameTypes.py
===================================================================
--- trunk/blender/source/gameengine/PyDoc/GameTypes.py	2009-06-16 18:02:38 UTC (rev 20936)
+++ trunk/blender/source/gameengine/PyDoc/GameTypes.py	2009-06-16 18:25:48 UTC (rev 20937)
@@ -336,17 +336,25 @@
 	@ivar framePropName: The name of the property that is set to the current frame number.
 	@type framePropName: string
 	"""
-	def setChannel(channel, matrix, mode = False):
+	def setChannel(channel, matrix):
 		"""
-		@param channel: A string specifying the name of the bone channel.
+		Alternative to the 2 arguments, 4 arguments (channel, matrix, loc, size, quat) are also supported.
+		
+		@param channel: A string specifying the name of the bone channel, created if missing.
 		@type channel: string
 		@param matrix: A 4x4 matrix specifying the overriding transformation
 		               as an offset from the bone's rest position.
 		@type matrix: list [[float]]
-		@param mode: True for armature/world space, False for bone space
-		@type mode: boolean
 		"""
 
+	def getChannel(channel):
+		"""
+		@param channel: A string specifying the name of the bone channel. error raised if missing.
+		@type channel: string
+		@rtype: tuple
+		@return: (loc, size, quat)
+		"""
+
 #{ Deprecated
 	def setAction(action, reset = True):
 		"""





More information about the Bf-blender-cvs mailing list