Blender V2.61 - r43446
|
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