800416b5f0ab5b786a5d5a04df5db5aa6cbe602b
[blender.git] / source / gameengine / Ketsji / KX_ConstraintActuator.cpp
1 /**
2  * Apply a constraint to a position or rotation value
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include "SCA_IActuator.h"
33 #include "KX_ConstraintActuator.h"
34 #include "SCA_IObject.h"
35 #include "MT_Point3.h"
36 #include "MT_Matrix3x3.h"
37 #include "KX_GameObject.h"
38 #include "KX_RayCast.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 /* ------------------------------------------------------------------------- */
45 /* Native functions                                                          */
46 /* ------------------------------------------------------------------------- */
47
48 KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, 
49                                                                                          int posDampTime,
50                                                                                          int rotDampTime,
51                                                                                          float minBound,
52                                                                                          float maxBound,
53                                                                                          float refDir[3],
54                                                                                          int locrotxyz,
55                                                                                          int time,
56                                                                                          int option,
57                                                                                          char *property,
58                                                                                          PyTypeObject* T) : 
59         m_refDirection(refDir),
60         m_currentTime(0),
61         SCA_IActuator(gameobj, T)
62 {
63         m_posDampTime = posDampTime;
64         m_rotDampTime = rotDampTime;
65         m_locrot   = locrotxyz;
66         m_option = option;
67         m_activeTime = time;
68         if (property) {
69                 strncpy(m_property, property, sizeof(m_property));
70                 m_property[sizeof(m_property)-1] = 0;
71         } else {
72                 m_property[0] = 0;
73         }
74         /* The units of bounds are determined by the type of constraint. To      */
75         /* make the constraint application easier and more transparent later on, */
76         /* I think converting the bounds to the applicable domain makes more     */
77         /* sense.                                                                */
78         switch (m_locrot) {
79         case KX_ACT_CONSTRAINT_ORIX:
80         case KX_ACT_CONSTRAINT_ORIY:
81         case KX_ACT_CONSTRAINT_ORIZ:
82                 {
83                         MT_Scalar len = m_refDirection.length();
84                         if (MT_fuzzyZero(len)) {
85                                 // missing a valid direction
86                                 std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no valid reference direction!" << std::endl;
87                                 m_locrot = KX_ACT_CONSTRAINT_NODEF;
88                         } else {
89                                 m_refDirection /= len;
90                         }
91                         m_minimumBound = cos(minBound);
92                         m_maximumBound = cos(maxBound);
93                         m_minimumSine = sin(minBound);
94                         m_maximumSine = sin(maxBound);
95                 }
96                 break;
97         default:
98                 m_minimumBound = minBound;
99                 m_maximumBound = maxBound;
100                 m_minimumSine = 0.f;
101                 m_maximumSine = 0.f;
102                 break;
103         }
104
105 } /* End of constructor */
106
107 KX_ConstraintActuator::~KX_ConstraintActuator()
108
109         // there's nothing to be done here, really....
110 } /* end of destructor */
111
112 bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, MT_Point3& hit_point, MT_Vector3& hit_normal, void * const data)
113 {
114
115         KX_GameObject* hitKXObj = client->m_gameobject;
116         
117         if (client->m_type > KX_ClientObjectInfo::ACTOR)
118         {
119                 // false hit
120                 return false;
121         }
122         bool bFound = false;
123
124         if (m_property[0] == 0)
125         {
126                 bFound = true;
127         }
128         else
129         {
130                 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
131                 {
132                         if (client->m_auxilary_info)
133                         {
134                                 bFound = !strcmp(m_property, ((char*)client->m_auxilary_info));
135                         }
136                 }
137                 else
138                 {
139                         bFound = hitKXObj->GetProperty(m_property) != NULL;
140                 }
141         }
142
143         return bFound;
144 }
145
146 bool KX_ConstraintActuator::Update(double curtime, bool frame)
147 {
148
149         bool result = false;    
150         bool bNegativeEvent = IsNegativeEvent();
151         RemoveAllEvents();
152
153         if (!bNegativeEvent) {
154                 /* Constraint clamps the values to the specified range, with a sort of    */
155                 /* low-pass filtered time response, if the damp time is unequal to 0.     */
156
157                 /* Having to retrieve location/rotation and setting it afterwards may not */
158                 /* be efficient enough... Somthing to look at later.                      */
159                 KX_GameObject  *obj = (KX_GameObject*) GetParent();
160                 MT_Point3    position = obj->NodeGetWorldPosition();
161                 MT_Point3    newposition;
162                 MT_Vector3   direction, refDirection;
163                 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
164                 MT_Scalar    filter, newdistance, cosangle;
165                 int axis, sign;
166
167                 if (m_posDampTime) {
168                         filter = m_posDampTime/(1.0+m_posDampTime);
169                 }
170                 switch (m_locrot) {
171                 case KX_ACT_CONSTRAINT_ORIX:
172                 case KX_ACT_CONSTRAINT_ORIY:
173                 case KX_ACT_CONSTRAINT_ORIZ:
174                         switch (m_locrot) {
175                         case KX_ACT_CONSTRAINT_ORIX:
176                                 direction[0] = rotation[0][0];
177                                 direction[1] = rotation[1][0];
178                                 direction[2] = rotation[2][0];
179                                 axis = 0;
180                                 break;
181                         case KX_ACT_CONSTRAINT_ORIY:
182                                 direction[0] = rotation[0][1];
183                                 direction[1] = rotation[1][1];
184                                 direction[2] = rotation[2][1];
185                                 axis = 1;
186                                 break;
187                         default:
188                                 direction[0] = rotation[0][2];
189                                 direction[1] = rotation[1][2];
190                                 direction[2] = rotation[2][2];
191                                 axis = 2;
192                                 break;
193                         }
194                         if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
195                                 // reference direction needs to be evaluated
196                                 // 1. get the cosine between current direction and target
197                                 cosangle = direction.dot(m_refDirection);
198                                 if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
199                                         // no change to do
200                                         result = true;
201                                         goto CHECK_TIME;
202                                 }
203                                 // 2. define a new reference direction
204                                 //    compute local axis with reference direction as X and
205                                 //    Y in direction X refDirection plane
206                                 MT_Vector3 zaxis = m_refDirection.cross(direction);
207                                 if (MT_fuzzyZero2(zaxis.length2())) {
208                                         // direction and refDirection are identical,
209                                         // choose any other direction to define plane
210                                         if (direction[0] < 0.9999)
211                                                 zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0));
212                                         else
213                                                 zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0));
214                                 }
215                                 MT_Vector3 yaxis = zaxis.cross(m_refDirection);
216                                 yaxis.normalize();
217                                 if (cosangle > m_minimumBound) {
218                                         // angle is too close to reference direction,
219                                         // choose a new reference that is exactly at minimum angle
220                                         refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis;
221                                 } else {
222                                         // angle is too large, choose new reference direction at maximum angle
223                                         refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis;
224                                 }
225                         } else {
226                                 refDirection = m_refDirection;
227                         }
228                         if (m_posDampTime) {
229                                 // apply damping on the direction
230                                 direction = filter*direction + (1.0-filter)*refDirection;
231                         } else {
232                                 direction = refDirection;
233                         }
234                         obj->AlignAxisToVect(direction, axis);
235                         result = true;
236                         goto CHECK_TIME;
237                 case KX_ACT_CONSTRAINT_DIRPX:
238                 case KX_ACT_CONSTRAINT_DIRPY:
239                 case KX_ACT_CONSTRAINT_DIRPZ:
240                 case KX_ACT_CONSTRAINT_DIRMX:
241                 case KX_ACT_CONSTRAINT_DIRMY:
242                 case KX_ACT_CONSTRAINT_DIRMZ:
243                         switch (m_locrot) {
244                         case KX_ACT_CONSTRAINT_DIRPX:
245                                 direction[0] = rotation[0][0];
246                                 direction[1] = rotation[1][0];
247                                 direction[2] = rotation[2][0];
248                                 axis = 0;               // axis according to KX_GameObject::AlignAxisToVect()
249                                 sign = 1;               // X axis will be anti parrallel to normal
250                                 break;
251                         case KX_ACT_CONSTRAINT_DIRPY:
252                                 direction[0] = rotation[0][1];
253                                 direction[1] = rotation[1][1];
254                                 direction[2] = rotation[2][1];
255                                 axis = 1;
256                                 sign = 1;
257                                 break;
258                         case KX_ACT_CONSTRAINT_DIRPZ:
259                                 direction[0] = rotation[0][2];
260                                 direction[1] = rotation[1][2];
261                                 direction[2] = rotation[2][2];
262                                 axis = 2;
263                                 sign = 1;
264                                 break;
265                         case KX_ACT_CONSTRAINT_DIRMX:
266                                 direction[0] = -rotation[0][0];
267                                 direction[1] = -rotation[1][0];
268                                 direction[2] = -rotation[2][0];
269                                 axis = 0;
270                                 sign = 0;
271                                 break;
272                         case KX_ACT_CONSTRAINT_DIRMY:
273                                 direction[0] = -rotation[0][1];
274                                 direction[1] = -rotation[1][1];
275                                 direction[2] = -rotation[2][1];
276                                 axis = 1;
277                                 sign = 0;
278                                 break;
279                         case KX_ACT_CONSTRAINT_DIRMZ:
280                                 direction[0] = -rotation[0][2];
281                                 direction[1] = -rotation[1][2];
282                                 direction[2] = -rotation[2][2];
283                                 axis = 2;
284                                 sign = 0;
285                                 break;
286                         }
287                         direction.normalize();
288                         {
289                                 MT_Point3 topoint = position + (m_maximumBound) * direction;
290                                 MT_Point3 resultpoint;
291                                 MT_Vector3 resultnormal;
292                                 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
293                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
294
295                                 if (!pe) {
296                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
297                                         goto CHECK_TIME;
298                                 }        
299                                 if (!spc) {
300                                         // the object is not physical, we probably want to avoid hitting its own parent
301                                         KX_GameObject *parent = obj->GetParent();
302                                         if (parent) {
303                                                 spc = parent->GetPhysicsController();
304                                                 parent->Release();
305                                         }
306                                 }
307                                 result = KX_RayCast::RayTest(spc, pe, position, topoint, resultpoint, resultnormal, KX_RayCast::Callback<KX_ConstraintActuator>(this));
308
309                                 if (result)     {
310                                         // compute new position & orientation
311                                         if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
312                                                 // if none option is set, the actuator does nothing but detect ray 
313                                                 // (works like a sensor)
314                                                 goto CHECK_TIME;
315                                         }
316                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
317                                                 // the new orientation must be so that the axis is parallel to normal
318                                                 if (sign)
319                                                         resultnormal = -resultnormal;
320                                                 // apply damping on the direction
321                                                 if (m_rotDampTime) {
322                                                         MT_Scalar rotFilter = 1.0/(1.0+m_rotDampTime);
323                                                         resultnormal = (-m_rotDampTime*rotFilter)*direction + rotFilter*resultnormal;
324                                                 } else if (m_posDampTime) {
325                                                         resultnormal = -filter*direction + (1.0-filter)*resultnormal;
326                                                 }
327                                                 obj->AlignAxisToVect(resultnormal, axis);
328                                                 direction = -resultnormal;
329                                         }
330                                         if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
331                                                 if (m_posDampTime) {
332                                                         newdistance = filter*(position-resultpoint).length()+(1.0-filter)*m_minimumBound;
333                                                 } else {
334                                                         newdistance = m_minimumBound;
335                                                 }
336                                         } else {
337                                                 newdistance = (position-resultpoint).length();
338                                         }
339                                         newposition = resultpoint-newdistance*direction;
340                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
341                                         // no contact but still keep running
342                                         result = true;
343                                         goto CHECK_TIME;
344                                 }
345                         }
346                         break; 
347                 case KX_ACT_CONSTRAINT_LOCX:
348                 case KX_ACT_CONSTRAINT_LOCY:
349                 case KX_ACT_CONSTRAINT_LOCZ:
350                         newposition = position;
351                         switch (m_locrot) {
352                         case KX_ACT_CONSTRAINT_LOCX:
353                                 Clamp(newposition[0], m_minimumBound, m_maximumBound);
354                                 break;
355                         case KX_ACT_CONSTRAINT_LOCY:
356                                 Clamp(newposition[1], m_minimumBound, m_maximumBound);
357                                 break;
358                         case KX_ACT_CONSTRAINT_LOCZ:
359                                 Clamp(newposition[2], m_minimumBound, m_maximumBound);
360                                 break;
361                         }
362                         result = true;
363                         if (m_posDampTime) {
364                                 newposition = filter*position + (1.0-filter)*newposition;
365                         }
366                         break;
367                 }
368                 if (result) {
369                         // set the new position but take into account parent if any
370                         obj->NodeSetWorldPosition(newposition);
371                 }
372         CHECK_TIME:
373                 if (result && m_activeTime > 0 ) {
374                         if (++m_currentTime >= m_activeTime)
375                                 result = false;
376                 }
377         }
378         if (!result) {
379                 m_currentTime = 0;
380         }
381         return result;
382 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
383
384 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
385                                                                   float min, 
386                                                                   float max) {
387         if (var < min) {
388                 var = min;
389         } else if (var > max) {
390                 var = max;
391         }
392 }
393
394
395 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
396 {
397         bool res = false;
398
399         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
400                 res = true;
401         }
402
403         return res;
404 }
405
406 /* ------------------------------------------------------------------------- */
407 /* Python functions                                                          */
408 /* ------------------------------------------------------------------------- */
409
410 /* Integration hooks ------------------------------------------------------- */
411 PyTypeObject KX_ConstraintActuator::Type = {
412         PyObject_HEAD_INIT(&PyType_Type)
413         0,
414         "KX_ConstraintActuator",
415         sizeof(KX_ConstraintActuator),
416         0,
417         PyDestructor,
418         0,
419         __getattr,
420         __setattr,
421         0, //&MyPyCompare,
422         __repr,
423         0, //&cvalue_as_number,
424         0,
425         0,
426         0,
427         0
428 };
429
430 PyParentObject KX_ConstraintActuator::Parents[] = {
431         &KX_ConstraintActuator::Type,
432         &SCA_IActuator::Type,
433         &SCA_ILogicBrick::Type,
434         &CValue::Type,
435         NULL
436 };
437
438 PyMethodDef KX_ConstraintActuator::Methods[] = {
439         {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
440         {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
441         {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, SetRotDamp_doc},
442         {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_VARARGS, GetRotDamp_doc},
443         {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, SetDirection_doc},
444         {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_VARARGS, GetDirection_doc},
445         {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, SetOption_doc},
446         {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_VARARGS, GetOption_doc},
447         {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, SetTime_doc},
448         {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_VARARGS, GetTime_doc},
449         {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
450         {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
451         {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
452         {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
453         {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetDistance_doc},
454         {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetDistance_doc},
455         {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
456         {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
457         {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetRayLength_doc},
458         {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetRayLength_doc},
459         {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
460         {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
461         {NULL,NULL} //Sentinel
462 };
463
464 PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
465         _getattr_up(SCA_IActuator);
466 }
467
468 /* 2. setDamp                                                                */
469 char KX_ConstraintActuator::SetDamp_doc[] = 
470 "setDamp(duration)\n"
471 "\t- duration: integer\n"
472 "\tSets the time constant of the orientation and distance constraint.\n"
473 "\tIf the duration is negative, it is set to 0.\n";
474 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, 
475                                                                                    PyObject* args, 
476                                                                                    PyObject* kwds) {
477         int dampArg;
478         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
479                 return NULL;            
480         }
481         
482         m_posDampTime = dampArg;
483         if (m_posDampTime < 0) m_posDampTime = 0;
484
485         Py_Return;
486 }
487 /* 3. getDamp                                                                */
488 char KX_ConstraintActuator::GetDamp_doc[] = 
489 "getDamp()\n"
490 "\tReturns the damping parameter.\n";
491 PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self, 
492                                                                                    PyObject* args, 
493                                                                                    PyObject* kwds){
494         return PyInt_FromLong(m_posDampTime);
495 }
496
497 /* 2. setRotDamp                                                                */
498 char KX_ConstraintActuator::SetRotDamp_doc[] = 
499 "setRotDamp(duration)\n"
500 "\t- duration: integer\n"
501 "\tSets the time constant of the orientation constraint.\n"
502 "\tIf the duration is negative, it is set to 0.\n";
503 PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, 
504                                                                                       PyObject* args, 
505                                                                                       PyObject* kwds) {
506         int dampArg;
507         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
508                 return NULL;            
509         }
510         
511         m_rotDampTime = dampArg;
512         if (m_rotDampTime < 0) m_rotDampTime = 0;
513
514         Py_Return;
515 }
516 /* 3. getRotDamp                                                                */
517 char KX_ConstraintActuator::GetRotDamp_doc[] = 
518 "getRotDamp()\n"
519 "\tReturns the damping time for application of the constraint.\n";
520 PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self, 
521                                                                                       PyObject* args, 
522                                                                                       PyObject* kwds){
523         return PyInt_FromLong(m_rotDampTime);
524 }
525
526 /* 2. setDirection                                                                */
527 char KX_ConstraintActuator::SetDirection_doc[] = 
528 "setDirection(vector)\n"
529 "\t- vector: 3-tuple\n"
530 "\tSets the reference direction in world coordinate for the orientation constraint.\n";
531 PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, 
532                                                                                         PyObject* args, 
533                                                                                         PyObject* kwds) {
534         float x, y, z;
535         MT_Scalar len;
536         MT_Vector3 dir;
537
538         if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
539                 return NULL;            
540         }
541         dir[0] = x;
542         dir[1] = y;
543         dir[2] = z;
544         len = dir.length();
545         if (MT_fuzzyZero(len)) {
546                 std::cout << "Invalid direction" << std::endl;
547                 return NULL;
548         }
549         m_refDirection = dir/len;
550
551         Py_Return;
552 }
553 /* 3. getDirection                                                                */
554 char KX_ConstraintActuator::GetDirection_doc[] = 
555 "getDirection()\n"
556 "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
557 PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self, 
558                                                                                         PyObject* args, 
559                                                                                         PyObject* kwds){
560         PyObject *retVal = PyList_New(3);
561
562         PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
563         PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
564         PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
565         return retVal;
566 }
567
568 /* 2. setOption                                                                */
569 char KX_ConstraintActuator::SetOption_doc[] = 
570 "setOption(option)\n"
571 "\t- option: integer\n"
572 "\tSets several options of the distance  constraint.\n"
573 "\tBinary combination of the following values:\n"
574 "\t\t 64 : Activate alignment to surface\n"
575 "\t\t128 : Detect material rather than property\n"
576 "\t\t256 : No deactivation if ray does not hit target\n"
577 "\t\t512 : Activate distance control\n";
578 PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, 
579                                                                                      PyObject* args, 
580                                                                                      PyObject* kwds) {
581         int option;
582         if(!PyArg_ParseTuple(args, "i", &option)) {
583                 return NULL;            
584         }
585         
586         m_option = option;
587
588         Py_Return;
589 }
590 /* 3. getOption                                                              */
591 char KX_ConstraintActuator::GetOption_doc[] = 
592 "getOption()\n"
593 "\tReturns the option parameter.\n";
594 PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self, 
595                                                                                      PyObject* args, 
596                                                                                      PyObject* kwds){
597         return PyInt_FromLong(m_option);
598 }
599
600 /* 2. setTime                                                                */
601 char KX_ConstraintActuator::SetTime_doc[] = 
602 "setTime(duration)\n"
603 "\t- duration: integer\n"
604 "\tSets the activation time of the actuator.\n"
605 "\tThe actuator disables itself after this many frame.\n"
606 "\tIf set to 0 or negative, the actuator is not limited in time.\n";
607 PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, 
608                                                                                    PyObject* args, 
609                                                                                    PyObject* kwds) {
610         int t;
611         if(!PyArg_ParseTuple(args, "i", &t)) {
612                 return NULL;            
613         }
614         
615         if (t < 0)
616                 t = 0;
617         m_activeTime = t;
618
619         Py_Return;
620 }
621 /* 3. getTime                                                                */
622 char KX_ConstraintActuator::GetTime_doc[] = 
623 "getTime()\n"
624 "\tReturns the time parameter.\n";
625 PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self, 
626                                                                                    PyObject* args, 
627                                                                                    PyObject* kwds){
628         return PyInt_FromLong(m_activeTime);
629 }
630
631 /* 2. setProperty                                                                */
632 char KX_ConstraintActuator::SetProperty_doc[] = 
633 "setProperty(property)\n"
634 "\t- property: string\n"
635 "\tSets the name of the property or material for the ray detection of the distance constraint.\n"
636 "\tIf empty, the ray will detect any collisioning object.\n";
637 PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, 
638                                                                                        PyObject* args, 
639                                                                                        PyObject* kwds) {
640         char *property;
641         if (!PyArg_ParseTuple(args, "s", &property)) {
642                 return NULL;
643         }
644         if (property == NULL) {
645                 m_property[0] = 0;
646         } else {
647                 strncpy(m_property, property, sizeof(m_property));
648                 m_property[sizeof(m_property)-1] = 0;
649         }
650
651         Py_Return;
652 }
653 /* 3. getProperty                                                                */
654 char KX_ConstraintActuator::GetProperty_doc[] = 
655 "getProperty()\n"
656 "\tReturns the property parameter.\n";
657 PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self, 
658                                                                                        PyObject* args, 
659                                                                                        PyObject* kwds){
660         return PyString_FromString(m_property);
661 }
662
663 /* 4. setDistance                                                                 */
664 char KX_ConstraintActuator::SetDistance_doc[] = 
665 "setDistance(distance)\n"
666 "\t- distance: float\n"
667 "\tSets the target distance in distance constraint\n";
668 /* 4. setMin                                                                 */
669 char KX_ConstraintActuator::SetMin_doc[] = 
670 "setMin(lower_bound)\n"
671 "\t- lower_bound: float\n"
672 "\tSets the lower value of the interval to which the value\n"
673 "\tis clipped.\n";
674 PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, 
675                                                                                   PyObject* args, 
676                                                                                   PyObject* kwds) {
677         float minArg;
678         if(!PyArg_ParseTuple(args, "f", &minArg)) {
679                 return NULL;            
680         }
681
682         switch (m_locrot) {
683         default:
684                 m_minimumBound = minArg;
685                 break;
686         case KX_ACT_CONSTRAINT_ROTX:
687         case KX_ACT_CONSTRAINT_ROTY:
688         case KX_ACT_CONSTRAINT_ROTZ:
689                 m_minimumBound = MT_radians(minArg);
690                 break;
691         }
692
693         Py_Return;
694 }
695 /* 5. getDistance                                                                 */
696 char KX_ConstraintActuator::GetDistance_doc[] = 
697 "getDistance()\n"
698 "\tReturns the distance parameter \n";
699 /* 5. getMin                                                                 */
700 char KX_ConstraintActuator::GetMin_doc[] = 
701 "getMin()\n"
702 "\tReturns the lower value of the interval to which the value\n"
703 "\tis clipped.\n";
704 PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self, 
705                                                                                   PyObject* args, 
706                                                                                   PyObject* kwds) {
707         return PyFloat_FromDouble(m_minimumBound);
708 }
709
710 /* 6. setRayLength                                                                 */
711 char KX_ConstraintActuator::SetRayLength_doc[] = 
712 "setRayLength(length)\n"
713 "\t- length: float\n"
714 "\tSets the maximum ray length of the distance constraint\n";
715 /* 6. setMax                                                                 */
716 char KX_ConstraintActuator::SetMax_doc[] = 
717 "setMax(upper_bound)\n"
718 "\t- upper_bound: float\n"
719 "\tSets the upper value of the interval to which the value\n"
720 "\tis clipped.\n";
721 PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, 
722                                                                                   PyObject* args, 
723                                                                                   PyObject* kwds){
724         float maxArg;
725         if(!PyArg_ParseTuple(args, "f", &maxArg)) {
726                 return NULL;            
727         }
728
729         switch (m_locrot) {
730         default:
731                 m_maximumBound = maxArg;
732                 break;
733         case KX_ACT_CONSTRAINT_ROTX:
734         case KX_ACT_CONSTRAINT_ROTY:
735         case KX_ACT_CONSTRAINT_ROTZ:
736                 m_maximumBound = MT_radians(maxArg);
737                 break;
738         }
739
740         Py_Return;
741 }
742 /* 7. getRayLength                                                                 */
743 char KX_ConstraintActuator::GetRayLength_doc[] = 
744 "getRayLength()\n"
745 "\tReturns the length of the ray\n";
746 /* 7. getMax                                                                 */
747 char KX_ConstraintActuator::GetMax_doc[] = 
748 "getMax()\n"
749 "\tReturns the upper value of the interval to which the value\n"
750 "\tis clipped.\n";
751 PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self, 
752                                                                                   PyObject* args, 
753                                                                                   PyObject* kwds) {
754         return PyFloat_FromDouble(m_maximumBound);
755 }
756
757
758 /* This setter/getter probably for the constraint type                       */
759 /* 8. setLimit                                                               */
760 char KX_ConstraintActuator::SetLimit_doc[] = 
761 "setLimit(type)\n"
762 "\t- type: integer\n"
763 "\t  1  : LocX\n"
764 "\t  2  : LocY\n"
765 "\t  3  : LocZ\n"
766 "\t  7  : Distance along +X axis\n"
767 "\t  8  : Distance along +Y axis\n"
768 "\t  9  : Distance along +Z axis\n"
769 "\t  10 : Distance along -X axis\n"
770 "\t  11 : Distance along -Y axis\n"
771 "\t  12 : Distance along -Z axis\n"
772 "\t  13 : Align X axis\n"
773 "\t  14 : Align Y axis\n"
774 "\t  15 : Align Z axis\n"
775 "\tSets the type of constraint.\n";
776 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, 
777                                                                                         PyObject* args, 
778                                                                                         PyObject* kwds) {
779         int locrotArg;
780         if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
781                 return NULL;            
782         }
783         
784         if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
785
786         Py_Return;
787 }
788 /* 9. getLimit                                                               */
789 char KX_ConstraintActuator::GetLimit_doc[] = 
790 "getLimit()\n"
791 "\tReturns the type of constraint.\n";
792 PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self, 
793                                                                                         PyObject* args, 
794                                                                                         PyObject* kwds) {
795         return PyInt_FromLong(m_locrot);
796 }
797
798 /* eof */