Initial revision
[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/BL DUAL 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. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include "SCA_IActuator.h"
36 #include "KX_ConstraintActuator.h"
37 #include "SCA_IObject.h"
38 #include "MT_Point3.h"
39 #include "MT_Matrix3x3.h"
40 #include "KX_GameObject.h"
41 /* ------------------------------------------------------------------------- */
42 /* Native functions                                                          */
43 /* ------------------------------------------------------------------------- */
44
45 KX_ConstraintActuator::KX_ConstraintActuator(SCA_IObject *gameobj, 
46                                                                                          int dampTime,
47                                                                                          float minBound,
48                                                                                          float maxBound,
49                                                                                          int locrotxyz,
50                                                                                          PyTypeObject* T)
51         : SCA_IActuator(gameobj, T)
52 {
53         m_dampTime = dampTime;
54         m_locrot   = locrotxyz;
55         /* The units of bounds are determined by the type of constraint. To      */
56         /* make the constraint application easier and more transparent later on, */
57         /* I think converting the bounds to the applicable domain makes more     */
58         /* sense.                                                                */
59         switch (m_locrot) {
60         case KX_ACT_CONSTRAINT_LOCX:
61         case KX_ACT_CONSTRAINT_LOCY:
62         case KX_ACT_CONSTRAINT_LOCZ:
63                 m_minimumBound = minBound;
64                 m_maximumBound = maxBound;
65                 break;
66         case KX_ACT_CONSTRAINT_ROTX:
67         case KX_ACT_CONSTRAINT_ROTY:
68         case KX_ACT_CONSTRAINT_ROTZ:
69                 /* The user interface asks for degrees, we are radian.               */ 
70                 m_minimumBound = MT_radians(minBound);
71                 m_maximumBound = MT_radians(maxBound);
72                 break;
73         default:
74                 ; /* error */
75         }
76
77 } /* End of constructor */
78
79 KX_ConstraintActuator::~KX_ConstraintActuator()
80
81         // there's nothing to be done here, really....
82 } /* end of destructor */
83
84 bool KX_ConstraintActuator::Update(double curtime,double deltatime)
85 {
86
87         bool result = false;    
88         bool bNegativeEvent = IsNegativeEvent();
89         RemoveAllEvents();
90
91         if (bNegativeEvent)
92                 return false; // do nothing on negative events
93
94         /* Constraint clamps the values to the specified range, with a sort of    */
95         /* low-pass filtered time response, if the damp time is unequal to 0.     */
96
97         /* Having to retrieve location/rotation and setting it afterwards may not */
98         /* be efficient enough... Somthing to look at later.                      */
99         KX_GameObject  *parent = (KX_GameObject*) GetParent();
100         MT_Point3    position = parent->NodeGetWorldPosition();
101         MT_Matrix3x3 rotation = parent->NodeGetWorldOrientation();
102 //      MT_Vector3      eulerrot = rotation.getEuler();
103         
104         switch (m_locrot) {
105         case KX_ACT_CONSTRAINT_LOCX:
106                 Clamp(position[0], m_minimumBound, m_maximumBound);
107                 break;
108         case KX_ACT_CONSTRAINT_LOCY:
109                 Clamp(position[1], m_minimumBound, m_maximumBound);
110                 break;
111         case KX_ACT_CONSTRAINT_LOCZ:
112                 Clamp(position[2], m_minimumBound, m_maximumBound);
113                 break;
114         
115 //      case KX_ACT_CONSTRAINT_ROTX:
116 //              /* The angles are Euler angles (I think that's what they are called) */
117 //              /* but we need to convert from/to the MT_Matrix3x3.                  */
118 //              Clamp(eulerrot[0], m_minimumBound, m_maximumBound);
119 //              break;
120 //      case KX_ACT_CONSTRAINT_ROTY:
121 //              Clamp(eulerrot[1], m_minimumBound, m_maximumBound);
122 //              break;
123 //      case KX_ACT_CONSTRAINT_ROTZ:
124 //              Clamp(eulerrot[2], m_minimumBound, m_maximumBound);
125 //              break;
126 //      default:
127 //              ; /* error */
128         }
129
130         /* Will be replaced by a filtered clamp. */
131         
132
133         switch (m_locrot) {
134         case KX_ACT_CONSTRAINT_LOCX:
135         case KX_ACT_CONSTRAINT_LOCY:
136         case KX_ACT_CONSTRAINT_LOCZ:
137                 parent->NodeSetLocalPosition(position);
138                 break;
139
140
141 //      case KX_ACT_CONSTRAINT_ROTX:
142 //      case KX_ACT_CONSTRAINT_ROTY:
143 //      case KX_ACT_CONSTRAINT_ROTZ:
144 //              rotation.setEuler(eulerrot);
145 //              parent->NodeSetLocalOrientation(rotation);
146                 break;
147
148         default:
149                 ; /* error */
150         }
151
152         return false;
153 } /* end of KX_ConstraintActuator::Update(double curtime,double deltatime)   */
154
155 void KX_ConstraintActuator::Clamp(MT_Scalar &var, 
156                                                                   float min, 
157                                                                   float max) {
158         if (var < min) {
159                 var = min;
160         } else if (var > max) {
161                 var = max;
162         }
163 }
164
165
166 bool KX_ConstraintActuator::IsValidMode(KX_ConstraintActuator::KX_CONSTRAINTTYPE m) 
167 {
168         bool res = false;
169
170         if ( (m > KX_ACT_CONSTRAINT_NODEF) && (m < KX_ACT_CONSTRAINT_MAX)) {
171                 res = true;
172         }
173
174         return res;
175 }
176
177 /* ------------------------------------------------------------------------- */
178 /* Python functions                                                          */
179 /* ------------------------------------------------------------------------- */
180
181 /* Integration hooks ------------------------------------------------------- */
182 PyTypeObject KX_ConstraintActuator::Type = {
183         PyObject_HEAD_INIT(&PyType_Type)
184         0,
185         "KX_ConstraintActuator",
186         sizeof(KX_ConstraintActuator),
187         0,
188         PyDestructor,
189         0,
190         __getattr,
191         __setattr,
192         0, //&MyPyCompare,
193         __repr,
194         0, //&cvalue_as_number,
195         0,
196         0,
197         0,
198         0
199 };
200
201 PyParentObject KX_ConstraintActuator::Parents[] = {
202         &KX_ConstraintActuator::Type,
203         &SCA_IActuator::Type,
204         &SCA_ILogicBrick::Type,
205         &CValue::Type,
206         NULL
207 };
208
209 PyMethodDef KX_ConstraintActuator::Methods[] = {
210         {"setDamp", (PyCFunction) KX_ConstraintActuator::sPySetDamp, METH_VARARGS, SetDamp_doc},
211         {"getDamp", (PyCFunction) KX_ConstraintActuator::sPyGetDamp, METH_VARARGS, GetDamp_doc},
212         {"setMin", (PyCFunction) KX_ConstraintActuator::sPySetMin, METH_VARARGS, SetMin_doc},
213         {"getMin", (PyCFunction) KX_ConstraintActuator::sPyGetMin, METH_VARARGS, GetMin_doc},
214         {"setMax", (PyCFunction) KX_ConstraintActuator::sPySetMax, METH_VARARGS, SetMax_doc},
215         {"getMax", (PyCFunction) KX_ConstraintActuator::sPyGetMax, METH_VARARGS, GetMax_doc},
216         {"setLimit", (PyCFunction) KX_ConstraintActuator::sPySetLimit, METH_VARARGS, SetLimit_doc},
217         {"getLimit", (PyCFunction) KX_ConstraintActuator::sPyGetLimit, METH_VARARGS, GetLimit_doc},
218         {NULL,NULL} //Sentinel
219 };
220
221 PyObject* KX_ConstraintActuator::_getattr(char* attr) {
222         _getattr_up(SCA_IActuator);
223 }
224
225 /* 2. setDamp                                                                */
226 char KX_ConstraintActuator::SetDamp_doc[] = 
227 "setDamp(duration)\n"
228 "\t- duration: integer\n"
229 "\tSets the time with which the constraint application is delayed.\n"
230 "\tIf the duration is negative, it is set to 0.\n";
231 PyObject* KX_ConstraintActuator::PySetDamp(PyObject* self, 
232                                                                                    PyObject* args, 
233                                                                                    PyObject* kwds) {
234         int dampArg;
235         if(!PyArg_ParseTuple(args, "i", &dampArg)) {
236                 return NULL;            
237         }
238         
239         m_dampTime = dampArg;
240         if (m_dampTime < 0) m_dampTime = 0;
241
242         Py_Return;
243 }
244 /* 3. getDamp                                                                */
245 char KX_ConstraintActuator::GetDamp_doc[] = 
246 "GetDamp()\n"
247 "\tReturns the damping time for application of the constraint.\n";
248 PyObject* KX_ConstraintActuator::PyGetDamp(PyObject* self, 
249                                                                                    PyObject* args, 
250                                                                                    PyObject* kwds){
251         return PyInt_FromLong(m_dampTime);
252 }
253
254 /* 4. setMin                                                                 */
255 char KX_ConstraintActuator::SetMin_doc[] = 
256 "setMin(lower_bound)\n"
257 "\t- lower_bound: float\n"
258 "\tSets the lower value of the interval to which the value\n"
259 "\tis clipped.\n";
260 PyObject* KX_ConstraintActuator::PySetMin(PyObject* self, 
261                                                                                   PyObject* args, 
262                                                                                   PyObject* kwds) {
263         float minArg;
264         if(!PyArg_ParseTuple(args, "f", &minArg)) {
265                 return NULL;            
266         }
267
268         switch (m_locrot) {
269         case KX_ACT_CONSTRAINT_LOCX:
270         case KX_ACT_CONSTRAINT_LOCY:
271         case KX_ACT_CONSTRAINT_LOCZ:
272                 m_minimumBound = minArg;
273                 break;
274         case KX_ACT_CONSTRAINT_ROTX:
275         case KX_ACT_CONSTRAINT_ROTY:
276         case KX_ACT_CONSTRAINT_ROTZ:
277                 m_minimumBound = MT_radians(minArg);
278                 break;
279         default:
280                 ; /* error */
281         }
282
283         Py_Return;
284 }
285 /* 5. getMin                                                                 */
286 char KX_ConstraintActuator::GetMin_doc[] = 
287 "getMin()\n"
288 "\tReturns the lower value of the interval to which the value\n"
289 "\tis clipped.\n";
290 PyObject* KX_ConstraintActuator::PyGetMin(PyObject* self, 
291                                                                                   PyObject* args, 
292                                                                                   PyObject* kwds) {
293         return PyFloat_FromDouble(m_minimumBound);
294 }
295
296 /* 6. setMax                                                                 */
297 char KX_ConstraintActuator::SetMax_doc[] = 
298 "setMax(upper_bound)\n"
299 "\t- upper_bound: float\n"
300 "\tSets the upper value of the interval to which the value\n"
301 "\tis clipped.\n";
302 PyObject* KX_ConstraintActuator::PySetMax(PyObject* self, 
303                                                                                   PyObject* args, 
304                                                                                   PyObject* kwds){
305         float maxArg;
306         if(!PyArg_ParseTuple(args, "f", &maxArg)) {
307                 return NULL;            
308         }
309
310         switch (m_locrot) {
311         case KX_ACT_CONSTRAINT_LOCX:
312         case KX_ACT_CONSTRAINT_LOCY:
313         case KX_ACT_CONSTRAINT_LOCZ:
314                 m_maximumBound = maxArg;
315                 break;
316         case KX_ACT_CONSTRAINT_ROTX:
317         case KX_ACT_CONSTRAINT_ROTY:
318         case KX_ACT_CONSTRAINT_ROTZ:
319                 m_maximumBound = MT_radians(maxArg);
320                 break;
321         default:
322                 ; /* error */
323         }
324
325         Py_Return;
326 }
327 /* 7. getMax                                                                 */
328 char KX_ConstraintActuator::GetMax_doc[] = 
329 "getMax()\n"
330 "\tReturns the upper value of the interval to which the value\n"
331 "\tis clipped.\n";
332 PyObject* KX_ConstraintActuator::PyGetMax(PyObject* self, 
333                                                                                   PyObject* args, 
334                                                                                   PyObject* kwds) {
335         return PyFloat_FromDouble(m_maximumBound);
336 }
337
338
339 /* This setter/getter probably for the constraint type                       */
340 /* 8. setLimit                                                               */
341 char KX_ConstraintActuator::SetLimit_doc[] = 
342 "setLimit(type)\n"
343 "\t- type: KX_CONSTRAINTACT_LOCX, KX_CONSTRAINTACT_LOCY,\n"
344 "\t        KX_CONSTRAINTACT_LOCZ, KX_CONSTRAINTACT_ROTX,\n"
345 "\t        KX_CONSTRAINTACT_ROTY, or KX_CONSTRAINTACT_ROTZ.\n"
346 "\tSets the type of constraint.\n";
347 PyObject* KX_ConstraintActuator::PySetLimit(PyObject* self, 
348                                                                                         PyObject* args, 
349                                                                                         PyObject* kwds) {
350         int locrotArg;
351         if(!PyArg_ParseTuple(args, "i", &locrotArg)) {
352                 return NULL;            
353         }
354         
355         if (IsValidMode((KX_CONSTRAINTTYPE)locrotArg)) m_locrot = locrotArg;
356
357         Py_Return;
358 }
359 /* 9. getLimit                                                               */
360 char KX_ConstraintActuator::GetLimit_doc[] = 
361 "getLimit(type)\n"
362 "\tReturns the type of constraint.\n";
363 PyObject* KX_ConstraintActuator::PyGetLimit(PyObject* self, 
364                                                                                         PyObject* args, 
365                                                                                         PyObject* kwds) {
366         return PyInt_FromLong(m_locrot);
367 }
368
369 /* eof */