correct indentation and some whitespace edits (no functional changes)
[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         {
183                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
184         }
185 }
186
187 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
188 {
189         bool bNegativeEvent = false;
190         bool bPositiveEvent = false;
191         bool keepgoing = true;
192         bool wrap = false;
193         bool apply=true;
194         int     priority;
195         float newweight;
196
197         curtime -= KX_KetsjiEngine::GetSuspendedDelta();
198         
199         // result = true if animation has to be continued, false if animation stops
200         // maybe there are events for us in the queue !
201         if (frame)
202         {
203                 bNegativeEvent = m_negevent;
204                 bPositiveEvent = m_posevent;
205                 RemoveAllEvents();
206                 
207                 if (bPositiveEvent)
208                         m_flag |= ACT_FLAG_ACTIVE;
209                 
210                 if (bNegativeEvent)
211                 {
212                         if (!(m_flag & ACT_FLAG_ACTIVE))
213                                 return false;
214                         m_flag &= ~ACT_FLAG_ACTIVE;
215                 }
216         }
217         
218         /*      This action can only be attached to a deform object */
219         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
220         float length = m_endframe - m_startframe;
221         
222         priority = m_priority;
223         
224         /* Determine pre-incrementation behaviour and set appropriate flags */
225         switch (m_playtype){
226         case ACT_ACTION_MOTION:
227                 if (bNegativeEvent){
228                         keepgoing=false;
229                         apply=false;
230                 };
231                 break;
232         case ACT_ACTION_FROM_PROP:
233                 if (bNegativeEvent){
234                         apply=false;
235                         keepgoing=false;
236                 }
237                 break;
238         case ACT_ACTION_LOOP_END:
239                 if (bPositiveEvent){
240                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
241                                 m_flag &= ~ACT_FLAG_KEYUP;
242                                 m_flag &= ~ACT_FLAG_REVERSE;
243                                 m_flag |= ACT_FLAG_LOCKINPUT;
244                                 m_localtime = m_startframe;
245                                 m_starttime = curtime;
246                         }
247                 }
248                 if (bNegativeEvent){
249                         m_flag |= ACT_FLAG_KEYUP;
250                 }
251                 break;
252         case ACT_ACTION_LOOP_STOP:
253                 if (bPositiveEvent){
254                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
255                                 m_flag &= ~ACT_FLAG_REVERSE;
256                                 m_flag &= ~ACT_FLAG_KEYUP;
257                                 m_flag |= ACT_FLAG_LOCKINPUT;
258                                 SetStartTime(curtime);
259                         }
260                 }
261                 if (bNegativeEvent){
262                         m_flag |= ACT_FLAG_KEYUP;
263                         m_flag &= ~ACT_FLAG_LOCKINPUT;
264                         keepgoing=false;
265                         apply=false;
266                 }
267                 break;
268         case ACT_ACTION_PINGPONG:
269                 if (bPositiveEvent){
270                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
271                                 m_flag &= ~ACT_FLAG_KEYUP;
272                                 m_localtime = m_starttime;
273                                 m_starttime = curtime;
274                                 m_flag |= ACT_FLAG_LOCKINPUT;
275                         }
276                 }
277                 break;
278         case ACT_ACTION_FLIPPER:
279                 if (bPositiveEvent){
280                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
281                                 m_flag &= ~ACT_FLAG_REVERSE;
282                                 m_flag |= ACT_FLAG_LOCKINPUT;
283                                 SetStartTime(curtime);
284                         }
285                 }
286                 else if (bNegativeEvent){
287                         m_flag |= ACT_FLAG_REVERSE;
288                         m_flag &= ~ACT_FLAG_LOCKINPUT;
289                         SetStartTime(curtime);
290                 }
291                 break;
292         case ACT_ACTION_PLAY:
293                 if (bPositiveEvent){
294                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
295                                 m_flag &= ~ACT_FLAG_REVERSE;
296                                 m_localtime = m_starttime;
297                                 m_starttime = curtime;
298                                 m_flag |= ACT_FLAG_LOCKINPUT;
299                         }
300                 }
301                 break;
302         default:
303                 break;
304         }
305         
306         /* Perform increment */
307         if (keepgoing){
308                 if (m_playtype == ACT_ACTION_MOTION){
309                         MT_Point3       newpos;
310                         MT_Point3       deltapos;
311                         
312                         newpos = obj->NodeGetWorldPosition();
313                         
314                         /* Find displacement */
315                         deltapos = newpos-m_lastpos;
316                         m_localtime += (length/m_stridelength) * deltapos.length();
317                         m_lastpos = newpos;
318                 }
319                 else{
320                         SetLocalTime(curtime);
321                 }
322         }
323         
324         /* Check if a wrapping response is needed */
325         if (length){
326                 if (m_localtime < m_startframe || m_localtime > m_endframe)
327                 {
328                         m_localtime = m_startframe + fmod(m_localtime, length);
329                         wrap = true;
330                 }
331         }
332         else
333                 m_localtime = m_startframe;
334         
335         /* Perform post-increment tasks */
336         switch (m_playtype){
337         case ACT_ACTION_FROM_PROP:
338                 {
339                         CValue* propval = GetParent()->GetProperty(m_propname);
340                         if (propval)
341                                 m_localtime = propval->GetNumber();
342                         
343                         if (bNegativeEvent){
344                                 keepgoing=false;
345                         }
346                 }
347                 break;
348         case ACT_ACTION_MOTION:
349                 break;
350         case ACT_ACTION_LOOP_STOP:
351                 break;
352         case ACT_ACTION_PINGPONG:
353                 if (wrap){
354                         if (!(m_flag & ACT_FLAG_REVERSE))
355                                 m_localtime = m_endframe;
356                         else 
357                                 m_localtime = m_startframe;
358
359                         m_flag &= ~ACT_FLAG_LOCKINPUT;
360                         m_flag ^= ACT_FLAG_REVERSE; //flip direction
361                         keepgoing = false;
362                 }
363                 break;
364         case ACT_ACTION_FLIPPER:
365                 if (wrap){
366                         if (!(m_flag & ACT_FLAG_REVERSE)){
367                                 m_localtime=m_endframe;
368                                 //keepgoing = false;
369                         }
370                         else {
371                                 m_localtime=m_startframe;
372                                 keepgoing = false;
373                         }
374                 }
375                 break;
376         case ACT_ACTION_LOOP_END:
377                 if (wrap){
378                         if (m_flag & ACT_FLAG_KEYUP){
379                                 keepgoing = false;
380                                 m_localtime = m_endframe;
381                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
382                         }
383                         SetStartTime(curtime);
384                 }
385                 break;
386         case ACT_ACTION_PLAY:
387                 if (wrap){
388                         m_localtime = m_endframe;
389                         keepgoing = false;
390                         m_flag &= ~ACT_FLAG_LOCKINPUT;
391                 }
392                 break;
393         default:
394                 keepgoing = false;
395                 break;
396         }
397         
398         /* Set the property if its defined */
399         if (m_framepropname[0] != '\0') {
400                 CValue* propowner = GetParent();
401                 CValue* oldprop = propowner->GetProperty(m_framepropname);
402                 CValue* newval = new CFloatValue(m_localtime);
403                 if (oldprop) {
404                         oldprop->SetValue(newval);
405                 } else {
406                         propowner->SetProperty(m_framepropname, newval);
407                 }
408                 newval->Release();
409         }
410         
411         if (bNegativeEvent)
412                 m_blendframe=0.0f;
413         
414         /* Apply the pose if necessary*/
415         if (apply) {
416
417                 /* Priority test */
418                 if (obj->SetActiveAction(this, priority, curtime)){
419                         BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer());
420                         Key *key = NULL;
421
422                         if (shape_deformer)
423                                 key = shape_deformer->GetKey();
424
425                         if (!key) {
426                                 // this could happen if the mesh was changed in the middle of an action
427                                 // and the new mesh has no key, stop the action
428                                 keepgoing = false;
429                         }
430                         else {
431                                 ListBase tchanbase= {NULL, NULL};
432                         
433                                 if (m_blendin && m_blendframe==0.0f){
434                                         // this is the start of the blending, remember the startup shape
435                                         obj->GetShape(m_blendshape);
436                                         m_blendstart = curtime;
437                                 }
438
439                                 KeyBlock *kb;
440                                 // We go through and clear out the keyblocks so there isn't any interference
441                                 // from other shape actions
442                                 for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next)
443                                         kb->curval = 0.f;
444
445                                 animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime);
446
447                                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
448                                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
449                                         // no update, this is possible if action does not match the keys, stop the action
450                                         keepgoing = false;
451                                 } 
452                                 else {
453                                         // the key have changed, apply blending if needed
454                                         if (m_blendin && (m_blendframe<m_blendin)){
455                                                 newweight = (m_blendframe/(float)m_blendin);
456
457                                                 BlendShape(key, 1.0f - newweight);
458
459                                                 /* Increment current blending percentage */
460                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
461                                                 if (m_blendframe>m_blendin)
462                                                         m_blendframe = m_blendin;
463                                         }
464                                         m_lastUpdate = m_localtime;
465                                 }
466                                 BLI_freelistN(&tchanbase);
467                         }
468                 }
469                 else{
470                         m_blendframe = 0.0f;
471                 }
472         }
473         
474         if (!keepgoing){
475                 m_blendframe = 0.0f;
476         }
477         return keepgoing;
478 };
479
480 #ifdef WITH_PYTHON
481
482 /* ------------------------------------------------------------------------- */
483 /* Python functions                                                          */
484 /* ------------------------------------------------------------------------- */
485
486 /* Integration hooks ------------------------------------------------------- */
487
488 PyTypeObject BL_ShapeActionActuator::Type = {
489         PyVarObject_HEAD_INIT(NULL, 0)
490         "BL_ShapeActionActuator",
491         sizeof(PyObjectPlus_Proxy),
492         0,
493         py_base_dealloc,
494         0,
495         0,
496         0,
497         0,
498         py_base_repr,
499         0,0,0,0,0,0,0,0,0,
500         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
501         0,0,0,0,0,0,0,
502         Methods,
503         0,
504         0,
505         &SCA_IActuator::Type,
506         0,0,0,0,0,0,
507         py_base_new
508 };
509
510
511 PyMethodDef BL_ShapeActionActuator::Methods[] = {
512         {NULL,NULL} //Sentinel
513 };
514
515 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
516         KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
517         KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
518         KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
519         KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
520         KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
521         KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
522         KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname),
523         KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname),
524         KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
525         KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
526         { NULL }        //Sentinel
527 };
528
529 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
530 {
531         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
532         return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
533 }
534
535 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
536 {
537         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
538         /* exact copy of BL_ActionActuator's function from here down */
539         if (!PyUnicode_Check(value))
540         {
541                 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
542                 return PY_SET_ATTR_FAIL;
543         }
544
545         bAction *action= NULL;
546         STR_String val = _PyUnicode_AsString(value);
547         
548         if (val != "")
549         {
550                 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
551                 if (action==NULL)
552                 {
553                         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
554                         return PY_SET_ATTR_FAIL;
555                 }
556         }
557         
558         self->SetAction(action);
559         return PY_SET_ATTR_SUCCESS;
560
561 }
562
563 #endif // WITH_PYTHON