Blender V2.61 - r43446

BL_ShapeActionActuator.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 <cmath>
00034 
00035 #include "SCA_LogicManager.h"
00036 #include "BL_ShapeActionActuator.h"
00037 #include "BL_ShapeDeformer.h"
00038 #include "KX_GameObject.h"
00039 #include "STR_HashedString.h"
00040 #include "DNA_nla_types.h"
00041 #include "DNA_action_types.h"
00042 #include "DNA_anim_types.h"
00043 #include "DNA_scene_types.h"
00044 #include "BKE_action.h"
00045 #include "DNA_armature_types.h"
00046 #include "MEM_guardedalloc.h"
00047 #include "BLI_blenlib.h"
00048 #include "BLI_math.h"
00049 #include "MT_Matrix4x4.h"
00050 
00051 #include "FloatValue.h"
00052 #include "PyObjectPlus.h"
00053 
00054 extern "C" {
00055     #include "BKE_animsys.h"
00056     #include "BKE_key.h"
00057     #include "RNA_access.h"
00058 }
00059 
00060 BL_ShapeActionActuator::BL_ShapeActionActuator(SCA_IObject* gameobj,
00061                     const STR_String& propname,
00062                     const STR_String& framepropname,
00063                     float starttime,
00064                     float endtime,
00065                     struct bAction *action,
00066                     short   playtype,
00067                     short   blendin,
00068                     short   priority,
00069                     float   stride) 
00070     : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION),
00071         
00072     m_lastpos(0, 0, 0),
00073     m_blendframe(0),
00074     m_flag(0),
00075     m_startframe (starttime),
00076     m_endframe(endtime) ,
00077     m_starttime(0),
00078     m_localtime(starttime),
00079     m_lastUpdate(-1),
00080     m_blendin(blendin),
00081     m_blendstart(0),
00082     m_stridelength(stride),
00083     m_playtype(playtype),
00084     m_priority(priority),
00085     m_action(action),
00086     m_framepropname(framepropname), 
00087     m_propname(propname)
00088 {
00089     m_idptr = new PointerRNA();
00090     BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
00091     BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
00092     RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_idptr);
00093 };
00094 
00095 BL_ShapeActionActuator::~BL_ShapeActionActuator()
00096 {
00097     if (m_idptr)
00098         delete m_idptr;
00099 }
00100 
00101 void BL_ShapeActionActuator::ProcessReplica()
00102 {
00103     SCA_IActuator::ProcessReplica();
00104     m_localtime=m_startframe;
00105     m_lastUpdate=-1;
00106 }
00107 
00108 void BL_ShapeActionActuator::SetBlendTime (float newtime)
00109 {
00110     m_blendframe = newtime;
00111 }
00112 
00113 CValue* BL_ShapeActionActuator::GetReplica() 
00114 {
00115     BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
00116     replica->ProcessReplica();
00117     return replica;
00118 }
00119 
00120 bool BL_ShapeActionActuator::ClampLocalTime()
00121 {
00122     if (m_startframe < m_endframe)  {
00123         if (m_localtime < m_startframe)
00124         {
00125             m_localtime = m_startframe;
00126             return true;
00127         } 
00128         else if (m_localtime > m_endframe)
00129         {
00130             m_localtime = m_endframe;
00131             return true;
00132         }
00133     } else {
00134         if (m_localtime > m_startframe)
00135         {
00136             m_localtime = m_startframe;
00137             return true;
00138         }
00139         else if (m_localtime < m_endframe)
00140         {
00141             m_localtime = m_endframe;
00142             return true;
00143         }
00144     }
00145     return false;
00146 }
00147 
00148 void BL_ShapeActionActuator::SetStartTime(float curtime)
00149 {
00150     float direction = m_startframe < m_endframe ? 1.0 : -1.0;
00151     
00152     if (!(m_flag & ACT_FLAG_REVERSE))
00153         m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
00154     else
00155         m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
00156 }
00157 
00158 void BL_ShapeActionActuator::SetLocalTime(float curtime)
00159 {
00160     float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
00161     
00162     if (m_endframe < m_startframe)
00163         delta_time = -delta_time;
00164 
00165     if (!(m_flag & ACT_FLAG_REVERSE))
00166         m_localtime = m_startframe + delta_time;
00167     else
00168         m_localtime = m_endframe - delta_time;
00169 }
00170 
00171 void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
00172 {
00173     vector<float>::const_iterator it;
00174     float dstweight;
00175     KeyBlock *kb;
00176     
00177     dstweight = 1.0F - srcweight;
00178 
00179     for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
00180          kb && it != m_blendshape.end();
00181          kb = (KeyBlock*)kb->next, it++)
00182     {
00183         kb->curval = kb->curval * dstweight + (*it) * srcweight;
00184     }
00185 }
00186 
00187 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
00188 {
00189     bool bNegativeEvent = false;
00190     bool bPositiveEvent = false;
00191     bool keepgoing = true;
00192     bool wrap = false;
00193     bool apply=true;
00194     int priority;
00195     float newweight;
00196 
00197     curtime -= KX_KetsjiEngine::GetSuspendedDelta();
00198     
00199     // result = true if animation has to be continued, false if animation stops
00200     // maybe there are events for us in the queue !
00201     if (frame)
00202     {
00203         bNegativeEvent = m_negevent;
00204         bPositiveEvent = m_posevent;
00205         RemoveAllEvents();
00206         
00207         if (bPositiveEvent)
00208             m_flag |= ACT_FLAG_ACTIVE;
00209         
00210         if (bNegativeEvent)
00211         {
00212             if (!(m_flag & ACT_FLAG_ACTIVE))
00213                 return false;
00214             m_flag &= ~ACT_FLAG_ACTIVE;
00215         }
00216     }
00217     
00218     /*  This action can only be attached to a deform object */
00219     BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
00220     float length = m_endframe - m_startframe;
00221     
00222     priority = m_priority;
00223     
00224     /* Determine pre-incrementation behaviour and set appropriate flags */
00225     switch (m_playtype){
00226     case ACT_ACTION_MOTION:
00227         if (bNegativeEvent){
00228             keepgoing=false;
00229             apply=false;
00230         };
00231         break;
00232     case ACT_ACTION_FROM_PROP:
00233         if (bNegativeEvent){
00234             apply=false;
00235             keepgoing=false;
00236         }
00237         break;
00238     case ACT_ACTION_LOOP_END:
00239         if (bPositiveEvent){
00240             if (!(m_flag & ACT_FLAG_LOCKINPUT)){
00241                 m_flag &= ~ACT_FLAG_KEYUP;
00242                 m_flag &= ~ACT_FLAG_REVERSE;
00243                 m_flag |= ACT_FLAG_LOCKINPUT;
00244                 m_localtime = m_startframe;
00245                 m_starttime = curtime;
00246             }
00247         }
00248         if (bNegativeEvent){
00249             m_flag |= ACT_FLAG_KEYUP;
00250         }
00251         break;
00252     case ACT_ACTION_LOOP_STOP:
00253         if (bPositiveEvent){
00254             if (!(m_flag & ACT_FLAG_LOCKINPUT)){
00255                 m_flag &= ~ACT_FLAG_REVERSE;
00256                 m_flag &= ~ACT_FLAG_KEYUP;
00257                 m_flag |= ACT_FLAG_LOCKINPUT;
00258                 SetStartTime(curtime);
00259             }
00260         }
00261         if (bNegativeEvent){
00262             m_flag |= ACT_FLAG_KEYUP;
00263             m_flag &= ~ACT_FLAG_LOCKINPUT;
00264             keepgoing=false;
00265             apply=false;
00266         }
00267         break;
00268     case ACT_ACTION_PINGPONG:
00269         if (bPositiveEvent){
00270             if (!(m_flag & ACT_FLAG_LOCKINPUT)){
00271                 m_flag &= ~ACT_FLAG_KEYUP;
00272                 m_localtime = m_starttime;
00273                 m_starttime = curtime;
00274                 m_flag |= ACT_FLAG_LOCKINPUT;
00275             }
00276         }
00277         break;
00278     case ACT_ACTION_FLIPPER:
00279         if (bPositiveEvent){
00280             if (!(m_flag & ACT_FLAG_LOCKINPUT)){
00281                 m_flag &= ~ACT_FLAG_REVERSE;
00282                 m_flag |= ACT_FLAG_LOCKINPUT;
00283                 SetStartTime(curtime);
00284             }
00285         }
00286         else if (bNegativeEvent){
00287             m_flag |= ACT_FLAG_REVERSE;
00288             m_flag &= ~ACT_FLAG_LOCKINPUT;
00289             SetStartTime(curtime);
00290         }
00291         break;
00292     case ACT_ACTION_PLAY:
00293         if (bPositiveEvent){
00294             if (!(m_flag & ACT_FLAG_LOCKINPUT)){
00295                 m_flag &= ~ACT_FLAG_REVERSE;
00296                 m_localtime = m_starttime;
00297                 m_starttime = curtime;
00298                 m_flag |= ACT_FLAG_LOCKINPUT;
00299             }
00300         }
00301         break;
00302     default:
00303         break;
00304     }
00305     
00306     /* Perform increment */
00307     if (keepgoing){
00308         if (m_playtype == ACT_ACTION_MOTION){
00309             MT_Point3   newpos;
00310             MT_Point3   deltapos;
00311             
00312             newpos = obj->NodeGetWorldPosition();
00313             
00314             /* Find displacement */
00315             deltapos = newpos-m_lastpos;
00316             m_localtime += (length/m_stridelength) * deltapos.length();
00317             m_lastpos = newpos;
00318         }
00319         else{
00320             SetLocalTime(curtime);
00321         }
00322     }
00323     
00324     /* Check if a wrapping response is needed */
00325     if (length){
00326         if (m_localtime < m_startframe || m_localtime > m_endframe)
00327         {
00328             m_localtime = m_startframe + fmod(m_localtime, length);
00329             wrap = true;
00330         }
00331     }
00332     else
00333         m_localtime = m_startframe;
00334     
00335     /* Perform post-increment tasks */
00336     switch (m_playtype){
00337     case ACT_ACTION_FROM_PROP:
00338         {
00339             CValue* propval = GetParent()->GetProperty(m_propname);
00340             if (propval)
00341                 m_localtime = propval->GetNumber();
00342             
00343             if (bNegativeEvent){
00344                 keepgoing=false;
00345             }
00346         }
00347         break;
00348     case ACT_ACTION_MOTION:
00349         break;
00350     case ACT_ACTION_LOOP_STOP:
00351         break;
00352     case ACT_ACTION_PINGPONG:
00353         if (wrap){
00354             if (!(m_flag & ACT_FLAG_REVERSE))
00355                 m_localtime = m_endframe;
00356             else 
00357                 m_localtime = m_startframe;
00358 
00359             m_flag &= ~ACT_FLAG_LOCKINPUT;
00360             m_flag ^= ACT_FLAG_REVERSE; //flip direction
00361             keepgoing = false;
00362         }
00363         break;
00364     case ACT_ACTION_FLIPPER:
00365         if (wrap){
00366             if (!(m_flag & ACT_FLAG_REVERSE)){
00367                 m_localtime=m_endframe;
00368                 //keepgoing = false;
00369             }
00370             else {
00371                 m_localtime=m_startframe;
00372                 keepgoing = false;
00373             }
00374         }
00375         break;
00376     case ACT_ACTION_LOOP_END:
00377         if (wrap){
00378             if (m_flag & ACT_FLAG_KEYUP){
00379                 keepgoing = false;
00380                 m_localtime = m_endframe;
00381                 m_flag &= ~ACT_FLAG_LOCKINPUT;
00382             }
00383             SetStartTime(curtime);
00384         }
00385         break;
00386     case ACT_ACTION_PLAY:
00387         if (wrap){
00388             m_localtime = m_endframe;
00389             keepgoing = false;
00390             m_flag &= ~ACT_FLAG_LOCKINPUT;
00391         }
00392         break;
00393     default:
00394         keepgoing = false;
00395         break;
00396     }
00397     
00398     /* Set the property if its defined */
00399     if (m_framepropname[0] != '\0') {
00400         CValue* propowner = GetParent();
00401         CValue* oldprop = propowner->GetProperty(m_framepropname);
00402         CValue* newval = new CFloatValue(m_localtime);
00403         if (oldprop) {
00404             oldprop->SetValue(newval);
00405         } else {
00406             propowner->SetProperty(m_framepropname, newval);
00407         }
00408         newval->Release();
00409     }
00410     
00411     if (bNegativeEvent)
00412         m_blendframe=0.0f;
00413     
00414     /* Apply the pose if necessary*/
00415     if (apply) {
00416 
00417         /* Priority test */
00418         if (obj->SetActiveAction(this, priority, curtime)){
00419             BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
00420             Key *key = NULL;
00421 
00422             if (shape_deformer)
00423                 key = shape_deformer->GetKey();
00424 
00425             if (!key) {
00426                 // this could happen if the mesh was changed in the middle of an action
00427                 // and the new mesh has no key, stop the action
00428                 keepgoing = false;
00429             }
00430             else {
00431                 ListBase tchanbase= {NULL, NULL};
00432             
00433                 if (m_blendin && m_blendframe==0.0f){
00434                     // this is the start of the blending, remember the startup shape
00435                     obj->GetShape(m_blendshape);
00436                     m_blendstart = curtime;
00437                 }
00438 
00439                 KeyBlock *kb;
00440                 // We go through and clear out the keyblocks so there isn't any interference
00441                 // from other shape actions
00442                 for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
00443                     kb->curval = 0.f;
00444 
00445                 animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime);
00446 
00447                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
00448                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
00449                     // no update, this is possible if action does not match the keys, stop the action
00450                     keepgoing = false;
00451                 } 
00452                 else {
00453                     // the key have changed, apply blending if needed
00454                     if (m_blendin && (m_blendframe<m_blendin)){
00455                         newweight = (m_blendframe/(float)m_blendin);
00456 
00457                         BlendShape(key, 1.0f - newweight);
00458 
00459                         /* Increment current blending percentage */
00460                         m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
00461                         if (m_blendframe>m_blendin)
00462                             m_blendframe = m_blendin;
00463                     }
00464                     m_lastUpdate = m_localtime;
00465                 }
00466                 BLI_freelistN(&tchanbase);
00467             }
00468         }
00469         else{
00470             m_blendframe = 0.0f;
00471         }
00472     }
00473     
00474     if (!keepgoing){
00475         m_blendframe = 0.0f;
00476     }
00477     return keepgoing;
00478 };
00479 
00480 #ifdef WITH_PYTHON
00481 
00482 /* ------------------------------------------------------------------------- */
00483 /* Python functions                                                          */
00484 /* ------------------------------------------------------------------------- */
00485 
00486 /* Integration hooks ------------------------------------------------------- */
00487 
00488 PyTypeObject BL_ShapeActionActuator::Type = {
00489     PyVarObject_HEAD_INIT(NULL, 0)
00490     "BL_ShapeActionActuator",
00491     sizeof(PyObjectPlus_Proxy),
00492     0,
00493     py_base_dealloc,
00494     0,
00495     0,
00496     0,
00497     0,
00498     py_base_repr,
00499     0,0,0,0,0,0,0,0,0,
00500     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
00501     0,0,0,0,0,0,0,
00502     Methods,
00503     0,
00504     0,
00505     &SCA_IActuator::Type,
00506     0,0,0,0,0,0,
00507     py_base_new
00508 };
00509 
00510 
00511 PyMethodDef BL_ShapeActionActuator::Methods[] = {
00512     {NULL,NULL} //Sentinel
00513 };
00514 
00515 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
00516     KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
00517     KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
00518     KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
00519     KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
00520     KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
00521     KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
00522     KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, BL_ShapeActionActuator, m_propname),
00523     KX_PYATTRIBUTE_STRING_RW("framePropName", 0, MAX_PROP_NAME, false, BL_ShapeActionActuator, m_framepropname),
00524     KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
00525     KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
00526     { NULL }    //Sentinel
00527 };
00528 
00529 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
00530 {
00531     BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
00532     return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
00533 }
00534 
00535 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
00536 {
00537     BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
00538     /* exact copy of BL_ActionActuator's function from here down */
00539     if (!PyUnicode_Check(value))
00540     {
00541         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
00542         return PY_SET_ATTR_FAIL;
00543     }
00544 
00545     bAction *action= NULL;
00546     STR_String val = _PyUnicode_AsString(value);
00547     
00548     if (val != "")
00549     {
00550         action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
00551         if (action==NULL)
00552         {
00553             PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
00554             return PY_SET_ATTR_FAIL;
00555         }
00556     }
00557     
00558     self->SetAction(action);
00559     return PY_SET_ATTR_SUCCESS;
00560 
00561 }
00562 
00563 #endif // WITH_PYTHON