Blender  V2.59
BL_ShapeActionActuator.cpp
Go to the documentation of this file.
00001 /*
00002 * $Id: BL_ShapeActionActuator.cpp 35167 2011-02-25 13:30:41Z jesterking $
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 #if defined (__sgi)
00036 #include <math.h>
00037 #else
00038 #include <cmath>
00039 #endif
00040 
00041 #include "SCA_LogicManager.h"
00042 #include "BL_ShapeActionActuator.h"
00043 #include "BL_ShapeDeformer.h"
00044 #include "KX_GameObject.h"
00045 #include "STR_HashedString.h"
00046 #include "DNA_nla_types.h"
00047 #include "DNA_action_types.h"
00048 #include "DNA_anim_types.h"
00049 #include "DNA_scene_types.h"
00050 #include "BKE_action.h"
00051 #include "DNA_armature_types.h"
00052 #include "MEM_guardedalloc.h"
00053 #include "BLI_blenlib.h"
00054 #include "BLI_math.h"
00055 #include "MT_Matrix4x4.h"
00056 
00057 #include "FloatValue.h"
00058 #include "PyObjectPlus.h"
00059 
00060 extern "C" {
00061         #include "BKE_animsys.h"
00062 }
00063 
00064 BL_ShapeActionActuator::~BL_ShapeActionActuator()
00065 {
00066 }
00067 
00068 void BL_ShapeActionActuator::ProcessReplica()
00069 {
00070         SCA_IActuator::ProcessReplica();
00071         m_localtime=m_startframe;
00072         m_lastUpdate=-1;
00073 }
00074 
00075 void BL_ShapeActionActuator::SetBlendTime (float newtime)
00076 {
00077         m_blendframe = newtime;
00078 }
00079 
00080 CValue* BL_ShapeActionActuator::GetReplica() 
00081 {
00082         BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
00083         replica->ProcessReplica();
00084         return replica;
00085 }
00086 
00087 bool BL_ShapeActionActuator::ClampLocalTime()
00088 {
00089         if (m_startframe < m_endframe)  {
00090                 if (m_localtime < m_startframe)
00091                 {
00092                         m_localtime = m_startframe;
00093                         return true;
00094                 } 
00095                 else if (m_localtime > m_endframe)
00096                 {
00097                         m_localtime = m_endframe;
00098                         return true;
00099                 }
00100         } else {
00101                 if (m_localtime > m_startframe)
00102                 {
00103                         m_localtime = m_startframe;
00104                         return true;
00105                 }
00106                 else if (m_localtime < m_endframe)
00107                 {
00108                         m_localtime = m_endframe;
00109                         return true;
00110                 }
00111         }
00112         return false;
00113 }
00114 
00115 void BL_ShapeActionActuator::SetStartTime(float curtime)
00116 {
00117         float direction = m_startframe < m_endframe ? 1.0 : -1.0;
00118         
00119         if (!(m_flag & ACT_FLAG_REVERSE))
00120                 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
00121         else
00122                 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
00123 }
00124 
00125 void BL_ShapeActionActuator::SetLocalTime(float curtime)
00126 {
00127         float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
00128         
00129         if (m_endframe < m_startframe)
00130                 delta_time = -delta_time;
00131 
00132         if (!(m_flag & ACT_FLAG_REVERSE))
00133                 m_localtime = m_startframe + delta_time;
00134         else
00135                 m_localtime = m_endframe - delta_time;
00136 }
00137 
00138 void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
00139 {
00140         vector<float>::const_iterator it;
00141         float dstweight;
00142         KeyBlock *kb;
00143         
00144         dstweight = 1.0F - srcweight;
00145 
00146         for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
00147                  kb && it != m_blendshape.end(); 
00148                  kb = (KeyBlock*)kb->next, it++) {
00149                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
00150         }
00151 }
00152 
00153 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
00154 {
00155         bool bNegativeEvent = false;
00156         bool bPositiveEvent = false;
00157         bool keepgoing = true;
00158         bool wrap = false;
00159         bool apply=true;
00160         int     priority;
00161         float newweight;
00162 
00163         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
00164         
00165         // result = true if animation has to be continued, false if animation stops
00166         // maybe there are events for us in the queue !
00167         if (frame)
00168         {
00169                 bNegativeEvent = m_negevent;
00170                 bPositiveEvent = m_posevent;
00171                 RemoveAllEvents();
00172                 
00173                 if (bPositiveEvent)
00174                         m_flag |= ACT_FLAG_ACTIVE;
00175                 
00176                 if (bNegativeEvent)
00177                 {
00178                         if (!(m_flag & ACT_FLAG_ACTIVE))
00179                                 return false;
00180                         m_flag &= ~ACT_FLAG_ACTIVE;
00181                 }
00182         }
00183         
00184         /*      This action can only be attached to a deform object */
00185         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)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.0f;
00379         
00380         /* Apply the pose if necessary*/
00381         if (apply) {
00382 
00383                 /* Priority test */
00384                 if (obj->SetActiveAction(this, priority, curtime)){
00385                         Key *key = obj->GetKey();
00386 
00387                         if (!key) {
00388                                 // this could happen if the mesh was changed in the middle of an action
00389                                 // and the new mesh has no key, stop the action
00390                                 keepgoing = false;
00391                         }
00392                         else {
00393                                 ListBase tchanbase= {NULL, NULL};
00394                         
00395                                 if (m_blendin && m_blendframe==0.0f){
00396                                         // this is the start of the blending, remember the startup shape
00397                                         obj->GetShape(m_blendshape);
00398                                         m_blendstart = curtime;
00399                                 }
00400                                 // only interested in shape channel
00401 
00402                                 // in 2.4x was // extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
00403                                 BKE_animsys_evaluate_animdata(&key->id, key->adt, m_localtime, ADT_RECALC_ANIM);
00404 
00405                                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
00406                                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
00407                                         // no update, this is possible if action does not match the keys, stop the action
00408                                         keepgoing = false;
00409                                 } 
00410                                 else {
00411                                         // the key have changed, apply blending if needed
00412                                         if (m_blendin && (m_blendframe<m_blendin)){
00413                                                 newweight = (m_blendframe/(float)m_blendin);
00414 
00415                                                 BlendShape(key, 1.0f - newweight);
00416 
00417                                                 /* Increment current blending percentage */
00418                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
00419                                                 if (m_blendframe>m_blendin)
00420                                                         m_blendframe = m_blendin;
00421                                         }
00422                                         m_lastUpdate = m_localtime;
00423                                 }
00424                                 BLI_freelistN(&tchanbase);
00425                         }
00426                 }
00427                 else{
00428                         m_blendframe = 0.0f;
00429                 }
00430         }
00431         
00432         if (!keepgoing){
00433                 m_blendframe = 0.0f;
00434         }
00435         return keepgoing;
00436 };
00437 
00438 #ifdef WITH_PYTHON
00439 
00440 /* ------------------------------------------------------------------------- */
00441 /* Python functions                                                          */
00442 /* ------------------------------------------------------------------------- */
00443 
00444 /* Integration hooks ------------------------------------------------------- */
00445 
00446 PyTypeObject BL_ShapeActionActuator::Type = {
00447         PyVarObject_HEAD_INIT(NULL, 0)
00448         "BL_ShapeActionActuator",
00449         sizeof(PyObjectPlus_Proxy),
00450         0,
00451         py_base_dealloc,
00452         0,
00453         0,
00454         0,
00455         0,
00456         py_base_repr,
00457         0,0,0,0,0,0,0,0,0,
00458         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00459         0,0,0,0,0,0,0,
00460         Methods,
00461         0,
00462         0,
00463         &SCA_IActuator::Type,
00464         0,0,0,0,0,0,
00465         py_base_new
00466 };
00467 
00468 
00469 PyMethodDef BL_ShapeActionActuator::Methods[] = {
00470         {NULL,NULL} //Sentinel
00471 };
00472 
00473 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
00474         KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
00475         KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
00476         KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
00477         KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
00478         KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
00479         KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
00480         KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname),
00481         KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname),
00482         KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
00483         KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
00484         { NULL }        //Sentinel
00485 };
00486 
00487 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00488 {
00489         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
00490         return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
00491 }
00492 
00493 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00494 {
00495         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
00496         /* exact copy of BL_ActionActuator's function from here down */
00497         if (!PyUnicode_Check(value))
00498         {
00499                 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
00500                 return PY_SET_ATTR_FAIL;
00501         }
00502 
00503         bAction *action= NULL;
00504         STR_String val = _PyUnicode_AsString(value);
00505         
00506         if (val != "")
00507         {
00508                 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
00509                 if (action==NULL)
00510                 {
00511                         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
00512                         return PY_SET_ATTR_FAIL;
00513                 }
00514         }
00515         
00516         self->SetAction(action);
00517         return PY_SET_ATTR_SUCCESS;
00518 
00519 }
00520 
00521 #endif // WITH_PYTHON