merge with trunk (15330 -> 15566)
[blender.git] / source / gameengine / Converter / BL_ShapeActionActuator.cpp
1 /**
2 * $Id:BL_ShapeActionActuator.cpp 15330 2008-06-23 16:37:51Z theeth $
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_ActionActuator.h"
39 #include "BL_ShapeDeformer.h"
40 #include "KX_GameObject.h"
41 #include "STR_HashedString.h"
42 #include "DNA_action_types.h"
43 #include "DNA_nla_types.h"
44 #include "DNA_actuator_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_arithb.h"
50 #include "MT_Matrix4x4.h"
51 #include "BKE_utildefines.h"
52
53 #ifdef HAVE_CONFIG_H
54 #include <config.h>
55 #endif
56
57 BL_ShapeActionActuator::~BL_ShapeActionActuator()
58 {
59 }
60
61 void BL_ShapeActionActuator::ProcessReplica()
62 {
63         m_localtime=m_startframe;
64         m_lastUpdate=-1;
65 }
66
67 void BL_ShapeActionActuator::SetBlendTime (float newtime)
68 {
69         m_blendframe = newtime;
70 }
71
72 CValue* BL_ShapeActionActuator::GetReplica() 
73 {
74         BL_ShapeActionActuator* replica = new BL_ShapeActionActuator(*this);//m_float,GetName());
75         replica->ProcessReplica();
76         
77         // this will copy properties and so on...
78         CValue::AddDataToReplica(replica);
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         int i;
138         KeyBlock *kb;
139         
140         dstweight = 1.0F - srcweight;
141
142         for (it=m_blendshape.begin(), kb = (KeyBlock*)key->block.first; 
143                  kb && it != m_blendshape.end(); 
144                  kb = (KeyBlock*)kb->next, it++) {
145                 kb->curval = kb->curval * dstweight + (*it) * srcweight;
146         }
147 }
148
149 bool BL_ShapeActionActuator::Update(double curtime, bool frame)
150 {
151         bool bNegativeEvent = false;
152         bool bPositiveEvent = false;
153         bool keepgoing = true;
154         bool wrap = false;
155         bool apply=true;
156         int     priority;
157         float newweight;
158         
159         // result = true if animation has to be continued, false if animation stops
160         // maybe there are events for us in the queue !
161         if (frame)
162         {
163                 for (vector<CValue*>::iterator i=m_events.begin(); !(i==m_events.end());i++)
164                 {
165                         if ((*i)->GetNumber() == 0.0f)
166                                 bNegativeEvent = true;
167                         else
168                                 bPositiveEvent= true;
169                         (*i)->Release();
170                 
171                 }
172                 m_events.clear();
173                 
174                 if (bPositiveEvent)
175                         m_flag |= ACT_FLAG_ACTIVE;
176                 
177                 if (bNegativeEvent)
178                 {
179                         if (!(m_flag & ACT_FLAG_ACTIVE))
180                                 return false;
181                         m_flag &= ~ACT_FLAG_ACTIVE;
182                 }
183         }
184         
185         /*      This action can only be attached to a deform object */
186         BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent();
187         float length = m_endframe - m_startframe;
188         
189         priority = m_priority;
190         
191         /* Determine pre-incrementation behaviour and set appropriate flags */
192         switch (m_playtype){
193         case ACT_ACTION_MOTION:
194                 if (bNegativeEvent){
195                         keepgoing=false;
196                         apply=false;
197                 };
198                 break;
199         case ACT_ACTION_FROM_PROP:
200                 if (bNegativeEvent){
201                         apply=false;
202                         keepgoing=false;
203                 }
204                 break;
205         case ACT_ACTION_LOOP_END:
206                 if (bPositiveEvent){
207                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
208                                 m_flag &= ~ACT_FLAG_KEYUP;
209                                 m_flag &= ~ACT_FLAG_REVERSE;
210                                 m_flag |= ACT_FLAG_LOCKINPUT;
211                                 m_localtime = m_startframe;
212                                 m_starttime = curtime;
213                         }
214                 }
215                 if (bNegativeEvent){
216                         m_flag |= ACT_FLAG_KEYUP;
217                 }
218                 break;
219         case ACT_ACTION_LOOP_STOP:
220                 if (bPositiveEvent){
221                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
222                                 m_flag &= ~ACT_FLAG_REVERSE;
223                                 m_flag &= ~ACT_FLAG_KEYUP;
224                                 m_flag |= ACT_FLAG_LOCKINPUT;
225                                 SetStartTime(curtime);
226                         }
227                 }
228                 if (bNegativeEvent){
229                         m_flag |= ACT_FLAG_KEYUP;
230                         m_flag &= ~ACT_FLAG_LOCKINPUT;
231                         keepgoing=false;
232                         apply=false;
233                 }
234                 break;
235         case ACT_ACTION_FLIPPER:
236                 if (bPositiveEvent){
237                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
238                                 m_flag &= ~ACT_FLAG_REVERSE;
239                                 m_flag |= ACT_FLAG_LOCKINPUT;
240                                 SetStartTime(curtime);
241                         }
242                 }
243                 else if (bNegativeEvent){
244                         m_flag |= ACT_FLAG_REVERSE;
245                         m_flag &= ~ACT_FLAG_LOCKINPUT;
246                         SetStartTime(curtime);
247                 }
248                 break;
249         case ACT_ACTION_PLAY:
250                 if (bPositiveEvent){
251                         if (!(m_flag & ACT_FLAG_LOCKINPUT)){
252                                 m_flag &= ~ACT_FLAG_REVERSE;
253                                 m_localtime = m_starttime;
254                                 m_starttime = curtime;
255                                 m_flag |= ACT_FLAG_LOCKINPUT;
256                         }
257                 }
258                 break;
259         default:
260                 break;
261         }
262         
263         /* Perform increment */
264         if (keepgoing){
265                 if (m_playtype == ACT_ACTION_MOTION){
266                         MT_Point3       newpos;
267                         MT_Point3       deltapos;
268                         
269                         newpos = obj->NodeGetWorldPosition();
270                         
271                         /* Find displacement */
272                         deltapos = newpos-m_lastpos;
273                         m_localtime += (length/m_stridelength) * deltapos.length();
274                         m_lastpos = newpos;
275                 }
276                 else{
277                         SetLocalTime(curtime);
278                 }
279         }
280         
281         /* Check if a wrapping response is needed */
282         if (length){
283                 if (m_localtime < m_startframe || m_localtime > m_endframe)
284                 {
285                         m_localtime = m_startframe + fmod(m_localtime, length);
286                         wrap = true;
287                 }
288         }
289         else
290                 m_localtime = m_startframe;
291         
292         /* Perform post-increment tasks */
293         switch (m_playtype){
294         case ACT_ACTION_FROM_PROP:
295                 {
296                         CValue* propval = GetParent()->GetProperty(m_propname);
297                         if (propval)
298                                 m_localtime = propval->GetNumber();
299                         
300                         if (bNegativeEvent){
301                                 keepgoing=false;
302                         }
303                 }
304                 break;
305         case ACT_ACTION_MOTION:
306                 break;
307         case ACT_ACTION_LOOP_STOP:
308                 break;
309         case ACT_ACTION_FLIPPER:
310                 if (wrap){
311                         if (!(m_flag & ACT_FLAG_REVERSE)){
312                                 m_localtime=m_endframe;
313                                 //keepgoing = false;
314                         }
315                         else {
316                                 m_localtime=m_startframe;
317                                 keepgoing = false;
318                         }
319                 }
320                 break;
321         case ACT_ACTION_LOOP_END:
322                 if (wrap){
323                         if (m_flag & ACT_FLAG_KEYUP){
324                                 keepgoing = false;
325                                 m_localtime = m_endframe;
326                                 m_flag &= ~ACT_FLAG_LOCKINPUT;
327                         }
328                         SetStartTime(curtime);
329                 }
330                 break;
331         case ACT_ACTION_PLAY:
332                 if (wrap){
333                         m_localtime = m_endframe;
334                         keepgoing = false;
335                         m_flag &= ~ACT_FLAG_LOCKINPUT;
336                 }
337                 break;
338         default:
339                 keepgoing = false;
340                 break;
341         }
342         
343         
344         if (bNegativeEvent)
345                 m_blendframe=0.0f;
346         
347         /* Apply the pose if necessary*/
348         if (apply) {
349
350                 /* Priority test */
351                 if (obj->SetActiveAction(this, priority, curtime)){
352                         Key *key = obj->GetKey();
353
354                         if (!key) {
355                                 // this could happen if the mesh was changed in the middle of an action
356                                 // and the new mesh has no key, stop the action
357                                 keepgoing = false;
358                         }
359                         else {
360                                 ListBase tchanbase= {NULL, NULL};
361                         
362                                 if (m_blendin && m_blendframe==0.0f){
363                                         // this is the start of the blending, remember the startup shape
364                                         obj->GetShape(m_blendshape);
365                                         m_blendstart = curtime;
366                                 }
367                                 // only interested in shape channel
368                                 extract_ipochannels_from_action(&tchanbase, &key->id, m_action, "Shape", m_localtime);
369                 
370                                 if (!execute_ipochannels(&tchanbase)) {
371                                         // no update, this is possible if action does not match the keys, stop the action
372                                         keepgoing = false;
373                                 } 
374                                 else {
375                                         // the key have changed, apply blending if needed
376                                         if (m_blendin && (m_blendframe<m_blendin)){
377                                                 newweight = (m_blendframe/(float)m_blendin);
378
379                                                 BlendShape(key, 1.0f - newweight);
380
381                                                 /* Increment current blending percentage */
382                                                 m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate();
383                                                 if (m_blendframe>m_blendin)
384                                                         m_blendframe = m_blendin;
385                                         }
386                                         m_lastUpdate = m_localtime;
387                                 }
388                                 BLI_freelistN(&tchanbase);
389                         }
390                 }
391                 else{
392                         m_blendframe = 0.0f;
393                 }
394         }
395         
396         if (!keepgoing){
397                 m_blendframe = 0.0f;
398         }
399         return keepgoing;
400 };
401
402 /* ------------------------------------------------------------------------- */
403 /* Python functions                                                          */
404 /* ------------------------------------------------------------------------- */
405
406 /* Integration hooks ------------------------------------------------------- */
407
408 PyTypeObject BL_ShapeActionActuator::Type = {
409         PyObject_HEAD_INIT(&PyType_Type)
410                 0,
411                 "BL_ShapeActionActuator",
412                 sizeof(BL_ShapeActionActuator),
413                 0,
414                 PyDestructor,
415                 0,
416                 __getattr,
417                 __setattr,
418                 0, //&MyPyCompare,
419                 __repr,
420                 0, //&cvalue_as_number,
421                 0,
422                 0,
423                 0,
424                 0
425 };
426
427 PyParentObject BL_ShapeActionActuator::Parents[] = {
428         &BL_ShapeActionActuator::Type,
429                 &SCA_IActuator::Type,
430                 &SCA_ILogicBrick::Type,
431                 &CValue::Type,
432                 NULL
433 };
434
435 PyMethodDef BL_ShapeActionActuator::Methods[] = {
436         {"setAction", (PyCFunction) BL_ShapeActionActuator::sPySetAction, METH_VARARGS, SetAction_doc},
437         {"setStart", (PyCFunction) BL_ShapeActionActuator::sPySetStart, METH_VARARGS, SetStart_doc},
438         {"setEnd", (PyCFunction) BL_ShapeActionActuator::sPySetEnd, METH_VARARGS, SetEnd_doc},
439         {"setBlendin", (PyCFunction) BL_ShapeActionActuator::sPySetBlendin, METH_VARARGS, SetBlendin_doc},
440         {"setPriority", (PyCFunction) BL_ShapeActionActuator::sPySetPriority, METH_VARARGS, SetPriority_doc},
441         {"setFrame", (PyCFunction) BL_ShapeActionActuator::sPySetFrame, METH_VARARGS, SetFrame_doc},
442         {"setProperty", (PyCFunction) BL_ShapeActionActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
443         {"setBlendtime", (PyCFunction) BL_ShapeActionActuator::sPySetBlendtime, METH_VARARGS, SetBlendtime_doc},
444
445         {"getAction", (PyCFunction) BL_ShapeActionActuator::sPyGetAction, METH_VARARGS, GetAction_doc},
446         {"getStart", (PyCFunction) BL_ShapeActionActuator::sPyGetStart, METH_VARARGS, GetStart_doc},
447         {"getEnd", (PyCFunction) BL_ShapeActionActuator::sPyGetEnd, METH_VARARGS, GetEnd_doc},
448         {"getBlendin", (PyCFunction) BL_ShapeActionActuator::sPyGetBlendin, METH_VARARGS, GetBlendin_doc},
449         {"getPriority", (PyCFunction) BL_ShapeActionActuator::sPyGetPriority, METH_VARARGS, GetPriority_doc},
450         {"getFrame", (PyCFunction) BL_ShapeActionActuator::sPyGetFrame, METH_VARARGS, GetFrame_doc},
451         {"getProperty", (PyCFunction) BL_ShapeActionActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
452         {"getType", (PyCFunction) BL_ShapeActionActuator::sPyGetType, METH_VARARGS, GetType_doc},       
453         {"setType", (PyCFunction) BL_ShapeActionActuator::sPySetType, METH_VARARGS, SetType_doc},
454         {NULL,NULL} //Sentinel
455 };
456
457 PyObject* BL_ShapeActionActuator::_getattr(const STR_String& attr) {
458         _getattr_up(SCA_IActuator);
459 }
460
461 /*     setStart                                                              */
462 char BL_ShapeActionActuator::GetAction_doc[] = 
463 "getAction()\n"
464 "\tReturns a string containing the name of the current action.\n";
465
466 PyObject* BL_ShapeActionActuator::PyGetAction(PyObject* self, 
467                                                                                           PyObject* args, 
468                                                                                           PyObject* kwds) {
469         PyObject *result;
470         
471         if (m_action){
472                 result = Py_BuildValue("s", m_action->id.name+2);
473         }
474         else{
475                 Py_INCREF(Py_None);
476                 result = Py_None;
477         }
478         
479         return result;
480 }
481
482 /*     getProperty                                                             */
483 char BL_ShapeActionActuator::GetProperty_doc[] = 
484 "getProperty()\n"
485 "\tReturns the name of the property to be used in FromProp mode.\n";
486
487 PyObject* BL_ShapeActionActuator::PyGetProperty(PyObject* self, 
488                                                                                                 PyObject* args, 
489                                                                                                 PyObject* kwds) {
490         PyObject *result;
491         
492         result = Py_BuildValue("s", (const char *)m_propname);
493         
494         return result;
495 }
496
497 /*     getFrame                                                              */
498 char BL_ShapeActionActuator::GetFrame_doc[] = 
499 "getFrame()\n"
500 "\tReturns the current frame number.\n";
501
502 PyObject* BL_ShapeActionActuator::PyGetFrame(PyObject* self, 
503                                                                                          PyObject* args, 
504                                                                                          PyObject* kwds) {
505         PyObject *result;
506         
507         result = Py_BuildValue("f", m_localtime);
508         
509         return result;
510 }
511
512 /*     getEnd                                                                */
513 char BL_ShapeActionActuator::GetEnd_doc[] = 
514 "getEnd()\n"
515 "\tReturns the last frame of the action.\n";
516
517 PyObject* BL_ShapeActionActuator::PyGetEnd(PyObject* self, 
518                                                                                    PyObject* args, 
519                                                                                    PyObject* kwds) {
520         PyObject *result;
521         
522         result = Py_BuildValue("f", m_endframe);
523         
524         return result;
525 }
526
527 /*     getStart                                                              */
528 char BL_ShapeActionActuator::GetStart_doc[] = 
529 "getStart()\n"
530 "\tReturns the starting frame of the action.\n";
531
532 PyObject* BL_ShapeActionActuator::PyGetStart(PyObject* self, 
533                                                                                          PyObject* args, 
534                                                                                          PyObject* kwds) {
535         PyObject *result;
536         
537         result = Py_BuildValue("f", m_startframe);
538         
539         return result;
540 }
541
542 /*     getBlendin                                                            */
543 char BL_ShapeActionActuator::GetBlendin_doc[] = 
544 "getBlendin()\n"
545 "\tReturns the number of interpolation animation frames to be\n"
546 "\tgenerated when this actuator is triggered.\n";
547
548 PyObject* BL_ShapeActionActuator::PyGetBlendin(PyObject* self, 
549                                                                                            PyObject* args, 
550                                                                                            PyObject* kwds) {
551         PyObject *result;
552         
553         result = Py_BuildValue("f", m_blendin);
554         
555         return result;
556 }
557
558 /*     getPriority                                                           */
559 char BL_ShapeActionActuator::GetPriority_doc[] = 
560 "getPriority()\n"
561 "\tReturns the priority for this actuator.  Actuators with lower\n"
562 "\tPriority numbers will override actuators with higher numbers.\n";
563
564 PyObject* BL_ShapeActionActuator::PyGetPriority(PyObject* self, 
565                                                                                             PyObject* args, 
566                                                                                                 PyObject* kwds) {
567         PyObject *result;
568         
569         result = Py_BuildValue("i", m_priority);
570         
571         return result;
572 }
573
574 /*     setAction                                                             */
575 char BL_ShapeActionActuator::SetAction_doc[] = 
576 "setAction(action, (reset))\n"
577 "\t - action    : The name of the action to set as the current action.\n"
578 "\t               Should be an action with Shape channels.\n"
579 "\t - reset     : Optional parameter indicating whether to reset the\n"
580 "\t               blend timer or not.  A value of 1 indicates that the\n"
581 "\t               timer should be reset.  A value of 0 will leave it\n"
582 "\t               unchanged.  If reset is not specified, the timer will"
583 "\t                   be reset.\n";
584
585 PyObject* BL_ShapeActionActuator::PySetAction(PyObject* self, 
586                                                                                           PyObject* args, 
587                                                                                           PyObject* kwds) {
588         char *string;
589         int     reset = 1;
590
591         if (PyArg_ParseTuple(args,"s|i",&string, &reset))
592         {
593                 bAction *action;
594                 
595                 action = (bAction*)SCA_ILogicBrick::m_sCurrentLogicManager->GetActionByName(STR_String(string));
596                 
597                 if (!action){
598                         /* NOTE!  Throw an exception or something */
599                         //                      printf ("setAction failed: Action not found\n", string);
600                 }
601                 else{
602                         m_action=action;
603                         if (reset)
604                                 m_blendframe = 0.f;
605                 }
606         }
607         else {
608                 return NULL;
609         }
610         
611         Py_INCREF(Py_None);
612         return Py_None;
613 }
614
615 /*     setStart                                                              */
616 char BL_ShapeActionActuator::SetStart_doc[] = 
617 "setStart(start)\n"
618 "\t - start     : Specifies the starting frame of the animation.\n";
619
620 PyObject* BL_ShapeActionActuator::PySetStart(PyObject* self, 
621                                                                                          PyObject* args, 
622                                                                                          PyObject* kwds) {
623         float start;
624         
625         if (PyArg_ParseTuple(args,"f",&start))
626         {
627                 m_startframe = start;
628         }
629         else {
630                 return NULL;
631         }
632         
633         Py_INCREF(Py_None);
634         return Py_None;
635 }
636
637 /*     setEnd                                                                */
638 char BL_ShapeActionActuator::SetEnd_doc[] = 
639 "setEnd(end)\n"
640 "\t - end       : Specifies the ending frame of the animation.\n";
641
642 PyObject* BL_ShapeActionActuator::PySetEnd(PyObject* self, 
643                                                                                    PyObject* args, 
644                                                                                    PyObject* kwds) {
645         float end;
646         
647         if (PyArg_ParseTuple(args,"f",&end))
648         {
649                 m_endframe = end;
650         }
651         else {
652                 return NULL;
653         }
654         
655         Py_INCREF(Py_None);
656         return Py_None;
657 }
658
659 /*     setBlendin                                                            */
660 char BL_ShapeActionActuator::SetBlendin_doc[] = 
661 "setBlendin(blendin)\n"
662 "\t - blendin   : Specifies the number of frames of animation to generate\n"
663 "\t               when making transitions between actions.\n";
664
665 PyObject* BL_ShapeActionActuator::PySetBlendin(PyObject* self, 
666                                                                                            PyObject* args, 
667                                                                                            PyObject* kwds) {
668         float blendin;
669         
670         if (PyArg_ParseTuple(args,"f",&blendin))
671         {
672                 m_blendin = blendin;
673         }
674         else {
675                 return NULL;
676         }
677         
678         Py_INCREF(Py_None);
679         return Py_None;
680 }
681
682 /*     setBlendtime                                                          */
683 char BL_ShapeActionActuator::SetBlendtime_doc[] = 
684 "setBlendtime(blendtime)\n"
685 "\t - blendtime : Allows the script to directly modify the internal timer\n"
686 "\t               used when generating transitions between actions.  This\n"
687 "\t               parameter must be in the range from 0.0 to 1.0.\n";
688
689 PyObject* BL_ShapeActionActuator::PySetBlendtime(PyObject* self, 
690                                                                                                  PyObject* args, 
691                                                                                                    PyObject* kwds) {
692         float blendframe;
693         
694         if (PyArg_ParseTuple(args,"f",&blendframe))
695         {
696                 m_blendframe = blendframe * m_blendin;
697                 if (m_blendframe<0.f)
698                         m_blendframe = 0.f;
699                 if (m_blendframe>m_blendin)
700                         m_blendframe = m_blendin;
701         }
702         else {
703                 return NULL;
704         }
705         
706         Py_INCREF(Py_None);
707         return Py_None;
708 }
709
710 /*     setPriority                                                           */
711 char BL_ShapeActionActuator::SetPriority_doc[] = 
712 "setPriority(priority)\n"
713 "\t - priority  : Specifies the new priority.  Actuators will lower\n"
714 "\t               priority numbers will override actuators with higher\n"
715 "\t               numbers.\n";
716
717 PyObject* BL_ShapeActionActuator::PySetPriority(PyObject* self, 
718                                                                                                 PyObject* args, 
719                                                                                                 PyObject* kwds) {
720         int priority;
721         
722         if (PyArg_ParseTuple(args,"i",&priority))
723         {
724                 m_priority = priority;
725         }
726         else {
727                 return NULL;
728         }
729         
730         Py_INCREF(Py_None);
731         return Py_None;
732 }
733
734 /*     setFrame                                                              */
735 char BL_ShapeActionActuator::SetFrame_doc[] = 
736 "setFrame(frame)\n"
737 "\t - frame     : Specifies the new current frame for the animation\n";
738
739 PyObject* BL_ShapeActionActuator::PySetFrame(PyObject* self, 
740                                                                                          PyObject* args, 
741                                                                                          PyObject* kwds) {
742         float frame;
743         
744         if (PyArg_ParseTuple(args,"f",&frame))
745         {
746                 m_localtime = frame;
747                 if (m_localtime<m_startframe)
748                         m_localtime=m_startframe;
749                 else if (m_localtime>m_endframe)
750                         m_localtime=m_endframe;
751         }
752         else {
753                 return NULL;
754         }
755         
756         Py_INCREF(Py_None);
757         return Py_None;
758 }
759
760 /*     setProperty                                                           */
761 char BL_ShapeActionActuator::SetProperty_doc[] = 
762 "setProperty(prop)\n"
763 "\t - prop      : A string specifying the property name to be used in\n"
764 "\t               FromProp playback mode.\n";
765
766 PyObject* BL_ShapeActionActuator::PySetProperty(PyObject* self, 
767                                                                                                 PyObject* args, 
768                                                                                                 PyObject* kwds) {
769         char *string;
770         
771         if (PyArg_ParseTuple(args,"s",&string))
772         {
773                 m_propname = string;
774         }
775         else {
776                 return NULL;
777         }
778         
779         Py_INCREF(Py_None);
780         return Py_None;
781 }
782
783 /* getType */
784 char BL_ShapeActionActuator::GetType_doc[] =
785 "getType()\n"
786 "\tReturns the operation mode of the actuator.\n";
787 PyObject* BL_ShapeActionActuator::PyGetType(PyObject* self,
788                                                                                         PyObject* args, 
789                                                                                         PyObject* kwds) {
790     return Py_BuildValue("h", m_playtype);
791 }
792
793 /* setType */
794 char BL_ShapeActionActuator::SetType_doc[] =
795 "setType(mode)\n"
796 "\t - mode: Play (0), Flipper (2), LoopStop (3), LoopEnd (4) or Property (6)\n"
797 "\tSet the operation mode of the actuator.\n";
798 PyObject* BL_ShapeActionActuator::PySetType(PyObject* self,
799                                             PyObject* args,
800                                             PyObject* kwds) {
801         short typeArg;
802                                                                                                              
803     if (!PyArg_ParseTuple(args, "h", &typeArg)) {
804         return NULL;
805     }
806
807         switch (typeArg) {
808         case ACT_ACTION_PLAY:
809         case ACT_ACTION_FLIPPER:
810         case ACT_ACTION_LOOP_STOP:
811         case ACT_ACTION_LOOP_END:
812         case ACT_ACTION_FROM_PROP:
813                 m_playtype = typeArg;
814                 break;
815         default:
816                 printf("Invalid type for action actuator: %d\n", typeArg); /* error */
817     }
818         
819     Py_Return;
820 }
821