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