BGE patch: local/global flag to distance contraint actuator.
[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, KX_RayCast* result, void * const data)
113 {
114
115         KX_GameObject* hitKXObj = client->m_gameobject;
116         
117         bool bFound = false;
118
119         if (m_property[0] == 0)
120         {
121                 bFound = true;
122         }
123         else
124         {
125                 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
126                 {
127                         if (client->m_auxilary_info)
128                         {
129                                 bFound = !strcmp(m_property, ((char*)client->m_auxilary_info));
130                         }
131                 }
132                 else
133                 {
134                         bFound = hitKXObj->GetProperty(m_property) != NULL;
135                 }
136         }
137         // update the hit status
138         result->m_hitFound = bFound;
139         // stop looking
140         return true;
141 }
142
143 /* this function is used to pre-filter the object before casting the ray on them.
144    This is useful for "X-Ray" option when we want to see "through" unwanted object.
145  */
146 bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
147 {
148         if (client->m_type > KX_ClientObjectInfo::ACTOR)
149         {
150                 // Unknown type of object, skip it.
151                 // Should not occur as the sensor objects are filtered in RayTest()
152                 printf("Invalid client type %d found in ray casting\n", client->m_type);
153                 return false;
154         }
155         // no X-Ray function yet
156         return true;
157 }
158
159 bool KX_ConstraintActuator::Update(double curtime, bool frame)
160 {
161
162         bool result = false;    
163         bool bNegativeEvent = IsNegativeEvent();
164         RemoveAllEvents();
165
166         if (!bNegativeEvent) {
167                 /* Constraint clamps the values to the specified range, with a sort of    */
168                 /* low-pass filtered time response, if the damp time is unequal to 0.     */
169
170                 /* Having to retrieve location/rotation and setting it afterwards may not */
171                 /* be efficient enough... Somthing to look at later.                      */
172                 KX_GameObject  *obj = (KX_GameObject*) GetParent();
173                 MT_Point3    position = obj->NodeGetWorldPosition();
174                 MT_Point3    newposition;
175                 MT_Vector3   normal, direction, refDirection;
176                 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
177                 MT_Scalar    filter, newdistance, cosangle;
178                 int axis, sign;
179
180                 if (m_posDampTime) {
181                         filter = m_posDampTime/(1.0+m_posDampTime);
182                 } else {
183                         filter = 0.0;
184                 }
185                 switch (m_locrot) {
186                 case KX_ACT_CONSTRAINT_ORIX:
187                 case KX_ACT_CONSTRAINT_ORIY:
188                 case KX_ACT_CONSTRAINT_ORIZ:
189                         switch (m_locrot) {
190                         case KX_ACT_CONSTRAINT_ORIX:
191                                 direction[0] = rotation[0][0];
192                                 direction[1] = rotation[1][0];
193                                 direction[2] = rotation[2][0];
194                                 axis = 0;
195                                 break;
196                         case KX_ACT_CONSTRAINT_ORIY:
197                                 direction[0] = rotation[0][1];
198                                 direction[1] = rotation[1][1];
199                                 direction[2] = rotation[2][1];
200                                 axis = 1;
201                                 break;
202                         default:
203                                 direction[0] = rotation[0][2];
204                                 direction[1] = rotation[1][2];
205                                 direction[2] = rotation[2][2];
206                                 axis = 2;
207                                 break;
208                         }
209                         if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
210                                 // reference direction needs to be evaluated
211                                 // 1. get the cosine between current direction and target
212                                 cosangle = direction.dot(m_refDirection);
213                                 if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
214                                         // no change to do
215                                         result = true;
216                                         goto CHECK_TIME;
217                                 }
218                                 // 2. define a new reference direction
219                                 //    compute local axis with reference direction as X and
220                                 //    Y in direction X refDirection plane
221                                 MT_Vector3 zaxis = m_refDirection.cross(direction);
222                                 if (MT_fuzzyZero2(zaxis.length2())) {
223                                         // direction and refDirection are identical,
224                                         // choose any other direction to define plane
225                                         if (direction[0] < 0.9999)
226                                                 zaxis = m_refDirection.cross(MT_Vector3(1.0,0.0,0.0));
227                                         else
228                                                 zaxis = m_refDirection.cross(MT_Vector3(0.0,1.0,0.0));
229                                 }
230                                 MT_Vector3 yaxis = zaxis.cross(m_refDirection);
231                                 yaxis.normalize();
232                                 if (cosangle > m_minimumBound) {
233                                         // angle is too close to reference direction,
234                                         // choose a new reference that is exactly at minimum angle
235                                         refDirection = m_minimumBound * m_refDirection + m_minimumSine * yaxis;
236                                 } else {
237                                         // angle is too large, choose new reference direction at maximum angle
238                                         refDirection = m_maximumBound * m_refDirection + m_maximumSine * yaxis;
239                                 }
240                         } else {
241                                 refDirection = m_refDirection;
242                         }
243                         // apply damping on the direction
244                         direction = filter*direction + (1.0-filter)*refDirection;
245                         obj->AlignAxisToVect(direction, axis);
246                         result = true;
247                         goto CHECK_TIME;
248                 case KX_ACT_CONSTRAINT_DIRPX:
249                 case KX_ACT_CONSTRAINT_DIRPY:
250                 case KX_ACT_CONSTRAINT_DIRPZ:
251                 case KX_ACT_CONSTRAINT_DIRNX:
252                 case KX_ACT_CONSTRAINT_DIRNY:
253                 case KX_ACT_CONSTRAINT_DIRNZ:
254                         switch (m_locrot) {
255                         case KX_ACT_CONSTRAINT_DIRPX:
256                                 normal[0] = rotation[0][0];
257                                 normal[1] = rotation[1][0];
258                                 normal[2] = rotation[2][0];
259                                 axis = 0;               // axis according to KX_GameObject::AlignAxisToVect()
260                                 sign = 0;               // X axis will be parrallel to direction of ray
261                                 break;
262                         case KX_ACT_CONSTRAINT_DIRPY:
263                                 normal[0] = rotation[0][1];
264                                 normal[1] = rotation[1][1];
265                                 normal[2] = rotation[2][1];
266                                 axis = 1;
267                                 sign = 0;
268                                 break;
269                         case KX_ACT_CONSTRAINT_DIRPZ:
270                                 normal[0] = rotation[0][2];
271                                 normal[1] = rotation[1][2];
272                                 normal[2] = rotation[2][2];
273                                 axis = 2;
274                                 sign = 0;
275                                 break;
276                         case KX_ACT_CONSTRAINT_DIRNX:
277                                 normal[0] = -rotation[0][0];
278                                 normal[1] = -rotation[1][0];
279                                 normal[2] = -rotation[2][0];
280                                 axis = 0;
281                                 sign = 1;
282                                 break;
283                         case KX_ACT_CONSTRAINT_DIRNY:
284                                 normal[0] = -rotation[0][1];
285                                 normal[1] = -rotation[1][1];
286                                 normal[2] = -rotation[2][1];
287                                 axis = 1;
288                                 sign = 1;
289                                 break;
290                         case KX_ACT_CONSTRAINT_DIRNZ:
291                                 normal[0] = -rotation[0][2];
292                                 normal[1] = -rotation[1][2];
293                                 normal[2] = -rotation[2][2];
294                                 axis = 2;
295                                 sign = 1;
296                                 break;
297                         }
298                         normal.normalize();
299                         if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
300                                 // direction of the ray is along the local axis
301                                 direction = normal;
302                         } else {
303                                 switch (m_locrot) {
304                                 case KX_ACT_CONSTRAINT_DIRPX:
305                                         direction = MT_Vector3(1.0,0.0,0.0);
306                                         break;
307                                 case KX_ACT_CONSTRAINT_DIRPY:
308                                         direction = MT_Vector3(0.0,1.0,0.0);
309                                         break;
310                                 case KX_ACT_CONSTRAINT_DIRPZ:
311                                         direction = MT_Vector3(0.0,0.0,1.0);
312                                         break;
313                                 case KX_ACT_CONSTRAINT_DIRNX:
314                                         direction = MT_Vector3(-1.0,0.0,0.0);
315                                         break;
316                                 case KX_ACT_CONSTRAINT_DIRNY:
317                                         direction = MT_Vector3(0.0,-1.0,0.0);
318                                         break;
319                                 case KX_ACT_CONSTRAINT_DIRNZ:
320                                         direction = MT_Vector3(0.0,0.0,-1.0);
321                                         break;
322                                 }
323                         }
324                         {
325                                 MT_Point3 topoint = position + (m_maximumBound) * direction;
326                                 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
327                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
328
329                                 if (!pe) {
330                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
331                                         goto CHECK_TIME;
332                                 }        
333                                 if (!spc) {
334                                         // the object is not physical, we probably want to avoid hitting its own parent
335                                         KX_GameObject *parent = obj->GetParent();
336                                         if (parent) {
337                                                 spc = parent->GetPhysicsController();
338                                                 parent->Release();
339                                         }
340                                 }
341                                 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
342                                 result = KX_RayCast::RayTest(pe, position, topoint, callback);
343                                 if (result)     {
344                                         MT_Vector3 newnormal = callback.m_hitNormal;
345                                         // compute new position & orientation
346                                         if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
347                                                 // if none option is set, the actuator does nothing but detect ray 
348                                                 // (works like a sensor)
349                                                 goto CHECK_TIME;
350                                         }
351                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
352                                                 MT_Scalar rotFilter;
353                                                 // apply damping on the direction
354                                                 if (m_rotDampTime) {
355                                                         rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
356                                                 } else {
357                                                         rotFilter = filter;
358                                                 }
359                                                 newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
360                                                 obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
361                                                 if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
362                                                         direction = newnormal;
363                                                         direction.normalize();
364                                                 }
365                                         }
366                                         if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
367                                                 if (m_posDampTime) {
368                                                         newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
369                                                 } else {
370                                                         newdistance = m_minimumBound;
371                                                 }
372                                                 // logically we should cancel the speed along the ray direction as we set the
373                                                 // position along that axis
374                                                 spc = obj->GetPhysicsController();
375                                                 if (spc) {
376                                                         MT_Vector3 linV = spc->GetLinearVelocity();
377                                                         // cancel the projection along the ray direction
378                                                         MT_Scalar fallspeed = linV.dot(direction);
379                                                         if (!MT_fuzzyZero(fallspeed))
380                                                                 spc->SetLinearVelocity(linV-fallspeed*direction,false);
381                                                 }
382                                         } else {
383                                                 newdistance = (position-callback.m_hitPoint).length();
384                                         }
385                                         newposition = callback.m_hitPoint-newdistance*direction;
386                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
387                                         // no contact but still keep running
388                                         result = true;
389                                         goto CHECK_TIME;
390                                 }
391                         }
392                         break; 
393                 case KX_ACT_CONSTRAINT_LOCX:
394                 case KX_ACT_CONSTRAINT_LOCY:
395                 case KX_ACT_CONSTRAINT_LOCZ:
396                         newposition = position = obj->GetSGNode()->GetLocalPosition();
397                         switch (m_locrot) {
398                         case KX_ACT_CONSTRAINT_LOCX:
399                                 Clamp(newposition[0], m_minimumBound, m_maximumBound);
400                                 break;
401                         case KX_ACT_CONSTRAINT_LOCY:
402                                 Clamp(newposition[1], m_minimumBound, m_maximumBound);
403                                 break;
404                         case KX_ACT_CONSTRAINT_LOCZ:
405                                 Clamp(newposition[2], m_minimumBound, m_maximumBound);
406                                 break;
407                         }
408                         result = true;
409                         if (m_posDampTime) {
410                                 newposition = filter*position + (1.0-filter)*newposition;
411                         }
412                         obj->NodeSetLocalPosition(newposition);
413                         goto CHECK_TIME;
414                 }
415                 if (result) {
416                         // set the new position but take into account parent if any
417                         obj->NodeSetWorldPosition(newposition);
418                 }
419         CHECK_TIME:
420                 if (result && m_activeTime > 0 ) {
421                         if (++m_currentTime >= m_activeTime)
422                                 result = false;
423                 }
424         }
425         if (!result) {
426                 m_currentTime = 0;
427         }
428         return result;
429 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
430
431 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
432                                                                   float min, 
433                                                                   float max) {
434         if (var < min) {
435                 var = min;
436         } else if (var > max) {
437                 var = max;
438         }
439 }
440
441
442 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
443 {
444         bool res = false;
445
446         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
447                 res = true;
448         }
449
450         return res;
451 }
452
453 /* ------------------------------------------------------------------------- */
454 /* Python functions                                                          */
455 /* ------------------------------------------------------------------------- */
456
457 /* Integration hooks ------------------------------------------------------- */
458 PyTypeObject KX_ConstraintActuator::Type = {
459         PyObject_HEAD_INIT(&PyType_Type)
460         0,
461         "KX_ConstraintActuator",
462         sizeof(KX_ConstraintActuator),
463         0,
464         PyDestructor,
465         0,
466         __getattr,
467         __setattr,
468         0, //&MyPyCompare,
469         __repr,
470         0, //&cvalue_as_number,
471         0,
472         0,
473         0,
474         0
475 };
476
477 PyParentObject KX_ConstraintActuator::Parents[] = {
478         &KX_ConstraintActuator::Type,
479         &SCA_IActuator::Type,
480         &SCA_ILogicBrick::Type,
481         &CValue::Type,
482         NULL
483 };
484
485 PyMethodDef KX_ConstraintActuator::Methods[] = {
486         {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
487         {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, GetDamp_doc},
488         {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, SetRotDamp_doc},
489         {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, GetRotDamp_doc},
490         {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, SetDirection_doc},
491         {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, GetDirection_doc},
492         {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, SetOption_doc},
493         {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, GetOption_doc},
494         {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, SetTime_doc},
495         {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, GetTime_doc},
496         {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
497         {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, GetProperty_doc},
498         {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
499         {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, GetMin_doc},
500         {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetDistance_doc},
501         {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, GetDistance_doc},
502         {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
503         {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, GetMax_doc},
504         {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetRayLength_doc},
505         {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, GetRayLength_doc},
506         {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
507         {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, GetLimit_doc},
508         {NULL,NULL} //Sentinel
509 };
510
511 PyObject* KX_ConstraintActuator::_getattr(const STR_String& attr) {
512         _getattr_up(SCA_IActuator);
513 }
514
515 /* 2. setDamp                                                                */
516 const char KX_ConstraintActuator::SetDamp_doc[] = 
517 "setDamp(duration)\n"
518 "\t- duration: integer\n"
519 "\tSets the time constant of the orientation and distance constraint.\n"
520 "\tIf the duration is negative, it is set to 0.\n";
521 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, 
522                                                                                    PyObject* args, 
523                                                                                    PyObject* kwds) {
524         int dampArg;
525         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
526                 return NULL;            
527         }
528         
529         m_posDampTime = dampArg;
530         if (m_posDampTime < 0) m_posDampTime = 0;
531
532         Py_Return;
533 }
534 /* 3. getDamp                                                                */
535 const char KX_ConstraintActuator::GetDamp_doc[] = 
536 "getDamp()\n"
537 "\tReturns the damping parameter.\n";
538 PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self){
539         return PyInt_FromLong(m_posDampTime);
540 }
541
542 /* 2. setRotDamp                                                                */
543 const char KX_ConstraintActuator::SetRotDamp_doc[] = 
544 "setRotDamp(duration)\n"
545 "\t- duration: integer\n"
546 "\tSets the time constant of the orientation constraint.\n"
547 "\tIf the duration is negative, it is set to 0.\n";
548 PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* self, 
549                                                                                       PyObject* args, 
550                                                                                       PyObject* kwds) {
551         int dampArg;
552         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
553                 return NULL;            
554         }
555         
556         m_rotDampTime = dampArg;
557         if (m_rotDampTime < 0) m_rotDampTime = 0;
558
559         Py_Return;
560 }
561 /* 3. getRotDamp                                                                */
562 const char KX_ConstraintActuator::GetRotDamp_doc[] = 
563 "getRotDamp()\n"
564 "\tReturns the damping time for application of the constraint.\n";
565 PyObject* KX_ConstraintActuator::PyGetRotDamp(PyObject* self){
566         return PyInt_FromLong(m_rotDampTime);
567 }
568
569 /* 2. setDirection                                                                */
570 const char KX_ConstraintActuator::SetDirection_doc[] = 
571 "setDirection(vector)\n"
572 "\t- vector: 3-tuple\n"
573 "\tSets the reference direction in world coordinate for the orientation constraint.\n";
574 PyObject* KX_ConstraintActuator::PySetDirection(PyObject* self, 
575                                                                                         PyObject* args, 
576                                                                                         PyObject* kwds) {
577         float x, y, z;
578         MT_Scalar len;
579         MT_Vector3 dir;
580
581         if(!PyArg_ParseTuple(args, "(fff)", &x, &y, &z)) {
582                 return NULL;            
583         }
584         dir[0] = x;
585         dir[1] = y;
586         dir[2] = z;
587         len = dir.length();
588         if (MT_fuzzyZero(len)) {
589                 std::cout << "Invalid direction" << std::endl;
590                 return NULL;
591         }
592         m_refDirection = dir/len;
593
594         Py_Return;
595 }
596 /* 3. getDirection                                                                */
597 const char KX_ConstraintActuator::GetDirection_doc[] = 
598 "getDirection()\n"
599 "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
600 PyObject* KX_ConstraintActuator::PyGetDirection(PyObject* self){
601         PyObject *retVal = PyList_New(3);
602
603         PyList_SetItem(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
604         PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
605         PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
606         return retVal;
607 }
608
609 /* 2. setOption                                                                */
610 const char KX_ConstraintActuator::SetOption_doc[] = 
611 "setOption(option)\n"
612 "\t- option: integer\n"
613 "\tSets several options of the distance  constraint.\n"
614 "\tBinary combination of the following values:\n"
615 "\t\t 64 : Activate alignment to surface\n"
616 "\t\t128 : Detect material rather than property\n"
617 "\t\t256 : No deactivation if ray does not hit target\n"
618 "\t\t512 : Activate distance control\n";
619 PyObject* KX_ConstraintActuator::PySetOption(PyObject* self, 
620                                                                                      PyObject* args, 
621                                                                                      PyObject* kwds) {
622         int option;
623         if(!PyArg_ParseTuple(args, "i", &option)) {
624                 return NULL;            
625         }
626         
627         m_option = option;
628
629         Py_Return;
630 }
631 /* 3. getOption                                                              */
632 const char KX_ConstraintActuator::GetOption_doc[] = 
633 "getOption()\n"
634 "\tReturns the option parameter.\n";
635 PyObject* KX_ConstraintActuator::PyGetOption(PyObject* self){
636         return PyInt_FromLong(m_option);
637 }
638
639 /* 2. setTime                                                                */
640 const char KX_ConstraintActuator::SetTime_doc[] = 
641 "setTime(duration)\n"
642 "\t- duration: integer\n"
643 "\tSets the activation time of the actuator.\n"
644 "\tThe actuator disables itself after this many frame.\n"
645 "\tIf set to 0 or negative, the actuator is not limited in time.\n";
646 PyObject* KX_ConstraintActuator::PySetTime(PyObject* self, 
647                                                                                    PyObject* args, 
648                                                                                    PyObject* kwds) {
649         int t;
650         if(!PyArg_ParseTuple(args, "i", &t)) {
651                 return NULL;            
652         }
653         
654         if (t < 0)
655                 t = 0;
656         m_activeTime = t;
657
658         Py_Return;
659 }
660 /* 3. getTime                                                                */
661 const char KX_ConstraintActuator::GetTime_doc[] = 
662 "getTime()\n"
663 "\tReturns the time parameter.\n";
664 PyObject* KX_ConstraintActuator::PyGetTime(PyObject* self){
665         return PyInt_FromLong(m_activeTime);
666 }
667
668 /* 2. setProperty                                                                */
669 const char KX_ConstraintActuator::SetProperty_doc[] = 
670 "setProperty(property)\n"
671 "\t- property: string\n"
672 "\tSets the name of the property or material for the ray detection of the distance constraint.\n"
673 "\tIf empty, the ray will detect any collisioning object.\n";
674 PyObject* KX_ConstraintActuator::PySetProperty(PyObject* self, 
675                                                                                        PyObject* args, 
676                                                                                        PyObject* kwds) {
677         char *property;
678         if (!PyArg_ParseTuple(args, "s", &property)) {
679                 return NULL;
680         }
681         if (property == NULL) {
682                 m_property[0] = 0;
683         } else {
684                 strncpy(m_property, property, sizeof(m_property));
685                 m_property[sizeof(m_property)-1] = 0;
686         }
687
688         Py_Return;
689 }
690 /* 3. getProperty                                                                */
691 const char KX_ConstraintActuator::GetProperty_doc[] = 
692 "getProperty()\n"
693 "\tReturns the property parameter.\n";
694 PyObject* KX_ConstraintActuator::PyGetProperty(PyObject* self){
695         return PyString_FromString(m_property);
696 }
697
698 /* 4. setDistance                                                                 */
699 const char KX_ConstraintActuator::SetDistance_doc[] = 
700 "setDistance(distance)\n"
701 "\t- distance: float\n"
702 "\tSets the target distance in distance constraint\n";
703 /* 4. setMin                                                                 */
704 const char KX_ConstraintActuator::SetMin_doc[] = 
705 "setMin(lower_bound)\n"
706 "\t- lower_bound: float\n"
707 "\tSets the lower value of the interval to which the value\n"
708 "\tis clipped.\n";
709 PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, 
710                                                                                   PyObject* args, 
711                                                                                   PyObject* kwds) {
712         float minArg;
713         if(!PyArg_ParseTuple(args, "f", &minArg)) {
714                 return NULL;            
715         }
716
717         switch (m_locrot) {
718         default:
719                 m_minimumBound = minArg;
720                 break;
721         case KX_ACT_CONSTRAINT_ROTX:
722         case KX_ACT_CONSTRAINT_ROTY:
723         case KX_ACT_CONSTRAINT_ROTZ:
724                 m_minimumBound = MT_radians(minArg);
725                 break;
726         }
727
728         Py_Return;
729 }
730 /* 5. getDistance                                                                 */
731 const char KX_ConstraintActuator::GetDistance_doc[] = 
732 "getDistance()\n"
733 "\tReturns the distance parameter \n";
734 /* 5. getMin                                                                 */
735 const char KX_ConstraintActuator::GetMin_doc[] = 
736 "getMin()\n"
737 "\tReturns the lower value of the interval to which the value\n"
738 "\tis clipped.\n";
739 PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self) {
740         return PyFloat_FromDouble(m_minimumBound);
741 }
742
743 /* 6. setRayLength                                                                 */
744 const char KX_ConstraintActuator::SetRayLength_doc[] = 
745 "setRayLength(length)\n"
746 "\t- length: float\n"
747 "\tSets the maximum ray length of the distance constraint\n";
748 /* 6. setMax                                                                 */
749 const char KX_ConstraintActuator::SetMax_doc[] = 
750 "setMax(upper_bound)\n"
751 "\t- upper_bound: float\n"
752 "\tSets the upper value of the interval to which the value\n"
753 "\tis clipped.\n";
754 PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, 
755                                                                                   PyObject* args, 
756                                                                                   PyObject* kwds){
757         float maxArg;
758         if(!PyArg_ParseTuple(args, "f", &maxArg)) {
759                 return NULL;            
760         }
761
762         switch (m_locrot) {
763         default:
764                 m_maximumBound = maxArg;
765                 break;
766         case KX_ACT_CONSTRAINT_ROTX:
767         case KX_ACT_CONSTRAINT_ROTY:
768         case KX_ACT_CONSTRAINT_ROTZ:
769                 m_maximumBound = MT_radians(maxArg);
770                 break;
771         }
772
773         Py_Return;
774 }
775 /* 7. getRayLength                                                                 */
776 const char KX_ConstraintActuator::GetRayLength_doc[] = 
777 "getRayLength()\n"
778 "\tReturns the length of the ray\n";
779 /* 7. getMax                                                                 */
780 const char KX_ConstraintActuator::GetMax_doc[] = 
781 "getMax()\n"
782 "\tReturns the upper value of the interval to which the value\n"
783 "\tis clipped.\n";
784 PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self) {
785         return PyFloat_FromDouble(m_maximumBound);
786 }
787
788
789 /* This setter/getter probably for the constraint type                       */
790 /* 8. setLimit                                                               */
791 const char KX_ConstraintActuator::SetLimit_doc[] = 
792 "setLimit(type)\n"
793 "\t- type: integer\n"
794 "\t  1  : LocX\n"
795 "\t  2  : LocY\n"
796 "\t  3  : LocZ\n"
797 "\t  7  : Distance along +X axis\n"
798 "\t  8  : Distance along +Y axis\n"
799 "\t  9  : Distance along +Z axis\n"
800 "\t  10 : Distance along -X axis\n"
801 "\t  11 : Distance along -Y axis\n"
802 "\t  12 : Distance along -Z axis\n"
803 "\t  13 : Align X axis\n"
804 "\t  14 : Align Y axis\n"
805 "\t  15 : Align Z axis\n"
806 "\tSets the type of constraint.\n";
807 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, 
808                                                                                         PyObject* args, 
809                                                                                         PyObject* kwds) {
810         int locrotArg;
811         if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
812                 return NULL;            
813         }
814         
815         if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
816
817         Py_Return;
818 }
819 /* 9. getLimit                                                               */
820 const char KX_ConstraintActuator::GetLimit_doc[] = 
821 "getLimit()\n"
822 "\tReturns the type of constraint.\n";
823 PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self) {
824         return PyInt_FromLong(m_locrot);
825 }
826
827 /* eof */