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