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