Blender V2.61 - r43446

BL_ActionActuator.cpp

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 #include "SCA_LogicManager.h"
00034 #include "BL_ActionActuator.h"
00035 #include "BL_ArmatureObject.h"
00036 #include "BL_SkinDeformer.h"
00037 #include "BL_Action.h"
00038 #include "KX_GameObject.h"
00039 #include "STR_HashedString.h"
00040 #include "MEM_guardedalloc.h"
00041 #include "DNA_nla_types.h"
00042 #include "DNA_action_types.h"
00043 #include "DNA_armature_types.h"
00044 #include "DNA_scene_types.h"
00045 #include "BLI_blenlib.h"
00046 #include "BLI_math.h"
00047 #include "BLI_utildefines.h"
00048 #include "MT_Matrix4x4.h"
00049 
00050 #include "BKE_action.h"
00051 #include "FloatValue.h"
00052 #include "PyObjectPlus.h"
00053 #include "KX_PyMath.h"
00054 
00055 extern "C" {
00056 #include "BKE_animsys.h"
00057 #include "BKE_action.h"
00058 #include "RNA_access.h"
00059 #include "RNA_define.h"
00060 }
00061 
00062 BL_ActionActuator::BL_ActionActuator(SCA_IObject* gameobj,
00063                     const STR_String& propname,
00064                     const STR_String& framepropname,
00065                     float starttime,
00066                     float endtime,
00067                     struct bAction *action,
00068                     short   playtype,
00069                     short   blendin,
00070                     short   priority,
00071                     short   layer,
00072                     float   layer_weight,
00073                     short   ipo_flags,
00074                     short   end_reset,
00075                     float   stride) 
00076     : SCA_IActuator(gameobj, KX_ACT_ACTION),
00077         
00078     m_lastpos(0, 0, 0),
00079     m_blendframe(0),
00080     m_flag(0),
00081     m_startframe (starttime),
00082     m_endframe(endtime) ,
00083     m_starttime(0),
00084     m_localtime(starttime),
00085     m_lastUpdate(-1),
00086     m_blendin(blendin),
00087     m_blendstart(0),
00088     m_stridelength(stride),
00089     m_layer_weight(layer_weight),
00090     m_playtype(playtype),
00091     m_priority(priority),
00092     m_layer(layer),
00093     m_ipo_flags(ipo_flags),
00094     m_pose(NULL),
00095     m_blendpose(NULL),
00096     m_userpose(NULL),
00097     m_action(action),
00098     m_propname(propname),
00099     m_framepropname(framepropname)      
00100 {
00101     if (!end_reset)
00102         m_flag |= ACT_FLAG_CONTINUE;
00103 };
00104 
00105 BL_ActionActuator::~BL_ActionActuator()
00106 {
00107     if (m_pose)
00108         game_free_pose(m_pose);
00109     if (m_userpose)
00110         game_free_pose(m_userpose);
00111     if (m_blendpose)
00112         game_free_pose(m_blendpose);
00113 }
00114 
00115 void BL_ActionActuator::ProcessReplica()
00116 {
00117     SCA_IActuator::ProcessReplica();
00118     
00119     m_pose = NULL;
00120     m_blendpose = NULL;
00121     m_localtime=m_startframe;
00122     m_lastUpdate=-1;
00123     
00124 }
00125 
00126 void BL_ActionActuator::SetBlendTime (float newtime)
00127 {
00128     m_blendframe = newtime;
00129 }
00130 
00131 void BL_ActionActuator::SetLocalTime(float curtime)
00132 {
00133     float dt = (curtime-m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
00134 
00135     if (m_endframe < m_startframe)
00136         dt = -dt;
00137 
00138     m_localtime = m_startframe + dt;
00139     
00140     // Handle wrap around
00141     if (m_localtime < min(m_startframe, m_endframe) || m_localtime > max(m_startframe, m_endframe))
00142     {
00143         switch(m_playtype)
00144         {
00145         case ACT_ACTION_PLAY:
00146             // Clamp
00147             m_localtime = m_endframe;
00148             ((KX_GameObject*)GetParent())->StopAction(m_layer);
00149             break;
00150         case ACT_ACTION_LOOP_END:
00151             // Put the time back to the beginning
00152             m_localtime = m_startframe;
00153             m_starttime = curtime;
00154             break;
00155         case ACT_ACTION_PINGPONG:
00156             // Swap the start and end frames
00157             float temp = m_startframe;
00158             m_startframe = m_endframe;
00159             m_endframe = temp;
00160 
00161             m_starttime = curtime;
00162 
00163             m_flag ^= ACT_FLAG_REVERSE;
00164 
00165             break;
00166         }
00167     }
00168 }
00169 
00170 void BL_ActionActuator::ResetStartTime(float curtime)
00171 {
00172     float dt = m_localtime - m_startframe;
00173 
00174     m_starttime = curtime - dt / (KX_KetsjiEngine::GetAnimFrameRate());
00175     //SetLocalTime(curtime);
00176 }
00177 
00178 CValue* BL_ActionActuator::GetReplica() {
00179     BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName());
00180     replica->ProcessReplica();
00181     return replica;
00182 }
00183 
00184 bool BL_ActionActuator::Update(double curtime, bool frame)
00185 {
00186     bool bNegativeEvent = false;
00187     bool bPositiveEvent = false;
00188     bool bUseContinue = false;
00189     KX_GameObject *obj = (KX_GameObject*)GetParent();
00190     short playtype = BL_Action::ACT_MODE_PLAY;
00191     float start = m_startframe;
00192     float end = m_endframe;
00193 
00194     // If we don't have an action, we can't do anything
00195     if (!m_action)
00196         return false;
00197 
00198     // Convert our playtype to one that BL_Action likes
00199     switch(m_playtype)
00200     {
00201         case ACT_ACTION_LOOP_END:
00202         case ACT_ACTION_LOOP_STOP:
00203             playtype = BL_Action::ACT_MODE_LOOP;
00204             break;
00205 
00206         case ACT_ACTION_PINGPONG:
00207             // We handle ping pong ourselves to increase compabitility
00208             // with files made prior to animation changes from GSoC 2011.
00209             playtype = BL_Action::ACT_MODE_PLAY;
00210         
00211             if (m_flag & ACT_FLAG_REVERSE)
00212             {
00213                 start = m_endframe;
00214                 end = m_startframe;
00215             }
00216 
00217             break;
00218         case ACT_ACTION_FROM_PROP:
00219             CValue* prop = GetParent()->GetProperty(m_propname);
00220 
00221             // If we don't have a property, we can't do anything, so just bail
00222             if (!prop) return false;
00223 
00224             playtype = BL_Action::ACT_MODE_PLAY;
00225             start = end = prop->GetNumber();
00226 
00227             break;
00228     }
00229 
00230     if (m_flag & ACT_FLAG_CONTINUE)
00231         bUseContinue = true;
00232     
00233     
00234     // Handle events
00235     if (frame)
00236     {
00237         bNegativeEvent = m_negevent;
00238         bPositiveEvent = m_posevent;
00239         RemoveAllEvents();
00240     }
00241 
00242     // "Active" actions need to keep updating their current frame
00243     if (bUseContinue && (m_flag & ACT_FLAG_ACTIVE))
00244         m_localtime = obj->GetActionFrame(m_layer);
00245 
00246     if (m_flag & ACT_FLAG_ATTEMPT_PLAY)
00247         SetLocalTime(curtime);
00248     else
00249         ResetStartTime(curtime);
00250 
00251     // Handle a frame property if it's defined
00252     if ((m_flag & ACT_FLAG_ACTIVE) && m_framepropname[0] != 0)
00253     {
00254         CValue* oldprop = obj->GetProperty(m_framepropname);
00255         CValue* newval = new CFloatValue(obj->GetActionFrame(m_layer));
00256         if (oldprop)
00257             oldprop->SetValue(newval);
00258         else
00259             obj->SetProperty(m_framepropname, newval);
00260 
00261         newval->Release();
00262     }
00263 
00264     // Handle a finished animation
00265     if ((m_flag & ACT_FLAG_PLAY_END) && (m_flag & ACT_FLAG_ACTIVE) && obj->IsActionDone(m_layer))
00266     {
00267         m_flag &= ~ACT_FLAG_ACTIVE;
00268         m_flag &= ~ACT_FLAG_ATTEMPT_PLAY;
00269 
00270         if (m_playtype == ACT_ACTION_PINGPONG)
00271             m_flag ^= ACT_FLAG_REVERSE;
00272         return false;
00273     }
00274     
00275     // If a different action is playing, we've been overruled and are no longer active
00276     if (obj->GetCurrentAction(m_layer) != m_action && !obj->IsActionDone(m_layer))
00277         m_flag &= ~ACT_FLAG_ACTIVE;
00278 
00279     if (bPositiveEvent || (m_flag & ACT_FLAG_ATTEMPT_PLAY && !(m_flag & ACT_FLAG_ACTIVE)))
00280     {
00281         if (bPositiveEvent && m_playtype == ACT_ACTION_PLAY)
00282         {
00283             if (obj->IsActionDone(m_layer))
00284                 m_localtime = start;
00285             ResetStartTime(curtime);
00286         }
00287 
00288         if (obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, m_blendin, playtype, m_layer_weight, m_ipo_flags))
00289         {
00290             m_flag |= ACT_FLAG_ACTIVE;
00291             if (bUseContinue)
00292                 obj->SetActionFrame(m_layer, m_localtime);
00293 
00294             if (m_playtype == ACT_ACTION_PLAY || m_playtype == ACT_ACTION_PINGPONG)
00295                 m_flag |= ACT_FLAG_PLAY_END;
00296             else
00297                 m_flag &= ~ACT_FLAG_PLAY_END;
00298         }
00299         m_flag |= ACT_FLAG_ATTEMPT_PLAY;
00300     }
00301     else if ((m_flag & ACT_FLAG_ACTIVE) && bNegativeEvent)
00302     {   
00303         m_flag &= ~ACT_FLAG_ATTEMPT_PLAY;
00304         m_localtime = obj->GetActionFrame(m_layer);
00305         bAction *curr_action = obj->GetCurrentAction(m_layer);
00306         if (curr_action && curr_action != m_action)
00307         {
00308             // Someone changed the action on us, so we wont mess with it
00309             // Hopefully there wont be too many problems with two actuators using
00310             // the same action...
00311             m_flag &= ~ACT_FLAG_ACTIVE;
00312             return false;
00313         }
00314 
00315         switch(m_playtype)
00316         {
00317             case ACT_ACTION_LOOP_STOP:
00318                 obj->StopAction(m_layer); // Stop the action after getting the frame
00319 
00320                 // We're done
00321                 m_flag &= ~ACT_FLAG_ACTIVE;
00322                 return false;
00323             case ACT_ACTION_LOOP_END:
00324                 // Convert into a play and let it finish
00325                 obj->SetPlayMode(m_layer, BL_Action::ACT_MODE_PLAY);
00326 
00327                 m_flag |= ACT_FLAG_PLAY_END;
00328                 break;
00329     
00330             case ACT_ACTION_FLIPPER:
00331                 // Convert into a play action and play back to the beginning
00332                 end = start;
00333                 start = obj->GetActionFrame(m_layer);
00334                 obj->PlayAction(m_action->id.name+2, start, end, m_layer, m_priority, 0, BL_Action::ACT_MODE_PLAY, m_layer_weight, m_ipo_flags);
00335 
00336                 m_flag |= ACT_FLAG_PLAY_END;
00337                 break;
00338         }
00339     }
00340 
00341     return true;
00342 }
00343 
00344 #ifdef WITH_PYTHON
00345 
00346 /* ------------------------------------------------------------------------- */
00347 /* Python functions                                                          */
00348 /* ------------------------------------------------------------------------- */
00349 
00350 PyObject* BL_ActionActuator::PyGetChannel(PyObject* value)
00351 {
00352     const char *string= _PyUnicode_AsString(value);
00353     
00354     if (!string) {
00355         PyErr_SetString(PyExc_TypeError, "expected a single string");
00356         return NULL;
00357     }
00358     
00359     bPoseChannel *pchan;
00360     
00361     if(m_userpose==NULL && m_pose==NULL) {
00362         BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
00363         obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
00364     }
00365     
00366     // get_pose_channel accounts for NULL pose, run on both incase one exists but
00367     // the channel doesnt
00368     if(     !(pchan=get_pose_channel(m_userpose, string)) &&
00369             !(pchan=get_pose_channel(m_pose, string))  )
00370     {
00371         PyErr_SetString(PyExc_ValueError, "channel doesnt exist");
00372         return NULL;
00373     }
00374 
00375     PyObject *ret = PyTuple_New(3);
00376     
00377     PyObject *list = PyList_New(3); 
00378     PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->loc[0]));
00379     PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->loc[1]));
00380     PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->loc[2]));
00381     PyTuple_SET_ITEM(ret, 0, list);
00382     
00383     list = PyList_New(3);
00384     PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->size[0]));
00385     PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->size[1]));
00386     PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->size[2]));
00387     PyTuple_SET_ITEM(ret, 1, list);
00388     
00389     list = PyList_New(4);
00390     PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->quat[0]));
00391     PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->quat[1]));
00392     PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->quat[2]));
00393     PyList_SET_ITEM(list, 3, PyFloat_FromDouble(pchan->quat[3]));
00394     PyTuple_SET_ITEM(ret, 2, list);
00395 
00396     return ret;
00397 /*
00398     return Py_BuildValue("([fff][fff][ffff])",
00399         pchan->loc[0], pchan->loc[1], pchan->loc[2],
00400         pchan->size[0], pchan->size[1], pchan->size[2],
00401         pchan->quat[0], pchan->quat[1], pchan->quat[2], pchan->quat[3] );
00402 */
00403 }
00404 
00405 /*     setChannel                                                         */
00406 KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel,
00407 "setChannel(channel, matrix)\n"
00408 "\t - channel   : A string specifying the name of the bone channel.\n"
00409 "\t - matrix    : A 4x4 matrix specifying the overriding transformation\n"
00410 "\t               as an offset from the bone's rest position.\n")
00411 {
00412     BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
00413     char *string;
00414     PyObject *pymat= NULL;
00415     PyObject *pyloc= NULL, *pysize= NULL, *pyquat= NULL;
00416     bPoseChannel *pchan;
00417     
00418     if(PyTuple_Size(args)==2) {
00419         if (!PyArg_ParseTuple(args,"sO:setChannel", &string, &pymat)) // matrix
00420             return NULL;
00421     }
00422     else if(PyTuple_Size(args)==4) {
00423         if (!PyArg_ParseTuple(args,"sOOO:setChannel", &string, &pyloc, &pysize, &pyquat)) // loc/size/quat
00424             return NULL;
00425     }
00426     else {
00427         PyErr_SetString(PyExc_ValueError, "Expected a string and a 4x4 matrix (2 args) or a string and loc/size/quat sequences (4 args)");
00428         return NULL;
00429     }
00430     
00431     if(pymat) {
00432         float matrix[4][4];
00433         MT_Matrix4x4 mat;
00434         
00435         if(!PyMatTo(pymat, mat))
00436             return NULL;
00437         
00438         mat.getValue((float*)matrix);
00439         
00440         BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent();
00441         
00442         if (!m_userpose) {
00443             if(!m_pose)
00444                 obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
00445             game_copy_pose(&m_userpose, m_pose, 0);
00446         }
00447         // pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there.
00448         pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there.
00449         
00450         if(pchan) {
00451             copy_v3_v3(pchan->loc, matrix[3]);
00452             mat4_to_size(pchan->size, matrix);
00453             mat4_to_quat(pchan->quat, matrix);
00454         }
00455     }
00456     else {
00457         MT_Vector3 loc;
00458         MT_Vector3 size;
00459         MT_Quaternion quat;
00460         
00461         if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyQuatTo(pyquat, quat))
00462             return NULL;
00463         
00464         // same as above
00465         if (!m_userpose) {
00466             if(!m_pose)
00467                 obj->GetPose(&m_pose); /* Get the underlying pose from the armature */
00468             game_copy_pose(&m_userpose, m_pose, 0);
00469         }
00470         // pchan= verify_pose_channel(m_userpose, string);
00471         pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there.
00472         
00473         // for some reason loc.setValue(pchan->loc) fails
00474         if(pchan) {
00475             pchan->loc[0]= loc[0]; pchan->loc[1]= loc[1]; pchan->loc[2]= loc[2];
00476             pchan->size[0]= size[0]; pchan->size[1]= size[1]; pchan->size[2]= size[2];
00477             pchan->quat[0]= quat[3]; pchan->quat[1]= quat[0]; pchan->quat[2]= quat[1]; pchan->quat[3]= quat[2]; /* notice xyzw -> wxyz is intentional */
00478         }
00479     }
00480     
00481     if(pchan==NULL) {
00482         PyErr_SetString(PyExc_ValueError, "Channel could not be found, use the 'channelNames' attribute to get a list of valid channels");
00483         return NULL;
00484     }
00485     
00486     Py_RETURN_NONE;
00487 }
00488 
00489 /* ------------------------------------------------------------------------- */
00490 /* Python Integration Hooks                                                  */
00491 /* ------------------------------------------------------------------------- */
00492 
00493 PyTypeObject BL_ActionActuator::Type = {
00494     PyVarObject_HEAD_INIT(NULL, 0)
00495     "BL_ActionActuator",
00496     sizeof(PyObjectPlus_Proxy),
00497     0,
00498     py_base_dealloc,
00499     0,
00500     0,
00501     0,
00502     0,
00503     py_base_repr,
00504     0,0,0,0,0,0,0,0,0,
00505     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00506     0,0,0,0,0,0,0,
00507     Methods,
00508     0,
00509     0,
00510     &SCA_IActuator::Type,
00511     0,0,0,0,0,0,
00512     py_base_new
00513 };
00514 
00515 PyMethodDef BL_ActionActuator::Methods[] = {
00516     {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_O},
00517     KX_PYMETHODTABLE(BL_ActionActuator, setChannel),
00518     {NULL,NULL} //Sentinel
00519 };
00520 
00521 PyAttributeDef BL_ActionActuator::Attributes[] = {
00522     KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ActionActuator, m_startframe),
00523     KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ActionActuator, m_endframe),
00524     KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ActionActuator, m_blendin),
00525     KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action),
00526     KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names),
00527     KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority),
00528     KX_PYATTRIBUTE_RW_FUNCTION("frame", BL_ActionActuator, pyattr_get_frame, pyattr_set_frame),
00529     KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_propname),
00530     KX_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, BL_ActionActuator, m_framepropname),
00531     KX_PYATTRIBUTE_RW_FUNCTION("useContinue", BL_ActionActuator, pyattr_get_use_continue, pyattr_set_use_continue),
00532     KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime),
00533     KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType),
00534     { NULL }    //Sentinel
00535 };
00536 
00537 PyObject* BL_ActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00538 {
00539     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00540     return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
00541 }
00542 
00543 int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00544 {
00545     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00546     
00547     if (!PyUnicode_Check(value))
00548     {
00549         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, expected the string name of the action");
00550         return PY_SET_ATTR_FAIL;
00551     }
00552 
00553     bAction *action= NULL;
00554     STR_String val = _PyUnicode_AsString(value);
00555     
00556     if (val != "")
00557     {
00558         action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
00559         if (!action)
00560         {
00561             PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!");
00562             return PY_SET_ATTR_FAIL;
00563         }
00564     }
00565     
00566     self->SetAction(action);
00567     return PY_SET_ATTR_SUCCESS;
00568 
00569 }
00570 
00571 PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00572 {
00573     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00574     PyObject *ret= PyList_New(0);
00575     PyObject *item;
00576     
00577     bPose *pose= ((BL_ArmatureObject*)self->GetParent())->GetOrigPose();
00578     
00579     if(pose) {
00580         bPoseChannel *pchan;
00581         for(pchan= (bPoseChannel *)pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) {
00582             item= PyUnicode_FromString(pchan->name);
00583             PyList_Append(ret, item);
00584             Py_DECREF(item);
00585         }
00586     }
00587     
00588     return ret;
00589 }
00590 
00591 PyObject* BL_ActionActuator::pyattr_get_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00592 {
00593     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00594     return PyBool_FromLong(self->m_flag & ACT_FLAG_CONTINUE);
00595 }
00596 
00597 int BL_ActionActuator::pyattr_set_use_continue(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00598 {
00599     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00600     
00601     if (PyObject_IsTrue(value))
00602         self->m_flag |= ACT_FLAG_CONTINUE;
00603     else
00604         self->m_flag &= ~ACT_FLAG_CONTINUE;
00605     
00606     return PY_SET_ATTR_SUCCESS;
00607 }
00608 
00609 PyObject* BL_ActionActuator::pyattr_get_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00610 {
00611     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00612     return PyFloat_FromDouble(((KX_GameObject*)self->m_gameobj)->GetActionFrame(self->m_layer));
00613 }
00614 
00615 int BL_ActionActuator::pyattr_set_frame(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00616 {
00617     BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v);
00618     
00619     ((KX_GameObject*)self->m_gameobj)->SetActionFrame(self->m_layer, PyFloat_AsDouble(value));
00620     
00621     return PY_SET_ATTR_SUCCESS;
00622 }
00623 
00624 #endif // WITH_PYTHON