Merging trunk up to r39145.
[blender.git] / source / gameengine / Converter / BL_ShapeActionActuator.cpp
1 /*
2 * $Id$
3 *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28 */
29
30 /** \file gameengine/Converter/BL_ShapeActionActuator.cpp
31  *  \ingroup bgeconv
32  */
33
34
35 #if defined (__sgi)
36 #include <math.h>
37 #else
38 #include <cmath>
39 #endif
40
41 #include "SCA_LogicManager.h"
42 #include "BL_ShapeActionActuator.h"
43 #include "BL_ShapeDeformer.h"
44 #include "KX_GameObject.h"
45 #include "STR_HashedString.h"
46 #include "DNA_nla_types.h"
47 #include "DNA_action_types.h"
48 #include "DNA_anim_types.h"
49 #include "DNA_scene_types.h"
50 #include "BKE_action.h"
51 #include "DNA_armature_types.h"
52 #include "MEM_guardedalloc.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_math.h"
55 #include "MT_Matrix4x4.h"
56
57 #include "FloatValue.h"
58 #include "PyObjectPlus.h"
59
60 extern "C" {
61         #include "BKE_animsys.h"
62         #include "BKE_key.h"
63         #include "RNA_access.h"
64 }
65
66 BL_ShapeActionActuator::BL_ShapeActionActuator(SCA_IObject* gameobj,
67                                         const STR_String& propname,
68                                         const STR_String& framepropname,
69                                         float starttime,
70                                         float endtime,
71                                         struct bAction *action,
72                                         short   playtype,
73                                         short   blendin,
74                                         short   priority,
75                                         float   stride) 
76         : SCA_IActuator(gameobj, KX_ACT_SHAPEACTION),
77                 
78         m_lastpos(0, 0, 0),
79         m_blendframe(0),
80         m_flag(0),
81         m_startframe (starttime),
82         m_endframe(endtime) ,
83         m_starttime(0),
84         m_localtime(starttime),
85         m_lastUpdate(-1),
86         m_blendin(blendin),
87         m_blendstart(0),
88         m_stridelength(stride),
89         m_playtype(playtype),
90         m_priority(priority),
91         m_action(action),
92         m_framepropname(framepropname), 
93         m_propname(propname)
94 {
95         m_idptr = new PointerRNA();
96         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
97         BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
98         RNA_id_pointer_create(&shape_deformer->GetKey()->id, m_idptr);
99 };
100
101 BL_ShapeActionActuator::~BL_ShapeActionActuator()
102 {
103         if (m_idptr)
104                 delete m_idptr;
105 }
106
107 void BL_ShapeActionActuator::ProcessReplica()
108 {
109         SCA_IActuator::ProcessReplica();
110         m_localtime=m_startframe;
111         m_lastUpdate=-1;
112 }
113
114 void BL_ShapeActionActuator::SetBlendTime (float newtime)
115 {
116         m_blendframe = newtime;
117 }
118
119 CValue* BL_ShapeActionActuator::GetReplica() 
120 {
121         BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
122         replica->ProcessReplica();
123         return replica;
124 }
125
126 bool BL_ShapeActionActuator::ClampLocalTime()
127 {
128         if (m_startframe < m_endframe)  {
129                 if (m_localtime < m_startframe)
130                 {
131                         m_localtime = m_startframe;
132                         return true;
133                 } 
134                 else if (m_localtime > m_endframe)
135                 {
136                         m_localtime = m_endframe;
137                         return true;
138                 }
139         } else {
140                 if (m_localtime > m_startframe)
141                 {
142                         m_localtime = m_startframe;
143                         return true;
144                 }
145                 else if (m_localtime < m_endframe)
146                 {
147                         m_localtime = m_endframe;
148                         return true;
149                 }
150         }
151         return false;
152 }
153
154 void BL_ShapeActionActuator::SetStartTime(float curtime)
155 {
156         float direction = m_startframe < m_endframe ? 1.0 : -1.0;
157         
158         if (!(m_flag & ACT_FLAG_REVERSE))
159                 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
160         else
161                 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
162 }
163
164 void BL_ShapeActionActuator::SetLocalTime(float curtime)
165 {
166         float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
167         
168         if (m_endframe < m_startframe)
169                 delta_time = -delta_time;
170
171         if (!(m_flag & ACT_FLAG_REVERSE))
172                 m_localtime = m_startframe + delta_time;
173         else
174                 m_localtime = m_endframe - delta_time;
175 }
176
177 void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
178 {
179         vector<float>::const_iterator it;
180         float dstweight;
181         KeyBlock *kb;
182         
183         dstweight = 1.0F - srcweight;
184
185         for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
186                  kb && it != m_blendshape.end(); 
187                  kb = (KeyBlock*)kb->next, it++) {
188                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
189         }
190 }
191
192 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
193 {
194         bool bNegativeEvent = false;
195         bool bPositiveEvent = false;
196         bool keepgoing = true;
197         bool wrap = false;
198         bool apply=true;
199         int     priority;
200         float newweight;
201
202         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
203         
204         // result = true if animation has to be continued, false if animation stops
205         // maybe there are events for us in the queue !
206         if (frame)
207         {
208                 bNegativeEvent = m_negevent;
209                 bPositiveEvent = m_posevent;
210                 RemoveAllEvents();
211                 
212                 if (bPositiveEvent)
213                         m_flag |= ACT_FLAG_ACTIVE;
214                 
215                 if (bNegativeEvent)
216                 {
217                         if (!(m_flag & ACT_FLAG_ACTIVE))
218                                 return false;
219                         m_flag &= ~ACT_FLAG_ACTIVE;
220                 }
221         }
222         
223         /*      This action can only be attached to a deform object */
224         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
225         float length = m_endframe - m_startframe;
226         
227         priority = m_priority;
228         
229         /* Determine pre-incrementation behaviour and set appropriate flags */
230         switch (m_playtype){
231         case ACT_ACTION_MOTION:
232                 if (bNegativeEvent){
233                         keepgoing=false;
234                         apply=false;
235                 };
236                 break;
237         case ACT_ACTION_FROM_PROP:
238                 if (bNegativeEvent){
239                         apply=false;
240                         keepgoing=false;
241                 }
242                 break;
243         case ACT_ACTION_LOOP_END:
244                 if (bPositiveEvent){
245                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
246                                 m_flag &= ~ACT_FLAG_KEYUP;
247                                 m_flag &= ~ACT_FLAG_REVERSE;
248                                 m_flag |= ACT_FLAG_LOCKINPUT;
249                                 m_localtime = m_startframe;
250                                 m_starttime = curtime;
251                         }
252                 }
253                 if (bNegativeEvent){
254                         m_flag |= ACT_FLAG_KEYUP;
255                 }
256                 break;
257         case ACT_ACTION_LOOP_STOP:
258                 if (bPositiveEvent){
259                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
260                                 m_flag &= ~ACT_FLAG_REVERSE;
261                                 m_flag &= ~ACT_FLAG_KEYUP;
262                                 m_flag |= ACT_FLAG_LOCKINPUT;
263                                 SetStartTime(curtime);
264                         }
265                 }
266                 if (bNegativeEvent){
267                         m_flag |= ACT_FLAG_KEYUP;
268                         m_flag &= ~ACT_FLAG_LOCKINPUT;
269                         keepgoing=false;
270                         apply=false;
271                 }
272                 break;
273         case ACT_ACTION_PINGPONG:
274                 if (bPositiveEvent){
275                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
276                                 m_flag &= ~ACT_FLAG_KEYUP;
277                                 m_localtime = m_starttime;
278                                 m_starttime = curtime;
279                                 m_flag |= ACT_FLAG_LOCKINPUT;
280                         }
281                 }
282                 break;
283         case ACT_ACTION_FLIPPER:
284                 if (bPositiveEvent){
285                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
286                                 m_flag &= ~ACT_FLAG_REVERSE;
287                                 m_flag |= ACT_FLAG_LOCKINPUT;
288                                 SetStartTime(curtime);
289                         }
290                 }
291                 else if (bNegativeEvent){
292                         m_flag |= ACT_FLAG_REVERSE;
293                         m_flag &= ~ACT_FLAG_LOCKINPUT;
294                         SetStartTime(curtime);
295                 }
296                 break;
297         case ACT_ACTION_PLAY:
298                 if (bPositiveEvent){
299                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
300                                 m_flag &= ~ACT_FLAG_REVERSE;
301                                 m_localtime = m_starttime;
302                                 m_starttime = curtime;
303                                 m_flag |= ACT_FLAG_LOCKINPUT;
304                         }
305                 }
306                 break;
307         default:
308                 break;
309         }
310         
311         /* Perform increment */
312         if (keepgoing){
313                 if (m_playtype == ACT_ACTION_MOTION){
314                         MT_Point3       newpos;
315                         MT_Point3       deltapos;
316                         
317                         newpos = obj->NodeGetWorldPosition();
318                         
319                         /* Find displacement */
320                         deltapos = newpos-m_lastpos;
321                         m_localtime += (length/m_stridelength) * deltapos.length();
322                         m_lastpos = newpos;
323                 }
324                 else{
325                         SetLocalTime(curtime);
326                 }
327         }
328         
329         /* Check if a wrapping response is needed */
330         if (length){
331                 if (m_localtime < m_startframe || m_localtime > m_endframe)
332                 {
333                         m_localtime = m_startframe + fmod(m_localtime, length);
334                         wrap = true;
335                 }
336         }
337         else
338                 m_localtime = m_startframe;
339         
340         /* Perform post-increment tasks */
341         switch (m_playtype){
342         case ACT_ACTION_FROM_PROP:
343                 {
344                         CValue* propval = GetParent()->GetProperty(m_propname);
345                         if (propval)
346                                 m_localtime = propval->GetNumber();
347                         
348                         if (bNegativeEvent){
349                                 keepgoing=false;
350                         }
351                 }
352                 break;
353         case ACT_ACTION_MOTION:
354                 break;
355         case ACT_ACTION_LOOP_STOP:
356                 break;
357         case ACT_ACTION_PINGPONG:
358                 if (wrap){
359                         if (!(m_flag & ACT_FLAG_REVERSE))
360                                 m_localtime = m_endframe;
361                         else 
362                                 m_localtime = m_startframe;
363
364                         m_flag &= ~ACT_FLAG_LOCKINPUT;
365                         m_flag ^= ACT_FLAG_REVERSE; //flip direction
366                         keepgoing = false;
367                 }
368                 break;
369         case ACT_ACTION_FLIPPER:
370                 if (wrap){
371                         if (!(m_flag & ACT_FLAG_REVERSE)){
372                                 m_localtime=m_endframe;
373                                 //keepgoing = false;
374                         }
375                         else {
376                                 m_localtime=m_startframe;
377                                 keepgoing = false;
378                         }
379                 }
380                 break;
381         case ACT_ACTION_LOOP_END:
382                 if (wrap){
383                         if (m_flag & ACT_FLAG_KEYUP){
384                                 keepgoing = false;
385                                 m_localtime = m_endframe;
386                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
387                         }
388                         SetStartTime(curtime);
389                 }
390                 break;
391         case ACT_ACTION_PLAY:
392                 if (wrap){
393                         m_localtime = m_endframe;
394                         keepgoing = false;
395                         m_flag &= ~ACT_FLAG_LOCKINPUT;
396                 }
397                 break;
398         default:
399                 keepgoing = false;
400                 break;
401         }
402         
403         /* Set the property if its defined */
404         if (m_framepropname[0] != '\0') {
405                 CValue* propowner = GetParent();
406                 CValue* oldprop = propowner->GetProperty(m_framepropname);
407                 CValue* newval = new CFloatValue(m_localtime);
408                 if (oldprop) {
409                         oldprop->SetValue(newval);
410                 } else {
411                         propowner->SetProperty(m_framepropname, newval);
412                 }
413                 newval->Release();
414         }
415         
416         if (bNegativeEvent)
417                 m_blendframe=0.0f;
418         
419         /* Apply the pose if necessary*/
420         if (apply) {
421
422                 /* Priority test */
423                 if (obj->SetActiveAction(this, priority, curtime)){
424                         BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
425                         Key *key = NULL;
426
427                         if (shape_deformer)
428                                 key = shape_deformer->GetKey();
429
430                         if (!key) {
431                                 // this could happen if the mesh was changed in the middle of an action
432                                 // and the new mesh has no key, stop the action
433                                 keepgoing = false;
434                         }
435                         else {
436                                 ListBase tchanbase= {NULL, NULL};
437                         
438                                 if (m_blendin && m_blendframe==0.0f){
439                                         // this is the start of the blending, remember the startup shape
440                                         obj->GetShape(m_blendshape);
441                                         m_blendstart = curtime;
442                                 }
443
444                                 KeyBlock *kb;
445                                 // We go through and clear out the keyblocks so there isn't any interference
446                                 // from other shape actions
447                                 for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
448                                         kb->curval = 0.f;
449
450                                 animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime);
451
452                                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
453                                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
454                                         // no update, this is possible if action does not match the keys, stop the action
455                                         keepgoing = false;
456                                 } 
457                                 else {
458                                         // the key have changed, apply blending if needed
459                                         if (m_blendin && (m_blendframe<m_blendin)){
460                                                 newweight = (m_blendframe/(float)m_blendin);
461
462                                                 BlendShape(key, 1.0f - newweight);
463
464                                                 /* Increment current blending percentage */
465                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
466                                                 if (m_blendframe>m_blendin)
467                                                         m_blendframe = m_blendin;
468                                         }
469                                         m_lastUpdate = m_localtime;
470                                 }
471                                 BLI_freelistN(&tchanbase);
472                         }
473                 }
474                 else{
475                         m_blendframe = 0.0f;
476                 }
477         }
478         
479         if (!keepgoing){
480                 m_blendframe = 0.0f;
481         }
482         return keepgoing;
483 };
484
485 #ifdef WITH_PYTHON
486
487 /* ------------------------------------------------------------------------- */
488 /* Python functions                                                          */
489 /* ------------------------------------------------------------------------- */
490
491 /* Integration hooks ------------------------------------------------------- */
492
493 PyTypeObject BL_ShapeActionActuator::Type = {
494         PyVarObject_HEAD_INIT(NULL, 0)
495         "BL_ShapeActionActuator",
496         sizeof(PyObjectPlus_Proxy),
497         0,
498         py_base_dealloc,
499         0,
500         0,
501         0,
502         0,
503         py_base_repr,
504         0,0,0,0,0,0,0,0,0,
505         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
506         0,0,0,0,0,0,0,
507         Methods,
508         0,
509         0,
510         &SCA_IActuator::Type,
511         0,0,0,0,0,0,
512         py_base_new
513 };
514
515
516 PyMethodDef BL_ShapeActionActuator::Methods[] = {
517         {NULL,NULL} //Sentinel
518 };
519
520 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
521         KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
522         KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
523         KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
524         KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
525         KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
526         KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
527         KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname),
528         KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname),
529         KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
530         KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
531         { NULL }        //Sentinel
532 };
533
534 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
535 {
536         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
537         return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
538 }
539
540 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
541 {
542         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
543         /* exact copy of BL_ActionActuator's function from here down */
544         if (!PyUnicode_Check(value))
545         {
546                 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
547                 return PY_SET_ATTR_FAIL;
548         }
549
550         bAction *action= NULL;
551         STR_String val = _PyUnicode_AsString(value);
552         
553         if (val != "")
554         {
555                 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
556                 if (action==NULL)
557                 {
558                         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
559                         return PY_SET_ATTR_FAIL;
560                 }
561         }
562         
563         self->SetAction(action);
564         return PY_SET_ATTR_SUCCESS;
565
566 }
567
568 #endif // WITH_PYTHON