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