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