doxygen: prevent GPL license block from being parsed as doxygen comment.
[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
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_PINGPONG:
230                 if (bPositiveEvent){
231                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
232                                 m_flag &= ~ACT_FLAG_KEYUP;
233                                 m_localtime = m_starttime;
234                                 m_starttime = curtime;
235                                 m_flag |= ACT_FLAG_LOCKINPUT;
236                         }
237                 }
238                 break;
239         case ACT_ACTION_FLIPPER:
240                 if (bPositiveEvent){
241                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
242                                 m_flag &= ~ACT_FLAG_REVERSE;
243                                 m_flag |= ACT_FLAG_LOCKINPUT;
244                                 SetStartTime(curtime);
245                         }
246                 }
247                 else if (bNegativeEvent){
248                         m_flag |= ACT_FLAG_REVERSE;
249                         m_flag &= ~ACT_FLAG_LOCKINPUT;
250                         SetStartTime(curtime);
251                 }
252                 break;
253         case ACT_ACTION_PLAY:
254                 if (bPositiveEvent){
255                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
256                                 m_flag &= ~ACT_FLAG_REVERSE;
257                                 m_localtime = m_starttime;
258                                 m_starttime = curtime;
259                                 m_flag |= ACT_FLAG_LOCKINPUT;
260                         }
261                 }
262                 break;
263         default:
264                 break;
265         }
266         
267         /* Perform increment */
268         if (keepgoing){
269                 if (m_playtype == ACT_ACTION_MOTION){
270                         MT_Point3       newpos;
271                         MT_Point3       deltapos;
272                         
273                         newpos = obj->NodeGetWorldPosition();
274                         
275                         /* Find displacement */
276                         deltapos = newpos-m_lastpos;
277                         m_localtime += (length/m_stridelength) * deltapos.length();
278                         m_lastpos = newpos;
279                 }
280                 else{
281                         SetLocalTime(curtime);
282                 }
283         }
284         
285         /* Check if a wrapping response is needed */
286         if (length){
287                 if (m_localtime < m_startframe || m_localtime > m_endframe)
288                 {
289                         m_localtime = m_startframe + fmod(m_localtime, length);
290                         wrap = true;
291                 }
292         }
293         else
294                 m_localtime = m_startframe;
295         
296         /* Perform post-increment tasks */
297         switch (m_playtype){
298         case ACT_ACTION_FROM_PROP:
299                 {
300                         CValue* propval = GetParent()->GetProperty(m_propname);
301                         if (propval)
302                                 m_localtime = propval->GetNumber();
303                         
304                         if (bNegativeEvent){
305                                 keepgoing=false;
306                         }
307                 }
308                 break;
309         case ACT_ACTION_MOTION:
310                 break;
311         case ACT_ACTION_LOOP_STOP:
312                 break;
313         case ACT_ACTION_PINGPONG:
314                 if (wrap){
315                         if (!(m_flag & ACT_FLAG_REVERSE))
316                                 m_localtime = m_endframe;
317                         else 
318                                 m_localtime = m_startframe;
319
320                         m_flag &= ~ACT_FLAG_LOCKINPUT;
321                         m_flag ^= ACT_FLAG_REVERSE; //flip direction
322                         keepgoing = false;
323                 }
324                 break;
325         case ACT_ACTION_FLIPPER:
326                 if (wrap){
327                         if (!(m_flag & ACT_FLAG_REVERSE)){
328                                 m_localtime=m_endframe;
329                                 //keepgoing = false;
330                         }
331                         else {
332                                 m_localtime=m_startframe;
333                                 keepgoing = false;
334                         }
335                 }
336                 break;
337         case ACT_ACTION_LOOP_END:
338                 if (wrap){
339                         if (m_flag & ACT_FLAG_KEYUP){
340                                 keepgoing = false;
341                                 m_localtime = m_endframe;
342                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
343                         }
344                         SetStartTime(curtime);
345                 }
346                 break;
347         case ACT_ACTION_PLAY:
348                 if (wrap){
349                         m_localtime = m_endframe;
350                         keepgoing = false;
351                         m_flag &= ~ACT_FLAG_LOCKINPUT;
352                 }
353                 break;
354         default:
355                 keepgoing = false;
356                 break;
357         }
358         
359         /* Set the property if its defined */
360         if (m_framepropname[0] != '\0') {
361                 CValue* propowner = GetParent();
362                 CValue* oldprop = propowner->GetProperty(m_framepropname);
363                 CValue* newval = new CFloatValue(m_localtime);
364                 if (oldprop) {
365                         oldprop->SetValue(newval);
366                 } else {
367                         propowner->SetProperty(m_framepropname, newval);
368                 }
369                 newval->Release();
370         }
371         
372         if (bNegativeEvent)
373                 m_blendframe=0.0f;
374         
375         /* Apply the pose if necessary*/
376         if (apply) {
377
378                 /* Priority test */
379                 if (obj->SetActiveAction(this, priority, curtime)){
380                         Key *key = obj->GetKey();
381
382                         if (!key) {
383                                 // this could happen if the mesh was changed in the middle of an action
384                                 // and the new mesh has no key, stop the action
385                                 keepgoing = false;
386                         }
387                         else {
388                                 ListBase tchanbase= {NULL, NULL};
389                         
390                                 if (m_blendin && m_blendframe==0.0f){
391                                         // this is the start of the blending, remember the startup shape
392                                         obj->GetShape(m_blendshape);
393                                         m_blendstart = curtime;
394                                 }
395                                 // only interested in shape channel
396
397                                 // in 2.4x was // extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
398                                 BKE_animsys_evaluate_animdata(&key->id, key->adt, m_localtime, ADT_RECALC_ANIM);
399
400                                 // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell
401                                 if (0) { // XXX !execute_ipochannels(&tchanbase)) {
402                                         // no update, this is possible if action does not match the keys, stop the action
403                                         keepgoing = false;
404                                 } 
405                                 else {
406                                         // the key have changed, apply blending if needed
407                                         if (m_blendin && (m_blendframe<m_blendin)){
408                                                 newweight = (m_blendframe/(float)m_blendin);
409
410                                                 BlendShape(key, 1.0f - newweight);
411
412                                                 /* Increment current blending percentage */
413                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
414                                                 if (m_blendframe>m_blendin)
415                                                         m_blendframe = m_blendin;
416                                         }
417                                         m_lastUpdate = m_localtime;
418                                 }
419                                 BLI_freelistN(&tchanbase);
420                         }
421                 }
422                 else{
423                         m_blendframe = 0.0f;
424                 }
425         }
426         
427         if (!keepgoing){
428                 m_blendframe = 0.0f;
429         }
430         return keepgoing;
431 };
432
433 #ifdef WITH_PYTHON
434
435 /* ------------------------------------------------------------------------- */
436 /* Python functions                                                          */
437 /* ------------------------------------------------------------------------- */
438
439 /* Integration hooks ------------------------------------------------------- */
440
441 PyTypeObject BL_ShapeActionActuator::Type = {
442         PyVarObject_HEAD_INIT(NULL, 0)
443         "BL_ShapeActionActuator",
444         sizeof(PyObjectPlus_Proxy),
445         0,
446         py_base_dealloc,
447         0,
448         0,
449         0,
450         0,
451         py_base_repr,
452         0,0,0,0,0,0,0,0,0,
453         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
454         0,0,0,0,0,0,0,
455         Methods,
456         0,
457         0,
458         &SCA_IActuator::Type,
459         0,0,0,0,0,0,
460         py_base_new
461 };
462
463
464 PyMethodDef BL_ShapeActionActuator::Methods[] = {
465         {NULL,NULL} //Sentinel
466 };
467
468 PyAttributeDef BL_ShapeActionActuator::Attributes[] = {
469         KX_PYATTRIBUTE_FLOAT_RW("frameStart", 0, MAXFRAMEF, BL_ShapeActionActuator, m_startframe),
470         KX_PYATTRIBUTE_FLOAT_RW("frameEnd", 0, MAXFRAMEF, BL_ShapeActionActuator, m_endframe),
471         KX_PYATTRIBUTE_FLOAT_RW("blendIn", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendin),
472         KX_PYATTRIBUTE_RW_FUNCTION("action", BL_ShapeActionActuator, pyattr_get_action, pyattr_set_action),
473         KX_PYATTRIBUTE_SHORT_RW("priority", 0, 100, false, BL_ShapeActionActuator, m_priority),
474         KX_PYATTRIBUTE_FLOAT_RW_CHECK("frame", 0, MAXFRAMEF, BL_ShapeActionActuator, m_localtime, CheckFrame),
475         KX_PYATTRIBUTE_STRING_RW("propName", 0, 31, false, BL_ShapeActionActuator, m_propname),
476         KX_PYATTRIBUTE_STRING_RW("framePropName", 0, 31, false, BL_ShapeActionActuator, m_framepropname),
477         KX_PYATTRIBUTE_FLOAT_RW_CHECK("blendTime", 0, MAXFRAMEF, BL_ShapeActionActuator, m_blendframe, CheckBlendTime),
478         KX_PYATTRIBUTE_SHORT_RW_CHECK("mode",0,100,false,BL_ShapeActionActuator,m_playtype,CheckType),
479         { NULL }        //Sentinel
480 };
481
482 PyObject* BL_ShapeActionActuator::pyattr_get_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
483 {
484         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
485         return PyUnicode_FromString(self->GetAction() ? self->GetAction()->id.name+2 : "");
486 }
487
488 int BL_ShapeActionActuator::pyattr_set_action(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
489 {
490         BL_ShapeActionActuator* self= static_cast<BL_ShapeActionActuator*>(self_v);
491         /* exact copy of BL_ActionActuator's function from here down */
492         if (!PyUnicode_Check(value))
493         {
494                 PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, expected the string name of the action");
495                 return PY_SET_ATTR_FAIL;
496         }
497
498         bAction *action= NULL;
499         STR_String val = _PyUnicode_AsString(value);
500         
501         if (val != "")
502         {
503                 action= (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(val);
504                 if (action==NULL)
505                 {
506                         PyErr_SetString(PyExc_ValueError, "actuator.action = val: Shape Action Actuator, action not found!");
507                         return PY_SET_ATTR_FAIL;
508                 }
509         }
510         
511         self->SetAction(action);
512         return PY_SET_ATTR_SUCCESS;
513
514 }
515
516 #endif // WITH_PYTHON