forked from bartvdbraak/blender
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)
This commit is contained in:
parent
aa0825a5e5
commit
2faf20c4b3
@ -798,6 +798,7 @@ void calc_action_range(const bAction *act, float *start, float *end, int incl_hi
|
||||
/* 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 @@ void extract_pose_from_pose(bPose *pose, const bPose *src)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ bool BL_ActionActuator::Update(double curtime, bool frame)
|
||||
/* 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 @@ PyObject* BL_ActionActuator::PySetFrameProperty(PyObject* args,
|
||||
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))
|
||||
{
|
||||
m_propname = string;
|
||||
}
|
||||
else {
|
||||
if (!string) {
|
||||
PyErr_SetString(PyExc_TypeError, "expected a single string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
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)) )
|
||||
{
|
||||
PyErr_SetString(PyExc_ValueError, "channel doesnt exist");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *ret = PyTuple_New(3);
|
||||
|
||||
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 @@ KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel,
|
||||
"\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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
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]);
|
||||
if(pymat) {
|
||||
float matrix[4][4];
|
||||
MT_Matrix4x4 mat;
|
||||
|
||||
pchan->flag |= POSE_ROT|POSE_LOC|POSE_SIZE;
|
||||
|
||||
if (!m_userpose){
|
||||
m_userpose = (bPose*)MEM_callocN(sizeof(bPose), "userPose");
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
pchan= verify_pose_channel(m_userpose, string);
|
||||
|
||||
// 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 @@ PyMethodDef BL_ActionActuator::Methods[] = {
|
||||
{"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},
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
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);
|
||||
|
@ -336,15 +336,23 @@ class BL_ActionActuator(SCA_IActuator):
|
||||
@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
|
||||
|
Loading…
Reference in New Issue
Block a user