svn merge -r 21041:21301 https://svn.blender.org/svnroot/bf-blender/branches/blender2...
[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         SCA_IActuator(gameobj),
59         m_refDirVector(refDir),
60         m_currentTime(0)
61 {
62         m_refDirection[0] = refDir[0];
63         m_refDirection[1] = refDir[1];
64         m_refDirection[2] = refDir[2];
65         m_posDampTime = posDampTime;
66         m_rotDampTime = rotDampTime;
67         m_locrot   = locrotxyz;
68         m_option = option;
69         m_activeTime = time;
70         if (property) {
71                 m_property = property;
72         } else {
73                 m_property = "";
74         }
75         /* The units of bounds are determined by the type of constraint. To      */
76         /* make the constraint application easier and more transparent later on, */
77         /* I think converting the bounds to the applicable domain makes more     */
78         /* sense.                                                                */
79         switch (m_locrot) {
80         case KX_ACT_CONSTRAINT_ORIX:
81         case KX_ACT_CONSTRAINT_ORIY:
82         case KX_ACT_CONSTRAINT_ORIZ:
83                 {
84                         MT_Scalar len = m_refDirVector.length();
85                         if (MT_fuzzyZero(len)) {
86                                 // missing a valid direction
87                                 std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no valid reference direction!" << std::endl;
88                                 m_locrot = KX_ACT_CONSTRAINT_NODEF;
89                         } else {
90                                 m_refDirection[0] /= len;
91                                 m_refDirection[1] /= len;
92                                 m_refDirection[2] /= len;
93                                 m_refDirVector /= len;
94                         }
95                         m_minimumBound = cos(minBound);
96                         m_maximumBound = cos(maxBound);
97                         m_minimumSine = sin(minBound);
98                         m_maximumSine = sin(maxBound);
99                 }
100                 break;
101         default:
102                 m_minimumBound = minBound;
103                 m_maximumBound = maxBound;
104                 m_minimumSine = 0.f;
105                 m_maximumSine = 0.f;
106                 break;
107         }
108
109 } /* End of constructor */
110
111 KX_ConstraintActuator::~KX_ConstraintActuator()
112
113         // there's nothing to be done here, really....
114 } /* end of destructor */
115
116 bool KX_ConstraintActuator::RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data)
117 {
118
119         m_hitObject = client->m_gameobject;
120         
121         bool bFound = false;
122
123         if (m_property.IsEmpty())
124         {
125                 bFound = true;
126         }
127         else
128         {
129                 if (m_option & KX_ACT_CONSTRAINT_MATERIAL)
130                 {
131                         if (client->m_auxilary_info)
132                         {
133                                 bFound = !strcmp(m_property.Ptr(), ((char*)client->m_auxilary_info));
134                         }
135                 }
136                 else
137                 {
138                         bFound = m_hitObject->GetProperty(m_property) != NULL;
139                 }
140         }
141         // update the hit status
142         result->m_hitFound = bFound;
143         // stop looking
144         return true;
145 }
146
147 /* this function is used to pre-filter the object before casting the ray on them.
148    This is useful for "X-Ray" option when we want to see "through" unwanted object.
149  */
150 bool KX_ConstraintActuator::NeedRayCast(KX_ClientObjectInfo* client)
151 {
152         if (client->m_type > KX_ClientObjectInfo::ACTOR)
153         {
154                 // Unknown type of object, skip it.
155                 // Should not occur as the sensor objects are filtered in RayTest()
156                 printf("Invalid client type %d found in ray casting\n", client->m_type);
157                 return false;
158         }
159         // no X-Ray function yet
160         return true;
161 }
162
163 bool KX_ConstraintActuator::Update(double curtime, bool frame)
164 {
165
166         bool result = false;    
167         bool bNegativeEvent = IsNegativeEvent();
168         RemoveAllEvents();
169
170         if (!bNegativeEvent) {
171                 /* Constraint clamps the values to the specified range, with a sort of    */
172                 /* low-pass filtered time response, if the damp time is unequal to 0.     */
173
174                 /* Having to retrieve location/rotation and setting it afterwards may not */
175                 /* be efficient enough... Somthing to look at later.                      */
176                 KX_GameObject  *obj = (KX_GameObject*) GetParent();
177                 MT_Point3    position = obj->NodeGetWorldPosition();
178                 MT_Point3    newposition;
179                 MT_Vector3   normal, direction, refDirection;
180                 MT_Matrix3x3 rotation = obj->NodeGetWorldOrientation();
181                 MT_Scalar    filter, newdistance, cosangle;
182                 int axis, sign;
183
184                 if (m_posDampTime) {
185                         filter = m_posDampTime/(1.0+m_posDampTime);
186                 } else {
187                         filter = 0.0;
188                 }
189                 switch (m_locrot) {
190                 case KX_ACT_CONSTRAINT_ORIX:
191                 case KX_ACT_CONSTRAINT_ORIY:
192                 case KX_ACT_CONSTRAINT_ORIZ:
193                         switch (m_locrot) {
194                         case KX_ACT_CONSTRAINT_ORIX:
195                                 direction[0] = rotation[0][0];
196                                 direction[1] = rotation[1][0];
197                                 direction[2] = rotation[2][0];
198                                 axis = 0;
199                                 break;
200                         case KX_ACT_CONSTRAINT_ORIY:
201                                 direction[0] = rotation[0][1];
202                                 direction[1] = rotation[1][1];
203                                 direction[2] = rotation[2][1];
204                                 axis = 1;
205                                 break;
206                         default:
207                                 direction[0] = rotation[0][2];
208                                 direction[1] = rotation[1][2];
209                                 direction[2] = rotation[2][2];
210                                 axis = 2;
211                                 break;
212                         }
213                         if ((m_maximumBound < (1.0f-FLT_EPSILON)) || (m_minimumBound < (1.0f-FLT_EPSILON))) {
214                                 // reference direction needs to be evaluated
215                                 // 1. get the cosine between current direction and target
216                                 cosangle = direction.dot(m_refDirVector);
217                                 if (cosangle >= (m_maximumBound-FLT_EPSILON) && cosangle <= (m_minimumBound+FLT_EPSILON)) {
218                                         // no change to do
219                                         result = true;
220                                         goto CHECK_TIME;
221                                 }
222                                 // 2. define a new reference direction
223                                 //    compute local axis with reference direction as X and
224                                 //    Y in direction X refDirection plane
225                                 MT_Vector3 zaxis = m_refDirVector.cross(direction);
226                                 if (MT_fuzzyZero2(zaxis.length2())) {
227                                         // direction and refDirection are identical,
228                                         // choose any other direction to define plane
229                                         if (direction[0] < 0.9999)
230                                                 zaxis = m_refDirVector.cross(MT_Vector3(1.0,0.0,0.0));
231                                         else
232                                                 zaxis = m_refDirVector.cross(MT_Vector3(0.0,1.0,0.0));
233                                 }
234                                 MT_Vector3 yaxis = zaxis.cross(m_refDirVector);
235                                 yaxis.normalize();
236                                 if (cosangle > m_minimumBound) {
237                                         // angle is too close to reference direction,
238                                         // choose a new reference that is exactly at minimum angle
239                                         refDirection = m_minimumBound * m_refDirVector + m_minimumSine * yaxis;
240                                 } else {
241                                         // angle is too large, choose new reference direction at maximum angle
242                                         refDirection = m_maximumBound * m_refDirVector + m_maximumSine * yaxis;
243                                 }
244                         } else {
245                                 refDirection = m_refDirVector;
246                         }
247                         // apply damping on the direction
248                         direction = filter*direction + (1.0-filter)*refDirection;
249                         obj->AlignAxisToVect(direction, axis);
250                         result = true;
251                         goto CHECK_TIME;
252                 case KX_ACT_CONSTRAINT_DIRPX:
253                 case KX_ACT_CONSTRAINT_DIRPY:
254                 case KX_ACT_CONSTRAINT_DIRPZ:
255                 case KX_ACT_CONSTRAINT_DIRNX:
256                 case KX_ACT_CONSTRAINT_DIRNY:
257                 case KX_ACT_CONSTRAINT_DIRNZ:
258                         switch (m_locrot) {
259                         case KX_ACT_CONSTRAINT_DIRPX:
260                                 normal[0] = rotation[0][0];
261                                 normal[1] = rotation[1][0];
262                                 normal[2] = rotation[2][0];
263                                 axis = 0;               // axis according to KX_GameObject::AlignAxisToVect()
264                                 sign = 0;               // X axis will be parrallel to direction of ray
265                                 break;
266                         case KX_ACT_CONSTRAINT_DIRPY:
267                                 normal[0] = rotation[0][1];
268                                 normal[1] = rotation[1][1];
269                                 normal[2] = rotation[2][1];
270                                 axis = 1;
271                                 sign = 0;
272                                 break;
273                         case KX_ACT_CONSTRAINT_DIRPZ:
274                                 normal[0] = rotation[0][2];
275                                 normal[1] = rotation[1][2];
276                                 normal[2] = rotation[2][2];
277                                 axis = 2;
278                                 sign = 0;
279                                 break;
280                         case KX_ACT_CONSTRAINT_DIRNX:
281                                 normal[0] = -rotation[0][0];
282                                 normal[1] = -rotation[1][0];
283                                 normal[2] = -rotation[2][0];
284                                 axis = 0;
285                                 sign = 1;
286                                 break;
287                         case KX_ACT_CONSTRAINT_DIRNY:
288                                 normal[0] = -rotation[0][1];
289                                 normal[1] = -rotation[1][1];
290                                 normal[2] = -rotation[2][1];
291                                 axis = 1;
292                                 sign = 1;
293                                 break;
294                         case KX_ACT_CONSTRAINT_DIRNZ:
295                                 normal[0] = -rotation[0][2];
296                                 normal[1] = -rotation[1][2];
297                                 normal[2] = -rotation[2][2];
298                                 axis = 2;
299                                 sign = 1;
300                                 break;
301                         }
302                         normal.normalize();
303                         if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
304                                 // direction of the ray is along the local axis
305                                 direction = normal;
306                         } else {
307                                 switch (m_locrot) {
308                                 case KX_ACT_CONSTRAINT_DIRPX:
309                                         direction = MT_Vector3(1.0,0.0,0.0);
310                                         break;
311                                 case KX_ACT_CONSTRAINT_DIRPY:
312                                         direction = MT_Vector3(0.0,1.0,0.0);
313                                         break;
314                                 case KX_ACT_CONSTRAINT_DIRPZ:
315                                         direction = MT_Vector3(0.0,0.0,1.0);
316                                         break;
317                                 case KX_ACT_CONSTRAINT_DIRNX:
318                                         direction = MT_Vector3(-1.0,0.0,0.0);
319                                         break;
320                                 case KX_ACT_CONSTRAINT_DIRNY:
321                                         direction = MT_Vector3(0.0,-1.0,0.0);
322                                         break;
323                                 case KX_ACT_CONSTRAINT_DIRNZ:
324                                         direction = MT_Vector3(0.0,0.0,-1.0);
325                                         break;
326                                 }
327                         }
328                         {
329                                 MT_Point3 topoint = position + (m_maximumBound) * direction;
330                                 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
331                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
332
333                                 if (!pe) {
334                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
335                                         goto CHECK_TIME;
336                                 }        
337                                 if (!spc) {
338                                         // the object is not physical, we probably want to avoid hitting its own parent
339                                         KX_GameObject *parent = obj->GetParent();
340                                         if (parent) {
341                                                 spc = parent->GetPhysicsController();
342                                                 parent->Release();
343                                         }
344                                 }
345                                 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
346                                 result = KX_RayCast::RayTest(pe, position, topoint, callback);
347                                 if (result)     {
348                                         MT_Vector3 newnormal = callback.m_hitNormal;
349                                         // compute new position & orientation
350                                         if ((m_option & (KX_ACT_CONSTRAINT_NORMAL|KX_ACT_CONSTRAINT_DISTANCE)) == 0) {
351                                                 // if none option is set, the actuator does nothing but detect ray 
352                                                 // (works like a sensor)
353                                                 goto CHECK_TIME;
354                                         }
355                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL) {
356                                                 MT_Scalar rotFilter;
357                                                 // apply damping on the direction
358                                                 if (m_rotDampTime) {
359                                                         rotFilter = m_rotDampTime/(1.0+m_rotDampTime);
360                                                 } else {
361                                                         rotFilter = filter;
362                                                 }
363                                                 newnormal = rotFilter*normal - (1.0-rotFilter)*newnormal;
364                                                 obj->AlignAxisToVect((sign)?-newnormal:newnormal, axis);
365                                                 if (m_option & KX_ACT_CONSTRAINT_LOCAL) {
366                                                         direction = newnormal;
367                                                         direction.normalize();
368                                                 }
369                                         }
370                                         if (m_option & KX_ACT_CONSTRAINT_DISTANCE) {
371                                                 if (m_posDampTime) {
372                                                         newdistance = filter*(position-callback.m_hitPoint).length()+(1.0-filter)*m_minimumBound;
373                                                 } else {
374                                                         newdistance = m_minimumBound;
375                                                 }
376                                                 // logically we should cancel the speed along the ray direction as we set the
377                                                 // position along that axis
378                                                 spc = obj->GetPhysicsController();
379                                                 if (spc && spc->IsDyna()) {
380                                                         MT_Vector3 linV = spc->GetLinearVelocity();
381                                                         // cancel the projection along the ray direction
382                                                         MT_Scalar fallspeed = linV.dot(direction);
383                                                         if (!MT_fuzzyZero(fallspeed))
384                                                                 spc->SetLinearVelocity(linV-fallspeed*direction,false);
385                                                 }
386                                         } else {
387                                                 newdistance = (position-callback.m_hitPoint).length();
388                                         }
389                                         newposition = callback.m_hitPoint-newdistance*direction;
390                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
391                                         // no contact but still keep running
392                                         result = true;
393                                         goto CHECK_TIME;
394                                 }
395                         }
396                         break; 
397                 case KX_ACT_CONSTRAINT_FHPX:
398                 case KX_ACT_CONSTRAINT_FHPY:
399                 case KX_ACT_CONSTRAINT_FHPZ:
400                 case KX_ACT_CONSTRAINT_FHNX:
401                 case KX_ACT_CONSTRAINT_FHNY:
402                 case KX_ACT_CONSTRAINT_FHNZ:
403                         switch (m_locrot) {
404                         case KX_ACT_CONSTRAINT_FHPX:
405                                 normal[0] = -rotation[0][0];
406                                 normal[1] = -rotation[1][0];
407                                 normal[2] = -rotation[2][0];
408                                 direction = MT_Vector3(1.0,0.0,0.0);
409                                 break;
410                         case KX_ACT_CONSTRAINT_FHPY:
411                                 normal[0] = -rotation[0][1];
412                                 normal[1] = -rotation[1][1];
413                                 normal[2] = -rotation[2][1];
414                                 direction = MT_Vector3(0.0,1.0,0.0);
415                                 break;
416                         case KX_ACT_CONSTRAINT_FHPZ:
417                                 normal[0] = -rotation[0][2];
418                                 normal[1] = -rotation[1][2];
419                                 normal[2] = -rotation[2][2];
420                                 direction = MT_Vector3(0.0,0.0,1.0);
421                                 break;
422                         case KX_ACT_CONSTRAINT_FHNX:
423                                 normal[0] = rotation[0][0];
424                                 normal[1] = rotation[1][0];
425                                 normal[2] = rotation[2][0];
426                                 direction = MT_Vector3(-1.0,0.0,0.0);
427                                 break;
428                         case KX_ACT_CONSTRAINT_FHNY:
429                                 normal[0] = rotation[0][1];
430                                 normal[1] = rotation[1][1];
431                                 normal[2] = rotation[2][1];
432                                 direction = MT_Vector3(0.0,-1.0,0.0);
433                                 break;
434                         case KX_ACT_CONSTRAINT_FHNZ:
435                                 normal[0] = rotation[0][2];
436                                 normal[1] = rotation[1][2];
437                                 normal[2] = rotation[2][2];
438                                 direction = MT_Vector3(0.0,0.0,-1.0);
439                                 break;
440                         }
441                         normal.normalize();
442                         {
443                                 PHY_IPhysicsEnvironment* pe = obj->GetPhysicsEnvironment();
444                                 KX_IPhysicsController *spc = obj->GetPhysicsController();
445
446                                 if (!pe) {
447                                         std::cout << "WARNING: Constraint actuator " << GetName() << ":  There is no physics environment!" << std::endl;
448                                         goto CHECK_TIME;
449                                 }        
450                                 if (!spc || !spc->IsDyna()) {
451                                         // the object is not dynamic, it won't support setting speed
452                                         goto CHECK_TIME;
453                                 }
454                                 m_hitObject = NULL;
455                                 // distance of Fh area is stored in m_minimum
456                                 MT_Point3 topoint = position + (m_minimumBound+spc->GetRadius()) * direction;
457                                 KX_RayCast::Callback<KX_ConstraintActuator> callback(this,spc);
458                                 result = KX_RayCast::RayTest(pe, position, topoint, callback);
459                                 // we expect a hit object
460                                 if (!m_hitObject)
461                                         result = false;
462                                 if (result)     
463                                 {
464                                         MT_Vector3 newnormal = callback.m_hitNormal;
465                                         // compute new position & orientation
466                                         MT_Scalar distance = (callback.m_hitPoint-position).length()-spc->GetRadius(); 
467                                         // estimate the velocity of the hit point
468                                         MT_Point3 relativeHitPoint;
469                                         relativeHitPoint = (callback.m_hitPoint-m_hitObject->NodeGetWorldPosition());
470                                         MT_Vector3 velocityHitPoint = m_hitObject->GetVelocity(relativeHitPoint);
471                                         MT_Vector3 relativeVelocity = spc->GetLinearVelocity() - velocityHitPoint;
472                                         MT_Scalar relativeVelocityRay = direction.dot(relativeVelocity);
473                                         MT_Scalar springExtent = 1.0 - distance/m_minimumBound;
474                                         // Fh force is stored in m_maximum
475                                         MT_Scalar springForce = springExtent * m_maximumBound;
476                                         // damping is stored in m_refDirection [0] = damping, [1] = rot damping
477                                         MT_Scalar springDamp = relativeVelocityRay * m_refDirVector[0];
478                                         MT_Vector3 newVelocity = spc->GetLinearVelocity()-(springForce+springDamp)*direction;
479                                         if (m_option & KX_ACT_CONSTRAINT_NORMAL)
480                                         {
481                                                 newVelocity+=(springForce+springDamp)*(newnormal-newnormal.dot(direction)*direction);
482                                         }
483                                         spc->SetLinearVelocity(newVelocity, false);
484                                         if (m_option & KX_ACT_CONSTRAINT_DOROTFH)
485                                         {
486                                                 MT_Vector3 angSpring = (normal.cross(newnormal))*m_maximumBound;
487                                                 MT_Vector3 angVelocity = spc->GetAngularVelocity();
488                                                 // remove component that is parallel to normal
489                                                 angVelocity -= angVelocity.dot(newnormal)*newnormal;
490                                                 MT_Vector3 angDamp = angVelocity * ((m_refDirVector[1]>MT_EPSILON)?m_refDirVector[1]:m_refDirVector[0]);
491                                                 spc->SetAngularVelocity(spc->GetAngularVelocity()+(angSpring-angDamp), false);
492                                         }
493                                 } else if (m_option & KX_ACT_CONSTRAINT_PERMANENT) {
494                                         // no contact but still keep running
495                                         result = true;
496                                 }
497                                 // don't set the position with this constraint
498                                 goto CHECK_TIME;
499                         }
500                         break; 
501                 case KX_ACT_CONSTRAINT_LOCX:
502                 case KX_ACT_CONSTRAINT_LOCY:
503                 case KX_ACT_CONSTRAINT_LOCZ:
504                         newposition = position = obj->GetSGNode()->GetLocalPosition();
505                         switch (m_locrot) {
506                         case KX_ACT_CONSTRAINT_LOCX:
507                                 Clamp(newposition[0], m_minimumBound, m_maximumBound);
508                                 break;
509                         case KX_ACT_CONSTRAINT_LOCY:
510                                 Clamp(newposition[1], m_minimumBound, m_maximumBound);
511                                 break;
512                         case KX_ACT_CONSTRAINT_LOCZ:
513                                 Clamp(newposition[2], m_minimumBound, m_maximumBound);
514                                 break;
515                         }
516                         result = true;
517                         if (m_posDampTime) {
518                                 newposition = filter*position + (1.0-filter)*newposition;
519                         }
520                         obj->NodeSetLocalPosition(newposition);
521                         goto CHECK_TIME;
522                 }
523                 if (result) {
524                         // set the new position but take into account parent if any
525                         obj->NodeSetWorldPosition(newposition);
526                 }
527         CHECK_TIME:
528                 if (result && m_activeTime > 0 ) {
529                         if (++m_currentTime >= m_activeTime)
530                                 result = false;
531                 }
532         }
533         if (!result) {
534                 m_currentTime = 0;
535         }
536         return result;
537 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
538
539 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
540                                                                   float min, 
541                                                                   float max) {
542         if (var < min) {
543                 var = min;
544         } else if (var > max) {
545                 var = max;
546         }
547 }
548
549
550 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
551 {
552         bool res = false;
553
554         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
555                 res = true;
556         }
557
558         return res;
559 }
560
561 /* ------------------------------------------------------------------------- */
562 /* Python functions                                                          */
563 /* ------------------------------------------------------------------------- */
564
565 /* Integration hooks ------------------------------------------------------- */
566 PyTypeObject KX_ConstraintActuator::Type = {
567 #if (PY_VERSION_HEX >= 0x02060000)
568         PyVarObject_HEAD_INIT(NULL, 0)
569 #else
570         /* python 2.5 and below */
571         PyObject_HEAD_INIT( NULL )  /* required py macro */
572         0,                          /* ob_size */
573 #endif
574         "KX_ConstraintActuator",
575         sizeof(PyObjectPlus_Proxy),
576         0,
577         py_base_dealloc,
578         0,
579         0,
580         0,
581         0,
582         py_base_repr,
583         0,0,0,0,0,0,0,0,0,
584         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
585         0,0,0,0,0,0,0,
586         Methods,
587         0,
588         0,
589         &SCA_IActuator::Type,
590         0,0,0,0,0,0,
591         py_base_new
592 };
593
594 PyMethodDef KX_ConstraintActuator::Methods[] = {
595         // Deprecated -->
596         {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, (PY_METHODCHAR)SetDamp_doc},
597         {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_NOARGS, (PY_METHODCHAR)GetDamp_doc},
598         {"setRotDamp", (PyCFunction) KX_ConstraintActuator::sPySetRotDamp, METH_VARARGS, (PY_METHODCHAR)SetRotDamp_doc},
599         {"getRotDamp", (PyCFunction) KX_ConstraintActuator::sPyGetRotDamp, METH_NOARGS, (PY_METHODCHAR)GetRotDamp_doc},
600         {"setDirection", (PyCFunction) KX_ConstraintActuator::sPySetDirection, METH_VARARGS, (PY_METHODCHAR)SetDirection_doc},
601         {"getDirection", (PyCFunction) KX_ConstraintActuator::sPyGetDirection, METH_NOARGS, (PY_METHODCHAR)GetDirection_doc},
602         {"setOption", (PyCFunction) KX_ConstraintActuator::sPySetOption, METH_VARARGS, (PY_METHODCHAR)SetOption_doc},
603         {"getOption", (PyCFunction) KX_ConstraintActuator::sPyGetOption, METH_NOARGS, (PY_METHODCHAR)GetOption_doc},
604         {"setTime", (PyCFunction) KX_ConstraintActuator::sPySetTime, METH_VARARGS, (PY_METHODCHAR)SetTime_doc},
605         {"getTime", (PyCFunction) KX_ConstraintActuator::sPyGetTime, METH_NOARGS, (PY_METHODCHAR)GetTime_doc},
606         {"setProperty", (PyCFunction) KX_ConstraintActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
607         {"getProperty", (PyCFunction) KX_ConstraintActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
608         {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetMin_doc},
609         {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetMin_doc},
610         {"setDistance", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, (PY_METHODCHAR)SetDistance_doc},
611         {"getDistance", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_NOARGS, (PY_METHODCHAR)GetDistance_doc},
612         {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetMax_doc},
613         {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetMax_doc},
614         {"setRayLength", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, (PY_METHODCHAR)SetRayLength_doc},
615         {"getRayLength", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_NOARGS, (PY_METHODCHAR)GetRayLength_doc},
616         {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, (PY_METHODCHAR)SetLimit_doc},
617         {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_NOARGS, (PY_METHODCHAR)GetLimit_doc},
618         // <--
619         {NULL,NULL} //Sentinel
620 };
621
622 PyAttributeDef KX_ConstraintActuator::Attributes[] = {
623         KX_PYATTRIBUTE_INT_RW("damp",0,100,true,KX_ConstraintActuator,m_posDampTime),
624         KX_PYATTRIBUTE_INT_RW("rotDamp",0,100,true,KX_ConstraintActuator,m_rotDampTime),
625         KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK("direction",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_refDirection,3,pyattr_check_direction),
626         KX_PYATTRIBUTE_INT_RW("option",0,0xFFFF,false,KX_ConstraintActuator,m_option),
627         KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_ConstraintActuator,m_activeTime),
628         KX_PYATTRIBUTE_STRING_RW("propName",0,32,true,KX_ConstraintActuator,m_property),
629         KX_PYATTRIBUTE_FLOAT_RW("min",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound),
630         KX_PYATTRIBUTE_FLOAT_RW("distance",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_minimumBound),
631         KX_PYATTRIBUTE_FLOAT_RW("max",-FLT_MAX,FLT_MAX,KX_ConstraintActuator,m_maximumBound),
632         KX_PYATTRIBUTE_FLOAT_RW("rayLength",0,2000.f,KX_ConstraintActuator,m_maximumBound),
633         KX_PYATTRIBUTE_INT_RW("limit",KX_ConstraintActuator::KX_ACT_CONSTRAINT_NODEF+1,KX_ConstraintActuator::KX_ACT_CONSTRAINT_MAX-1,false,KX_ConstraintActuator,m_locrot),
634         { NULL }        //Sentinel
635 };
636
637 int KX_ConstraintActuator::pyattr_check_direction(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
638 {
639         KX_ConstraintActuator* act = static_cast<KX_ConstraintActuator*>(self);
640         MT_Vector3 dir(act->m_refDirection);
641         MT_Scalar len = dir.length();
642         if (MT_fuzzyZero(len)) {
643                 PyErr_SetString(PyExc_ValueError, "actuator.direction = vec: KX_ConstraintActuator, invalid direction");
644                 return 1;
645         }
646         act->m_refDirVector = dir/len;
647         return 0;       
648 }
649
650 /* 2. setDamp                                                                */
651 const char KX_ConstraintActuator::SetDamp_doc[] = 
652 "setDamp(duration)\n"
653 "\t- duration: integer\n"
654 "\tSets the time constant of the orientation and distance constraint.\n"
655 "\tIf the duration is negative, it is set to 0.\n";
656 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* args) {
657         ShowDeprecationWarning("setDamp()", "the damp property");
658         int dampArg;
659         if(!PyArg_ParseTuple(args, "i:setDamp", &dampArg)) {
660                 return NULL;            
661         }
662         
663         m_posDampTime = dampArg;
664         if (m_posDampTime < 0) m_posDampTime = 0;
665
666         Py_RETURN_NONE;
667 }
668 /* 3. getDamp                                                                */
669 const char KX_ConstraintActuator::GetDamp_doc[] = 
670 "getDamp()\n"
671 "\tReturns the damping parameter.\n";
672 PyObject* KX_ConstraintActuator::PyGetDamp(){
673         ShowDeprecationWarning("getDamp()", "the damp property");
674         return PyLong_FromSsize_t(m_posDampTime);
675 }
676
677 /* 2. setRotDamp                                                                */
678 const char KX_ConstraintActuator::SetRotDamp_doc[] = 
679 "setRotDamp(duration)\n"
680 "\t- duration: integer\n"
681 "\tSets the time constant of the orientation constraint.\n"
682 "\tIf the duration is negative, it is set to 0.\n";
683 PyObject* KX_ConstraintActuator::PySetRotDamp(PyObject* args) {
684         ShowDeprecationWarning("setRotDamp()", "the rotDamp property");
685         int dampArg;
686         if(!PyArg_ParseTuple(args, "i:setRotDamp", &dampArg)) {
687                 return NULL;            
688         }
689         
690         m_rotDampTime = dampArg;
691         if (m_rotDampTime < 0) m_rotDampTime = 0;
692
693         Py_RETURN_NONE;
694 }
695 /* 3. getRotDamp                                                                */
696 const char KX_ConstraintActuator::GetRotDamp_doc[] = 
697 "getRotDamp()\n"
698 "\tReturns the damping time for application of the constraint.\n";
699 PyObject* KX_ConstraintActuator::PyGetRotDamp(){
700         ShowDeprecationWarning("getRotDamp()", "the rotDamp property");
701         return PyLong_FromSsize_t(m_rotDampTime);
702 }
703
704 /* 2. setDirection                                                                */
705 const char KX_ConstraintActuator::SetDirection_doc[] = 
706 "setDirection(vector)\n"
707 "\t- vector: 3-tuple\n"
708 "\tSets the reference direction in world coordinate for the orientation constraint.\n";
709 PyObject* KX_ConstraintActuator::PySetDirection(PyObject* args) {
710         ShowDeprecationWarning("setDirection()", "the direction property");
711         float x, y, z;
712         MT_Scalar len;
713         MT_Vector3 dir;
714
715         if(!PyArg_ParseTuple(args, "(fff):setDirection", &x, &y, &z)) {
716                 return NULL;            
717         }
718         dir[0] = x;
719         dir[1] = y;
720         dir[2] = z;
721         len = dir.length();
722         if (MT_fuzzyZero(len)) {
723                 std::cout << "Invalid direction" << std::endl;
724                 return NULL;
725         }
726         m_refDirVector = dir/len;
727         m_refDirection[0] = x/len;
728         m_refDirection[1] = y/len;
729         m_refDirection[2] = z/len;
730
731         Py_RETURN_NONE;
732 }
733 /* 3. getDirection                                                                */
734 const char KX_ConstraintActuator::GetDirection_doc[] = 
735 "getDirection()\n"
736 "\tReturns the reference direction of the orientation constraint as a 3-tuple.\n";
737 PyObject* KX_ConstraintActuator::PyGetDirection(){
738         ShowDeprecationWarning("getDirection()", "the direction property");
739         PyObject *retVal = PyList_New(3);
740
741         PyList_SET_ITEM(retVal, 0, PyFloat_FromDouble(m_refDirection[0]));
742         PyList_SET_ITEM(retVal, 1, PyFloat_FromDouble(m_refDirection[1]));
743         PyList_SET_ITEM(retVal, 2, PyFloat_FromDouble(m_refDirection[2]));
744         return retVal;
745 }
746
747 /* 2. setOption                                                                */
748 const char KX_ConstraintActuator::SetOption_doc[] = 
749 "setOption(option)\n"
750 "\t- option: integer\n"
751 "\tSets several options of the distance  constraint.\n"
752 "\tBinary combination of the following values:\n"
753 "\t\t 64 : Activate alignment to surface\n"
754 "\t\t128 : Detect material rather than property\n"
755 "\t\t256 : No deactivation if ray does not hit target\n"
756 "\t\t512 : Activate distance control\n";
757 PyObject* KX_ConstraintActuator::PySetOption(PyObject* args) {
758         ShowDeprecationWarning("setOption()", "the option property");
759         int option;
760         if(!PyArg_ParseTuple(args, "i:setOption", &option)) {
761                 return NULL;            
762         }
763         
764         m_option = option;
765
766         Py_RETURN_NONE;
767 }
768 /* 3. getOption                                                              */
769 const char KX_ConstraintActuator::GetOption_doc[] = 
770 "getOption()\n"
771 "\tReturns the option parameter.\n";
772 PyObject* KX_ConstraintActuator::PyGetOption(){
773         ShowDeprecationWarning("getOption()", "the option property");
774         return PyLong_FromSsize_t(m_option);
775 }
776
777 /* 2. setTime                                                                */
778 const char KX_ConstraintActuator::SetTime_doc[] = 
779 "setTime(duration)\n"
780 "\t- duration: integer\n"
781 "\tSets the activation time of the actuator.\n"
782 "\tThe actuator disables itself after this many frame.\n"
783 "\tIf set to 0 or negative, the actuator is not limited in time.\n";
784 PyObject* KX_ConstraintActuator::PySetTime(PyObject* args) {
785         ShowDeprecationWarning("setTime()", "the time property");
786         int t;
787         if(!PyArg_ParseTuple(args, "i:setTime", &t)) {
788                 return NULL;            
789         }
790         
791         if (t < 0)
792                 t = 0;
793         m_activeTime = t;
794
795         Py_RETURN_NONE;
796 }
797 /* 3. getTime                                                                */
798 const char KX_ConstraintActuator::GetTime_doc[] = 
799 "getTime()\n"
800 "\tReturns the time parameter.\n";
801 PyObject* KX_ConstraintActuator::PyGetTime(){
802         ShowDeprecationWarning("getTime()", "the time property");
803         return PyLong_FromSsize_t(m_activeTime);
804 }
805
806 /* 2. setProperty                                                                */
807 const char KX_ConstraintActuator::SetProperty_doc[] = 
808 "setProperty(property)\n"
809 "\t- property: string\n"
810 "\tSets the name of the property or material for the ray detection of the distance constraint.\n"
811 "\tIf empty, the ray will detect any collisioning object.\n";
812 PyObject* KX_ConstraintActuator::PySetProperty(PyObject* args) {
813         ShowDeprecationWarning("setProperty()", "the 'property' property");
814         char *property;
815         if (!PyArg_ParseTuple(args, "s:setProperty", &property)) {
816                 return NULL;
817         }
818         if (property == NULL) {
819                 m_property = "";
820         } else {
821                 m_property = property;
822         }
823
824         Py_RETURN_NONE;
825 }
826 /* 3. getProperty                                                                */
827 const char KX_ConstraintActuator::GetProperty_doc[] = 
828 "getProperty()\n"
829 "\tReturns the property parameter.\n";
830 PyObject* KX_ConstraintActuator::PyGetProperty(){
831         ShowDeprecationWarning("getProperty()", "the 'property' property");
832         return PyUnicode_FromString(m_property.Ptr());
833 }
834
835 /* 4. setDistance                                                                 */
836 const char KX_ConstraintActuator::SetDistance_doc[] = 
837 "setDistance(distance)\n"
838 "\t- distance: float\n"
839 "\tSets the target distance in distance constraint\n";
840 /* 4. setMin                                                                 */
841 const char KX_ConstraintActuator::SetMin_doc[] = 
842 "setMin(lower_bound)\n"
843 "\t- lower_bound: float\n"
844 "\tSets the lower value of the interval to which the value\n"
845 "\tis clipped.\n";
846 PyObject* KX_ConstraintActuator::PySetMin(PyObject* args) {
847         ShowDeprecationWarning("setMin() or setDistance()", "the min or distance property");
848         float minArg;
849         if(!PyArg_ParseTuple(args, "f:setMin", &minArg)) {
850                 return NULL;            
851         }
852
853         switch (m_locrot) {
854         default:
855                 m_minimumBound = minArg;
856                 break;
857         case KX_ACT_CONSTRAINT_ROTX:
858         case KX_ACT_CONSTRAINT_ROTY:
859         case KX_ACT_CONSTRAINT_ROTZ:
860                 m_minimumBound = MT_radians(minArg);
861                 break;
862         }
863
864         Py_RETURN_NONE;
865 }
866 /* 5. getDistance                                                                 */
867 const char KX_ConstraintActuator::GetDistance_doc[] = 
868 "getDistance()\n"
869 "\tReturns the distance parameter \n";
870 /* 5. getMin                                                                 */
871 const char KX_ConstraintActuator::GetMin_doc[] = 
872 "getMin()\n"
873 "\tReturns the lower value of the interval to which the value\n"
874 "\tis clipped.\n";
875 PyObject* KX_ConstraintActuator::PyGetMin() {
876         ShowDeprecationWarning("getMin() or getDistance()", "the min or distance property");
877         return PyFloat_FromDouble(m_minimumBound);
878 }
879
880 /* 6. setRayLength                                                                 */
881 const char KX_ConstraintActuator::SetRayLength_doc[] = 
882 "setRayLength(length)\n"
883 "\t- length: float\n"
884 "\tSets the maximum ray length of the distance constraint\n";
885 /* 6. setMax                                                                 */
886 const char KX_ConstraintActuator::SetMax_doc[] = 
887 "setMax(upper_bound)\n"
888 "\t- upper_bound: float\n"
889 "\tSets the upper value of the interval to which the value\n"
890 "\tis clipped.\n";
891 PyObject* KX_ConstraintActuator::PySetMax(PyObject* args){
892         ShowDeprecationWarning("setMax() or setRayLength()", "the max or rayLength property");
893         float maxArg;
894         if(!PyArg_ParseTuple(args, "f:setMax", &maxArg)) {
895                 return NULL;            
896         }
897
898         switch (m_locrot) {
899         default:
900                 m_maximumBound = maxArg;
901                 break;
902         case KX_ACT_CONSTRAINT_ROTX:
903         case KX_ACT_CONSTRAINT_ROTY:
904         case KX_ACT_CONSTRAINT_ROTZ:
905                 m_maximumBound = MT_radians(maxArg);
906                 break;
907         }
908
909         Py_RETURN_NONE;
910 }
911 /* 7. getRayLength                                                                 */
912 const char KX_ConstraintActuator::GetRayLength_doc[] = 
913 "getRayLength()\n"
914 "\tReturns the length of the ray\n";
915 /* 7. getMax                                                                 */
916 const char KX_ConstraintActuator::GetMax_doc[] = 
917 "getMax()\n"
918 "\tReturns the upper value of the interval to which the value\n"
919 "\tis clipped.\n";
920 PyObject* KX_ConstraintActuator::PyGetMax() {
921         ShowDeprecationWarning("getMax() or getRayLength()", "the max or rayLength property");
922         return PyFloat_FromDouble(m_maximumBound);
923 }
924
925
926 /* This setter/getter probably for the constraint type                       */
927 /* 8. setLimit                                                               */
928 const char KX_ConstraintActuator::SetLimit_doc[] = 
929 "setLimit(type)\n"
930 "\t- type: integer\n"
931 "\t  1  : LocX\n"
932 "\t  2  : LocY\n"
933 "\t  3  : LocZ\n"
934 "\t  7  : Distance along +X axis\n"
935 "\t  8  : Distance along +Y axis\n"
936 "\t  9  : Distance along +Z axis\n"
937 "\t  10 : Distance along -X axis\n"
938 "\t  11 : Distance along -Y axis\n"
939 "\t  12 : Distance along -Z axis\n"
940 "\t  13 : Align X axis\n"
941 "\t  14 : Align Y axis\n"
942 "\t  15 : Align Z axis\n"
943 "\tSets the type of constraint.\n";
944 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* args) {
945         ShowDeprecationWarning("setLimit()", "the limit property");
946         int locrotArg;
947         if(!PyArg_ParseTuple(args, "i:setLimit", &locrotArg)) {
948                 return NULL;            
949         }
950         
951         if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
952
953         Py_RETURN_NONE;
954 }
955 /* 9. getLimit                                                               */
956 const char KX_ConstraintActuator::GetLimit_doc[] = 
957 "getLimit()\n"
958 "\tReturns the type of constraint.\n";
959 PyObject* KX_ConstraintActuator::PyGetLimit() {
960         ShowDeprecationWarning("setLimit()", "the limit property");
961         return PyLong_FromSsize_t(m_locrot);
962 }
963
964 /* eof */