|
Blender
V2.59
|
00001 /* 00002 * $Id: BL_ActionActuator.cpp 37512 2011-06-15 14:06:25Z campbellbarton $ 00003 * 00004 * ***** BEGIN GPL LICENSE BLOCK ***** 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software Foundation, 00018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 * 00020 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00021 * All rights reserved. 00022 * 00023 * The Original Code is: all of this file. 00024 * 00025 * Contributor(s): none yet. 00026 * 00027 * ***** END GPL LICENSE BLOCK ***** 00028 */ 00029 00035 #include "SCA_LogicManager.h" 00036 #include "BL_ActionActuator.h" 00037 #include "BL_ArmatureObject.h" 00038 #include "BL_SkinDeformer.h" 00039 #include "KX_GameObject.h" 00040 #include "STR_HashedString.h" 00041 #include "MEM_guardedalloc.h" 00042 #include "DNA_nla_types.h" 00043 #include "DNA_action_types.h" 00044 #include "DNA_armature_types.h" 00045 #include "DNA_scene_types.h" 00046 #include "BLI_blenlib.h" 00047 #include "BLI_math.h" 00048 #include "BLI_utildefines.h" 00049 #include "MT_Matrix4x4.h" 00050 00051 #include "BKE_action.h" 00052 #include "FloatValue.h" 00053 #include "PyObjectPlus.h" 00054 #include "KX_PyMath.h" 00055 00056 extern "C" { 00057 #include "BKE_animsys.h" 00058 #include "BKE_action.h" 00059 #include "RNA_access.h" 00060 #include "RNA_define.h" 00061 } 00062 00063 BL_ActionActuator::~BL_ActionActuator() 00064 { 00065 if (m_pose) 00066 game_free_pose(m_pose); 00067 if (m_userpose) 00068 game_free_pose(m_userpose); 00069 if (m_blendpose) 00070 game_free_pose(m_blendpose); 00071 } 00072 00073 void BL_ActionActuator::ProcessReplica() 00074 { 00075 SCA_IActuator::ProcessReplica(); 00076 00077 m_pose = NULL; 00078 m_blendpose = NULL; 00079 m_localtime=m_startframe; 00080 m_lastUpdate=-1; 00081 00082 } 00083 00084 void BL_ActionActuator::SetBlendTime (float newtime){ 00085 m_blendframe = newtime; 00086 } 00087 00088 CValue* BL_ActionActuator::GetReplica() { 00089 BL_ActionActuator* replica = new BL_ActionActuator(*this);//m_float,GetName()); 00090 replica->ProcessReplica(); 00091 return replica; 00092 } 00093 00094 bool BL_ActionActuator::ClampLocalTime() 00095 { 00096 if (m_startframe < m_endframe) 00097 { 00098 if (m_localtime < m_startframe) 00099 { 00100 m_localtime = m_startframe; 00101 return true; 00102 } 00103 else if (m_localtime > m_endframe) 00104 { 00105 m_localtime = m_endframe; 00106 return true; 00107 } 00108 } else { 00109 if (m_localtime > m_startframe) 00110 { 00111 m_localtime = m_startframe; 00112 return true; 00113 } 00114 else if (m_localtime < m_endframe) 00115 { 00116 m_localtime = m_endframe; 00117 return true; 00118 } 00119 } 00120 return false; 00121 } 00122 00123 void BL_ActionActuator::SetStartTime(float curtime) 00124 { 00125 float direction = m_startframe < m_endframe ? 1.0 : -1.0; 00126 00127 if (!(m_flag & ACT_FLAG_REVERSE)) 00128 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate(); 00129 else 00130 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate(); 00131 } 00132 00133 void BL_ActionActuator::SetLocalTime(float curtime) 00134 { 00135 float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate(); 00136 00137 if (m_endframe < m_startframe) 00138 delta_time = -delta_time; 00139 00140 if (!(m_flag & ACT_FLAG_REVERSE)) 00141 m_localtime = m_startframe + delta_time; 00142 else 00143 m_localtime = m_endframe - delta_time; 00144 } 00145 00146 00147 bool BL_ActionActuator::Update(double curtime, bool frame) 00148 { 00149 bool bNegativeEvent = false; 00150 bool bPositiveEvent = false; 00151 bool keepgoing = true; 00152 bool wrap = false; 00153 bool apply=true; 00154 int priority; 00155 float newweight; 00156 00157 curtime -= KX_KetsjiEngine::GetSuspendedDelta(); 00158 00159 // result = true if animation has to be continued, false if animation stops 00160 // maybe there are events for us in the queue ! 00161 if (frame) 00162 { 00163 bNegativeEvent = m_negevent; 00164 bPositiveEvent = m_posevent; 00165 RemoveAllEvents(); 00166 00167 if (bPositiveEvent) 00168 m_flag |= ACT_FLAG_ACTIVE; 00169 00170 if (bNegativeEvent) 00171 { 00172 // dont continue where we left off when restarting 00173 if (m_end_reset) { 00174 m_flag &= ~ACT_FLAG_LOCKINPUT; 00175 } 00176 00177 if (!(m_flag & ACT_FLAG_ACTIVE)) 00178 return false; 00179 m_flag &= ~ACT_FLAG_ACTIVE; 00180 } 00181 } 00182 00183 /* We know that action actuators have been discarded from all non armature objects: 00184 if we're being called, we're attached to a BL_ArmatureObject */ 00185 BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); 00186 float length = m_endframe - m_startframe; 00187 00188 priority = m_priority; 00189 00190 /* Determine pre-incrementation behaviour and set appropriate flags */ 00191 switch (m_playtype){ 00192 case ACT_ACTION_MOTION: 00193 if (bNegativeEvent){ 00194 keepgoing=false; 00195 apply=false; 00196 }; 00197 break; 00198 case ACT_ACTION_FROM_PROP: 00199 if (bNegativeEvent){ 00200 apply=false; 00201 keepgoing=false; 00202 } 00203 break; 00204 case ACT_ACTION_LOOP_END: 00205 if (bPositiveEvent){ 00206 if (!(m_flag & ACT_FLAG_LOCKINPUT)){ 00207 m_flag &= ~ACT_FLAG_KEYUP; 00208 m_flag &= ~ACT_FLAG_REVERSE; 00209 m_flag |= ACT_FLAG_LOCKINPUT; 00210 m_localtime = m_startframe; 00211 m_starttime = curtime; 00212 } 00213 } 00214 if (bNegativeEvent){ 00215 m_flag |= ACT_FLAG_KEYUP; 00216 } 00217 break; 00218 case ACT_ACTION_LOOP_STOP: 00219 if (bPositiveEvent){ 00220 if (!(m_flag & ACT_FLAG_LOCKINPUT)){ 00221 m_flag &= ~ACT_FLAG_REVERSE; 00222 m_flag &= ~ACT_FLAG_KEYUP; 00223 m_flag |= ACT_FLAG_LOCKINPUT; 00224 SetStartTime(curtime); 00225 } 00226 } 00227 if (bNegativeEvent){ 00228 m_flag |= ACT_FLAG_KEYUP; 00229 m_flag &= ~ACT_FLAG_LOCKINPUT; 00230 keepgoing=false; 00231 apply=false; 00232 } 00233 break; 00234 case ACT_ACTION_PINGPONG: 00235 if (bPositiveEvent){ 00236 if (!(m_flag & ACT_FLAG_LOCKINPUT)){ 00237 m_flag &= ~ACT_FLAG_KEYUP; 00238 m_localtime = m_starttime; 00239 m_starttime = curtime; 00240 m_flag |= ACT_FLAG_LOCKINPUT; 00241 } 00242 } 00243 break; 00244 case ACT_ACTION_FLIPPER: 00245 if (bPositiveEvent){ 00246 if (!(m_flag & ACT_FLAG_LOCKINPUT)){ 00247 m_flag &= ~ACT_FLAG_REVERSE; 00248 m_flag |= ACT_FLAG_LOCKINPUT; 00249 SetStartTime(curtime); 00250 } 00251 } 00252 else if (bNegativeEvent){ 00253 m_flag |= ACT_FLAG_REVERSE; 00254 m_flag &= ~ACT_FLAG_LOCKINPUT; 00255 SetStartTime(curtime); 00256 } 00257 break; 00258 case ACT_ACTION_PLAY: 00259 if (bPositiveEvent){ 00260 if (!(m_flag & ACT_FLAG_LOCKINPUT)){ 00261 m_flag &= ~ACT_FLAG_REVERSE; 00262 m_localtime = m_starttime; 00263 m_starttime = curtime; 00264 m_flag |= ACT_FLAG_LOCKINPUT; 00265 } 00266 } 00267 break; 00268 default: 00269 break; 00270 } 00271 00272 /* Perform increment */ 00273 if (keepgoing){ 00274 if (m_playtype == ACT_ACTION_MOTION){ 00275 MT_Point3 newpos; 00276 MT_Point3 deltapos; 00277 00278 newpos = obj->NodeGetWorldPosition(); 00279 00280 /* Find displacement */ 00281 deltapos = newpos-m_lastpos; 00282 m_localtime += (length/m_stridelength) * deltapos.length(); 00283 m_lastpos = newpos; 00284 } 00285 else{ 00286 SetLocalTime(curtime); 00287 } 00288 } 00289 00290 /* Check if a wrapping response is needed */ 00291 if (length){ 00292 if (m_localtime < m_startframe || m_localtime > m_endframe) 00293 { 00294 m_localtime = m_startframe + fmod(m_localtime, length); 00295 wrap = true; 00296 } 00297 } 00298 else 00299 m_localtime = m_startframe; 00300 00301 /* Perform post-increment tasks */ 00302 switch (m_playtype){ 00303 case ACT_ACTION_FROM_PROP: 00304 { 00305 CValue* propval = GetParent()->GetProperty(m_propname); 00306 if (propval) 00307 m_localtime = propval->GetNumber(); 00308 00309 if (bNegativeEvent){ 00310 keepgoing=false; 00311 } 00312 } 00313 break; 00314 case ACT_ACTION_MOTION: 00315 break; 00316 case ACT_ACTION_LOOP_STOP: 00317 break; 00318 case ACT_ACTION_PINGPONG: 00319 if (wrap){ 00320 if (!(m_flag & ACT_FLAG_REVERSE)) 00321 m_localtime = m_endframe; 00322 else 00323 m_localtime = m_startframe; 00324 00325 m_flag &= ~ACT_FLAG_LOCKINPUT; 00326 m_flag ^= ACT_FLAG_REVERSE; //flip direction 00327 keepgoing = false; 00328 } 00329 break; 00330 case ACT_ACTION_FLIPPER: 00331 if (wrap){ 00332 if (!(m_flag & ACT_FLAG_REVERSE)){ 00333 m_localtime=m_endframe; 00334 //keepgoing = false; 00335 } 00336 else { 00337 m_localtime=m_startframe; 00338 keepgoing = false; 00339 } 00340 } 00341 break; 00342 case ACT_ACTION_LOOP_END: 00343 if (wrap){ 00344 if (m_flag & ACT_FLAG_KEYUP){ 00345 keepgoing = false; 00346 m_localtime = m_endframe; 00347 m_flag &= ~ACT_FLAG_LOCKINPUT; 00348 } 00349 SetStartTime(curtime); 00350 } 00351 break; 00352 case ACT_ACTION_PLAY: 00353 if (wrap){ 00354 m_localtime = m_endframe; 00355 keepgoing = false; 00356 m_flag &= ~ACT_FLAG_LOCKINPUT; 00357 } 00358 break; 00359 default: 00360 keepgoing = false; 00361 break; 00362 } 00363 00364 /* Set the property if its defined */ 00365 if (m_framepropname[0] != '\0') { 00366 CValue* propowner = GetParent(); 00367 CValue* oldprop = propowner->GetProperty(m_framepropname); 00368 CValue* newval = new CFloatValue(m_localtime); 00369 if (oldprop) { 00370 oldprop->SetValue(newval); 00371 } else { 00372 propowner->SetProperty(m_framepropname, newval); 00373 } 00374 newval->Release(); 00375 } 00376 00377 if (bNegativeEvent) 00378 m_blendframe=0.0; 00379 00380 /* Apply the pose if necessary*/ 00381 if (apply){ 00382 00383 /* Priority test */ 00384 if (obj->SetActiveAction(this, priority, curtime)){ 00385 00386 /* Get the underlying pose from the armature */ 00387 obj->GetPose(&m_pose); 00388 00389 // 2.4x function, 00390 /* Override the necessary channels with ones from the action */ 00391 // XXX extract_pose_from_action(m_pose, m_action, m_localtime); 00392 00393 00394 // 2.5x - replacement for extract_pose_from_action(...) above. 00395 { 00396 struct PointerRNA id_ptr; 00397 Object *arm= obj->GetArmatureObject(); 00398 bPose *pose_back= arm->pose; 00399 00400 arm->pose= m_pose; 00401 RNA_id_pointer_create((ID *)arm, &id_ptr); 00402 animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime); 00403 00404 arm->pose= pose_back; 00405 00406 // 2.5x - could also do this but looks too high level, constraints use this, it works ok. 00407 // Object workob; /* evaluate using workob */ 00408 // what_does_obaction(obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime); 00409 } 00410 00411 // done getting the pose from the action 00412 00413 /* Perform the user override (if any) */ 00414 if (m_userpose){ 00415 extract_pose_from_pose(m_pose, m_userpose); 00416 game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too. 00417 m_userpose = NULL; 00418 } 00419 #if 1 00420 /* Handle blending */ 00421 if (m_blendin && (m_blendframe<m_blendin)){ 00422 /* If this is the start of a blending sequence... */ 00423 if ((m_blendframe==0.0) || (!m_blendpose)){ 00424 obj->GetMRDPose(&m_blendpose); 00425 m_blendstart = curtime; 00426 } 00427 00428 /* Find percentages */ 00429 newweight = (m_blendframe/(float)m_blendin); 00430 game_blend_poses(m_pose, m_blendpose, 1.0 - newweight); 00431 00432 /* Increment current blending percentage */ 00433 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); 00434 if (m_blendframe>m_blendin) 00435 m_blendframe = m_blendin; 00436 00437 } 00438 #endif 00439 m_lastUpdate = m_localtime; 00440 obj->SetPose (m_pose); 00441 } 00442 else{ 00443 m_blendframe = 0.0; 00444 } 00445 } 00446 00447 if (!keepgoing){ 00448 m_blendframe = 0.0; 00449 } 00450 return keepgoing; 00451 }; 00452 00453 #ifdef WITH_PYTHON 00454 00455 /* ------------------------------------------------------------------------- */ 00456 /* Python functions */ 00457 /* ------------------------------------------------------------------------- */ 00458 00459 PyObject* BL_ActionActuator::PyGetChannel(PyObject* value) { 00460 char *string= _PyUnicode_AsString(value); 00461 00462 if (!string) { 00463 PyErr_SetString(PyExc_TypeError, "expected a single string"); 00464 return NULL; 00465 } 00466 00467 bPoseChannel *pchan; 00468 00469 if(m_userpose==NULL && m_pose==NULL) { 00470 BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); 00471 obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ 00472 } 00473 00474 // get_pose_channel accounts for NULL pose, run on both incase one exists but 00475 // the channel doesnt 00476 if( !(pchan=get_pose_channel(m_userpose, string)) && 00477 !(pchan=get_pose_channel(m_pose, string)) ) 00478 { 00479 PyErr_SetString(PyExc_ValueError, "channel doesnt exist"); 00480 return NULL; 00481 } 00482 00483 PyObject *ret = PyTuple_New(3); 00484 00485 PyObject *list = PyList_New(3); 00486 PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->loc[0])); 00487 PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->loc[1])); 00488 PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->loc[2])); 00489 PyTuple_SET_ITEM(ret, 0, list); 00490 00491 list = PyList_New(3); 00492 PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->size[0])); 00493 PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->size[1])); 00494 PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->size[2])); 00495 PyTuple_SET_ITEM(ret, 1, list); 00496 00497 list = PyList_New(4); 00498 PyList_SET_ITEM(list, 0, PyFloat_FromDouble(pchan->quat[0])); 00499 PyList_SET_ITEM(list, 1, PyFloat_FromDouble(pchan->quat[1])); 00500 PyList_SET_ITEM(list, 2, PyFloat_FromDouble(pchan->quat[2])); 00501 PyList_SET_ITEM(list, 3, PyFloat_FromDouble(pchan->quat[3])); 00502 PyTuple_SET_ITEM(ret, 2, list); 00503 00504 return ret; 00505 /* 00506 return Py_BuildValue("([fff][fff][ffff])", 00507 pchan->loc[0], pchan->loc[1], pchan->loc[2], 00508 pchan->size[0], pchan->size[1], pchan->size[2], 00509 pchan->quat[0], pchan->quat[1], pchan->quat[2], pchan->quat[3] ); 00510 */ 00511 } 00512 00513 /* setChannel */ 00514 KX_PYMETHODDEF_DOC(BL_ActionActuator, setChannel, 00515 "setChannel(channel, matrix)\n" 00516 "\t - channel : A string specifying the name of the bone channel.\n" 00517 "\t - matrix : A 4x4 matrix specifying the overriding transformation\n" 00518 "\t as an offset from the bone's rest position.\n") 00519 { 00520 BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); 00521 char *string; 00522 PyObject *pymat= NULL; 00523 PyObject *pyloc= NULL, *pysize= NULL, *pyquat= NULL; 00524 bPoseChannel *pchan; 00525 00526 if(PyTuple_Size(args)==2) { 00527 if (!PyArg_ParseTuple(args,"sO:setChannel", &string, &pymat)) // matrix 00528 return NULL; 00529 } 00530 else if(PyTuple_Size(args)==4) { 00531 if (!PyArg_ParseTuple(args,"sOOO:setChannel", &string, &pyloc, &pysize, &pyquat)) // loc/size/quat 00532 return NULL; 00533 } 00534 else { 00535 PyErr_SetString(PyExc_ValueError, "Expected a string and a 4x4 matrix (2 args) or a string and loc/size/quat sequences (4 args)"); 00536 return NULL; 00537 } 00538 00539 if(pymat) { 00540 float matrix[4][4]; 00541 MT_Matrix4x4 mat; 00542 00543 if(!PyMatTo(pymat, mat)) 00544 return NULL; 00545 00546 mat.getValue((float*)matrix); 00547 00548 BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); 00549 00550 if (!m_userpose) { 00551 if(!m_pose) 00552 obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ 00553 game_copy_pose(&m_userpose, m_pose, 0); 00554 } 00555 // pchan= verify_pose_channel(m_userpose, string); // adds the channel if its not there. 00556 pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. 00557 00558 if(pchan) { 00559 VECCOPY (pchan->loc, matrix[3]); 00560 mat4_to_size( pchan->size,matrix); 00561 mat4_to_quat( pchan->quat,matrix); 00562 } 00563 } 00564 else { 00565 MT_Vector3 loc; 00566 MT_Vector3 size; 00567 MT_Quaternion quat; 00568 00569 if (!PyVecTo(pyloc, loc) || !PyVecTo(pysize, size) || !PyQuatTo(pyquat, quat)) 00570 return NULL; 00571 00572 // same as above 00573 if (!m_userpose) { 00574 if(!m_pose) 00575 obj->GetPose(&m_pose); /* Get the underlying pose from the armature */ 00576 game_copy_pose(&m_userpose, m_pose, 0); 00577 } 00578 // pchan= verify_pose_channel(m_userpose, string); 00579 pchan= get_pose_channel(m_userpose, string); // adds the channel if its not there. 00580 00581 // for some reason loc.setValue(pchan->loc) fails 00582 if(pchan) { 00583 pchan->loc[0]= loc[0]; pchan->loc[1]= loc[1]; pchan->loc[2]= loc[2]; 00584 pchan->size[0]= size[0]; pchan->size[1]= size[1]; pchan->size[2]= size[2]; 00585 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 */ 00586 } 00587 } 00588 00589 if(pchan==NULL) { 00590 PyErr_SetString(PyExc_ValueError, "Channel could not be found, use the 'channelNames' attribute to get a list of valid channels"); 00591 return NULL; 00592 } 00593 00594 Py_RETURN_NONE; 00595 } 00596 00597 /* ------------------------------------------------------------------------- */ 00598 /* Python Integration Hooks */ 00599 /* ------------------------------------------------------------------------- */ 00600 00601 PyTypeObject BL_ActionActuator::Type = { 00602 PyVarObject_HEAD_INIT(NULL, 0) 00603 "BL_ActionActuator", 00604 sizeof(PyObjectPlus_Proxy), 00605 0, 00606 py_base_dealloc, 00607 0, 00608 0, 00609 0, 00610 0, 00611 py_base_repr, 00612 0,0,0,0,0,0,0,0,0, 00613 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 00614 0,0,0,0,0,0,0, 00615 Methods, 00616 0, 00617 0, 00618 &SCA_IActuator::Type, 00619 0,0,0,0,0,0, 00620 py_base_new 00621 }; 00622 00623 PyMethodDef BL_ActionActuator::Methods[] = { 00624 {"getChannel", (PyCFunction) BL_ActionActuator::sPyGetChannel, METH_O}, 00625 KX_PYMETHODTABLE(BL_ActionActuator, setChannel), 00626 {NULL,NULL} //Sentinel 00627 }; 00628 00629 PyAttributeDef BL_ActionActuator::Attributes[] = { 00630 KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ActionActuator, m_startframe), 00631 KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ActionActuator, m_endframe), 00632 KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ActionActuator, m_blendin), 00633 KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ActionActuator, pyattr_get_action, pyattr_set_action), 00634 KX_PYATTRIBUTE_RO_FUNCTION("channelNames", BL_ActionActuator, pyattr_get_channel_names), 00635 KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ActionActuator, m_priority), 00636 KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ActionActuator, m_localtime, CheckFrame), 00637 KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ActionActuator, m_propname), 00638 KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ActionActuator, m_framepropname), 00639 KX_PYATTRIBUTE_BOOL_RW("useContinue", BL_ActionActuator, m_end_reset), 00640 KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ActionActuator, m_blendframe, CheckBlendTime), 00641 KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ActionActuator,m_playtype,CheckType), 00642 { NULL } //Sentinel 00643 }; 00644 00645 PyObject* BL_ActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 00646 { 00647 BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); 00648 return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : ""); 00649 } 00650 00651 int BL_ActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) 00652 { 00653 BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); 00654 00655 if (!PyUnicode_Check(value)) 00656 { 00657 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, expected the string name of the action"); 00658 return PY_SET_ATTR_FAIL; 00659 } 00660 00661 bAction *action= NULL; 00662 STR_String val = _PyUnicode_AsString(value); 00663 00664 if (val != "") 00665 { 00666 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val); 00667 if (!action) 00668 { 00669 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Action Actuator, action not found!"); 00670 return PY_SET_ATTR_FAIL; 00671 } 00672 } 00673 00674 self->SetAction(action); 00675 return PY_SET_ATTR_SUCCESS; 00676 00677 } 00678 00679 PyObject* BL_ActionActuator::pyattr_get_channel_names(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef) 00680 { 00681 BL_ActionActuator* self= static_cast<BL_ActionActuator*>(self_v); 00682 PyObject *ret= PyList_New(0); 00683 PyObject *item; 00684 00685 bPose *pose= ((BL_ArmatureObject*)self->GetParent())->GetOrigPose(); 00686 00687 if(pose) { 00688 bPoseChannel *pchan; 00689 for(pchan= (bPoseChannel *)pose->chanbase.first; pchan; pchan= (bPoseChannel *)pchan->next) { 00690 item= PyUnicode_FromString(pchan->name); 00691 PyList_Append(ret, item); 00692 Py_DECREF(item); 00693 } 00694 } 00695 00696 return ret; 00697 } 00698 00699 #endif // WITH_PYTHON