synched with trunk at revision 34793
[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 #if defined (__sgi)
31 #include <math.h>
32 #else
33 #include <cmath>
34 #endif
35
36 #include "SCA_LogicManager.h"
37 #include "BL_ShapeActionActuator.h"
38 #include "BL_ShapeDeformer.h"
39 #include "KX_GameObject.h"
40 #include "STR_HashedString.h"
41 #include "DNA_nla_types.h"
42 #include "DNA_action_types.h"
43 #include "DNA_anim_types.h"
44 #include "DNA_scene_types.h"
45 #include "BKE_action.h"
46 #include "DNA_armature_types.h"
47 #include "MEM_guardedalloc.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_math.h"
50 #include "MT_Matrix4x4.h"
51 #include "BKE_utildefines.h"
52 #include "FloatValue.h"
53 #include "PyObjectPlus.h"
54
55 extern "C" {
56         #include "BKE_animsys.h"
57 }
58
59 BL_ShapeActionActuator::~BL_ShapeActionActuator()
60 {
61 }
62
63 void BL_ShapeActionActuator::ProcessReplica()
64 {
65         SCA_IActuator::ProcessReplica();
66         m_localtime=m_startframe;
67         m_lastUpdate=-1;
68 }
69
70 void BL_ShapeActionActuator::SetBlendTime (float newtime)
71 {
72         m_blendframe = newtime;
73 }
74
75 CValue* BL_ShapeActionActuator::GetReplica() 
76 {
77         BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
78         replica->ProcessReplica();
79         return replica;
80 }
81
82 bool BL_ShapeActionActuator::ClampLocalTime()
83 {
84         if (m_startframe < m_endframe)  {
85                 if (m_localtime < m_startframe)
86                 {
87                         m_localtime = m_startframe;
88                         return true;
89                 } 
90                 else if (m_localtime > m_endframe)
91                 {
92                         m_localtime = m_endframe;
93                         return true;
94                 }
95         } else {
96                 if (m_localtime > m_startframe)
97                 {
98                         m_localtime = m_startframe;
99                         return true;
100                 }
101                 else if (m_localtime < m_endframe)
102                 {
103                         m_localtime = m_endframe;
104                         return true;
105                 }
106         }
107         return false;
108 }
109
110 void BL_ShapeActionActuator::SetStartTime(float curtime)
111 {
112         float direction = m_startframe < m_endframe ? 1.0 : -1.0;
113         
114         if (!(m_flag & ACT_FLAG_REVERSE))
115                 m_starttime = curtime - direction*(m_localtime - m_startframe)/KX_KetsjiEngine::GetAnimFrameRate();
116         else
117                 m_starttime = curtime - direction*(m_endframe - m_localtime)/KX_KetsjiEngine::GetAnimFrameRate();
118 }
119
120 void BL_ShapeActionActuator::SetLocalTime(float curtime)
121 {
122         float delta_time = (curtime - m_starttime)*KX_KetsjiEngine::GetAnimFrameRate();
123         
124         if (m_endframe < m_startframe)
125                 delta_time = -delta_time;
126
127         if (!(m_flag & ACT_FLAG_REVERSE))
128                 m_localtime = m_startframe + delta_time;
129         else
130                 m_localtime = m_endframe - delta_time;
131 }
132
133 void BL_ShapeActionActuator::BlendShape(Key* key, float srcweight)
134 {
135         vector<float>::const_iterator it;
136         float dstweight;
137         KeyBlock *kb;
138         
139         dstweight = 1.0F - srcweight;
140
141         for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
142                  kb && it != m_blendshape.end(); 
143                  kb = (KeyBlock*)kb->next, it++) {
144                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
145         }
146 }
147
148 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
149 {
150         bool bNegativeEvent = false;
151         bool bPositiveEvent = false;
152         bool keepgoing = true;
153         bool wrap = false;
154         bool apply=true;
155         int     priority;
156         float newweight;
157
158         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
159         
160         // result = true if animation has to be continued, false if animation stops
161         // maybe there are events for us in the queue !
162         if (frame)
163         {
164                 bNegativeEvent = m_negevent;
165                 bPositiveEvent = m_posevent;
166                 RemoveAllEvents();
167                 
168                 if (bPositiveEvent)
169                         m_flag |= ACT_FLAG_ACTIVE;
170                 
171                 if (bNegativeEvent)
172                 {
173                         if (!(m_flag & ACT_FLAG_ACTIVE))
174                                 return false;
175                         m_flag &= ~ACT_FLAG_ACTIVE;
176                 }
177         }
178         
179         /*      This action can only be attached to a deform object */
180         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
181         float length = m_endframe - m_startframe;
182         
183         priority = m_priority;
184         
185         /* Determine pre-incrementation behaviour and set appropriate flags */
186         switch (m_playtype){
187         case ACT_ACTION_MOTION:
188                 if (bNegativeEvent){
189                         keepgoing=false;
190                         apply=false;
191                 };
192                 break;
193         case ACT_ACTION_FROM_PROP:
194                 if (bNegativeEvent){
195                         apply=false;
196                         keepgoing=false;
197                 }
198                 break;
199         case ACT_ACTION_LOOP_END:
200                 if (bPositiveEvent){
201                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
202                                 m_flag &= ~ACT_FLAG_KEYUP;
203                                 m_flag &= ~ACT_FLAG_REVERSE;
204                                 m_flag |= ACT_FLAG_LOCKINPUT;
205                                 m_localtime = m_startframe;
206                                 m_starttime = curtime;
207                         }
208                 }
209                 if (bNegativeEvent){
210                         m_flag |= ACT_FLAG_KEYUP;
211                 }
212                 break;
213         case ACT_ACTION_LOOP_STOP:
214                 if (bPositiveEvent){
215                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
216                                 m_flag &= ~ACT_FLAG_REVERSE;
217                                 m_flag &= ~ACT_FLAG_KEYUP;
218                                 m_flag |= ACT_FLAG_LOCKINPUT;
219                                 SetStartTime(curtime);
220                         }
221                 }
222                 if (bNegativeEvent){
223                         m_flag |= ACT_FLAG_KEYUP;
224                         m_flag &= ~ACT_FLAG_LOCKINPUT;
225                         keepgoing=false;
226                         apply=false;
227                 }
228                 break;
229         case ACT_ACTION_FLIPPER:
230                 if (bPositiveEvent){
231                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
232                                 m_flag &= ~ACT_FLAG_REVERSE;
233                                 m_flag |= ACT_FLAG_LOCKINPUT;
234                                 SetStartTime(curtime);
235                         }
236                 }
237                 else if (bNegativeEvent){
238                         m_flag |= ACT_FLAG_REVERSE;
239                         m_flag &= ~ACT_FLAG_LOCKINPUT;
240                         SetStartTime(curtime);
241                 }
242                 break;
243         case ACT_ACTION_PLAY:
244                 if (bPositiveEvent){
245                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
246                                 m_flag &= ~ACT_FLAG_REVERSE;
247                                 m_localtime = m_starttime;
248                                 m_starttime = curtime;
249                                 m_flag |= ACT_FLAG_LOCKINPUT;
250                         }
251                 }
252                 break;
253         default:
254                 break;
255         }
256         
257         /* Perform increment */
258         if (keepgoing){
259                 if (m_playtype == ACT_ACTION_MOTION){
260                         MT_Point3       newpos;
261                         MT_Point3       deltapos;
262                         
263                         newpos = obj->NodeGetWorldPosition();
264                         
265                         /* Find displacement */
266                         deltapos = newpos-m_lastpos;
267                         m_localtime += (length/m_stridelength) * deltapos.length();
268                         m_lastpos = newpos;
269                 }
270                 else{
271                         SetLocalTime(curtime);
272                 }
273         }
274         
275         /* Check if a wrapping response is needed */
276         if (length){
277                 if (m_localtime < m_startframe || m_localtime > m_endframe)
278                 {
279                         m_localtime = m_startframe + fmod(m_localtime, length);
280                         wrap = true;
281                 }
282         }
283         else
284                 m_localtime = m_startframe;
285         
286         /* Perform post-increment tasks */
287         switch (m_playtype){
288         case ACT_ACTION_FROM_PROP:
289                 {
290                         CValue* propval = GetParent()->GetProperty(m_propname);
291                         if (propval)
292                                 m_localtime = propval->GetNumber();
293                         
294                         if (bNegativeEvent){
295                                 keepgoing=false;
296                         }
297                 }
298                 break;
299         case ACT_ACTION_MOTION:
300                 break;
301         case ACT_ACTION_LOOP_STOP:
302                 break;
303         case ACT_ACTION_FLIPPER:
304                 if (wrap){
305                         if (!(m_flag & ACT_FLAG_REVERSE)){
306                                 m_localtime=m_endframe;
307                                 //keepgoing = false;
308                         }
309                         else {
310                                 m_localtime=m_startframe;
311                                 keepgoing = false;
312                         }
313                 }
314                 break;
315         case ACT_ACTION_LOOP_END:
316                 if (wrap){
317                         if (m_flag & ACT_FLAG_KEYUP){
318                                 keepgoing = false;
319                                 m_localtime = m_endframe;
320                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
321                         }
322                         SetStartTime(curtime);
323                 }
324                 break;
325         case ACT_ACTION_PLAY:
326                 if (wrap){
327                         m_localtime = m_endframe;
328                         keepgoing = false;
329                         m_flag &= ~ACT_FLAG_LOCKINPUT;
330                 }
331                 break;
332         default:
333                 keepgoing = false;
334                 break;
335         }
336         
337         /* Set the property if its defined */
338         if (m_framepropname[0] != '\0') {
339                 CValue* propowner = GetParent();
340                 CValue* oldprop = propowner->GetProperty(m_framepropname);
341                 CValue* newval = new CFloatValue(m_localtime);
342                 if (oldprop) {
343                         oldprop->SetValue(newval);
344                 } else {
345                         propowner->SetProperty(m_framepropname, newval);
346                 }
347                 newval->Release();
348         }
349         
350         if (bNegativeEvent)
351                 m_blendframe=0.0f;
352         
353         /* Apply the pose if necessary*/
354         if (apply) {
355
356                 /* Priority test */
357                 if (obj->SetActiveAction(this, priority, curtime)){
358                         Key *key = obj->GetKey();
359
360                         if (!key) {
361                                 // this could happen if the mesh was changed in the middle of an action
362                                 // and the new mesh has no key, stop the action
363                                 keepgoing = false;
364                         }
365                         else {
366                                 ListBase tchanbase= {NULL, NULL};
367                         
368                                 if (m_blendin && m_blendframe==0.0f){
369                                         // this is the start of the blending, remember the startup shape
370                                         obj->GetShape(m_blendshape);
371                                         m_blendstart = curtime;
372                                 }
373                                 // only interested in shape channel
374
375                                 // in 2.4x was // extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
376                                 BKE_animsys_evaluate_animdata(&key->id, key->adt, m_localtime, ADT_RECALC_ANIM);
377
378                                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
379                                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
380                                         // no update, this is possible if action does not match the keys, stop the action
381                                         keepgoing = false;
382                                 } 
383                                 else {
384                                         // the key have changed, apply blending if needed
385                                         if (m_blendin && (m_blendframe<m_blendin)){
386                                                 newweight = (m_blendframe/(float)m_blendin);
387
388                                                 BlendShape(key, 1.0f - newweight);
389
390                                                 /* Increment current blending percentage */
391                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
392                                                 if (m_blendframe>m_blendin)
393                                                         m_blendframe = m_blendin;
394                                         }
395                                         m_lastUpdate = m_localtime;
396                                 }
397                                 BLI_freelistN(&tchanbase);
398                         }
399                 }
400                 else{
401                         m_blendframe = 0.0f;
402                 }
403         }
404         
405         if (!keepgoing){
406                 m_blendframe = 0.0f;
407         }
408         return keepgoing;
409 };
410
411 #ifndef DISABLE_PYTHON
412
413 /* ------------------------------------------------------------------------- */
414 /* Python functions                                                          */
415 /* ------------------------------------------------------------------------- */
416
417 /* Integration hooks ------------------------------------------------------- */
418
419 PyTypeObject BL_ShapeActionActuator::Type = {
420         PyVarObject_HEAD_INIT(NULL, 0)
421         "BL_ShapeActionActuator",
422         sizeof(PyObjectPlus_Proxy),
423         0,
424         py_base_dealloc,
425         0,
426         0,
427         0,
428         0,
429         py_base_repr,
430         0,0,0,0,0,0,0,0,0,
431         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
432         0,0,0,0,0,0,0,
433         Methods,
434         0,
435         0,
436         &SCA_IActuator::Type,
437         0,0,0,0,0,0,
438         py_base_new
439 };
440
441
442 PyMethodDef BL_ShapeActionActuator::Methods[] = {
443         {NULL,NULL} //Sentinel
444 };
445
446 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
447         KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
448         KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
449         KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
450         KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
451         KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
452         KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
453         KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname),
454         KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname),
455         KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
456         KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
457         { NULL }        //Sentinel
458 };
459
460 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
461 {
462         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
463         return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
464 }
465
466 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
467 {
468         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
469         /* exact copy of BL_ActionActuator's function from here down */
470         if (!PyUnicode_Check(value))
471         {
472                 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
473                 return PY_SET_ATTR_FAIL;
474         }
475
476         bAction *action= NULL;
477         STR_String val = _PyUnicode_AsString(value);
478         
479         if (val != "")
480         {
481                 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
482                 if (action==NULL)
483                 {
484                         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
485                         return PY_SET_ATTR_FAIL;
486                 }
487         }
488         
489         self->SetAction(action);
490         return PY_SET_ATTR_SUCCESS;
491
492 }
493
494 #endif // DISABLE_PYTHON