Merge of itasc branch. Project files, scons and cmake should be working. Makefile...
[blender.git] / source / gameengine / Ketsji / KX_PythonSeq.cpp
1 /**
2  * $Id: 
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: none of this file.
24  *
25  * Contributor(s): Campbell Barton
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  * Readonly sequence wrapper for lookups on logic bricks
29  */
30
31
32 #include "KX_PythonSeq.h"
33 #include "KX_GameObject.h"
34 #include "BL_ArmatureObject.h"
35 #include "SCA_ISensor.h"
36 #include "SCA_IController.h"
37 #include "SCA_IActuator.h"
38
39
40 PyObject *KX_PythonSeq_CreatePyObject( PyObject *base, short type )
41 {
42         KX_PythonSeq *seq = PyObject_NEW( KX_PythonSeq, &KX_PythonSeq_Type);
43         seq->base = base;
44         Py_INCREF(base); /* so we can always access to check if its valid */
45         seq->type = type;
46         seq->iter = -1; /* init */
47         return (PyObject *)seq;
48  }
49  
50  static void KX_PythonSeq_dealloc( KX_PythonSeq * self )
51 {
52         Py_DECREF(self->base);
53         PyObject_DEL( self );
54 }
55
56 static Py_ssize_t KX_PythonSeq_len( PyObject * self )
57 {
58         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
59          
60         if(self_plus==NULL) {
61                 PyErr_SetString(PyExc_SystemError, "len(seq): "BGE_PROXY_ERROR_MSG);
62                 return -1;
63         }
64         
65         switch(((KX_PythonSeq *)self)->type) {
66         case KX_PYGENSEQ_CONT_TYPE_SENSORS:
67                 return ((SCA_IController *)self_plus)->GetLinkedSensors().size();
68         case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
69                 return ((SCA_IController *)self_plus)->GetLinkedActuators().size();
70         case KX_PYGENSEQ_OB_TYPE_SENSORS:
71                 return ((KX_GameObject *)self_plus)->GetSensors().size();
72         case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
73                 return ((KX_GameObject *)self_plus)->GetControllers().size();
74         case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
75                 return ((KX_GameObject *)self_plus)->GetActuators().size();
76         case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
77                 return ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
78         case KX_PYGENSEQ_OB_TYPE_CHANNELS:
79                 return ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
80         default:
81                 /* Should never happen */
82                 PyErr_SetString(PyExc_SystemError, "invalid type, internal error");
83                 return -1;
84         }
85 }
86
87 static PyObject *KX_PythonSeq_getIndex(PyObject* self, int index)
88 {
89         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
90          
91         if(self_plus==NULL) {
92                 PyErr_SetString(PyExc_SystemError, "val = seq[i]: "BGE_PROXY_ERROR_MSG);
93                 return NULL;
94         }
95         
96         switch(((KX_PythonSeq *)self)->type) {
97                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
98                 {
99                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
100                         if(index<0) index += linkedsensors.size();
101                         if(index<0 || index>= linkedsensors.size()) {
102                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
103                                 return NULL;
104                         }
105                         return linkedsensors[index]->GetProxy();
106                 }
107                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
108                 {
109                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
110                         if(index<0) index += linkedactuators.size();
111                         if(index<0 || index>= linkedactuators.size()) {
112                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
113                                 return NULL;
114                         }
115                         return linkedactuators[index]->GetProxy();
116                 }
117                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
118                 {
119                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
120                         if(index<0) index += linkedsensors.size();
121                         if(index<0 || index>= linkedsensors.size()) {
122                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
123                                 return NULL;
124                         }
125                         return linkedsensors[index]->GetProxy();
126                 }
127                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
128                 {
129                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
130                         if(index<0) index += linkedcontrollers.size();
131                         if(index<0 || index>= linkedcontrollers.size()) {
132                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
133                                 return NULL;
134                         }
135                         return linkedcontrollers[index]->GetProxy();
136                 }
137                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
138                 {
139                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
140                         if(index<0) index += linkedactuators.size();
141                         if(index<0 || index>= linkedactuators.size()) {
142                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
143                                 return NULL;
144                         }
145                         return linkedactuators[index]->GetProxy();
146                 }
147                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
148                 {
149                         int nb_constraint = ((BL_ArmatureObject *)self_plus)->GetConstraintNumber();
150                         if(index<0) 
151                                 index += nb_constraint;
152                         if(index<0 || index>= nb_constraint) {
153                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
154                                 return NULL;
155                         }
156                         return ((BL_ArmatureObject *)self_plus)->GetConstraint(index)->GetProxy();
157                 }
158                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
159                 {
160                         int nb_channel = ((BL_ArmatureObject *)self_plus)->GetChannelNumber();
161                         if(index<0) 
162                                 index += nb_channel;
163                         if(index<0 || index>= nb_channel) {
164                                 PyErr_SetString(PyExc_IndexError, "seq[i]: index out of range");
165                                 return NULL;
166                         }
167                         return ((BL_ArmatureObject *)self_plus)->GetChannel(index)->GetProxy();
168                 }
169
170         }
171         
172         PyErr_SetString(PyExc_SystemError, "invalid sequence type, this is a bug");
173         return NULL;
174 }
175
176 static PyObjectPlus * KX_PythonSeq_subscript__internal(PyObject *self, char *key)
177 {
178         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
179         
180         switch(((KX_PythonSeq *)self)->type) {
181                 case KX_PYGENSEQ_CONT_TYPE_SENSORS:
182                 {
183                         vector<SCA_ISensor*>& linkedsensors = ((SCA_IController *)self_plus)->GetLinkedSensors();
184                         SCA_ISensor* sensor;
185                         for (unsigned int index=0;index<linkedsensors.size();index++) {
186                                 sensor = linkedsensors[index];
187                                 if (sensor->GetName() == key)
188                                         return static_cast<PyObjectPlus *>(sensor);
189                                 
190                         }
191                         break;
192                 }
193                 case KX_PYGENSEQ_CONT_TYPE_ACTUATORS:
194                 {
195                         vector<SCA_IActuator*>& linkedactuators = ((SCA_IController *)self_plus)->GetLinkedActuators();
196                         SCA_IActuator* actuator;
197                         for (unsigned int index=0;index<linkedactuators.size();index++) {
198                                 actuator = linkedactuators[index];
199                                 if (actuator->GetName() == key)
200                                         return static_cast<PyObjectPlus *>(actuator);
201                         }
202                         break;
203                 }
204                 case KX_PYGENSEQ_OB_TYPE_SENSORS:
205                 {
206                         SCA_SensorList& linkedsensors= ((KX_GameObject *)self_plus)->GetSensors();
207                         SCA_ISensor *sensor;
208                         for (unsigned int index=0;index<linkedsensors.size();index++) {
209                                 sensor= linkedsensors[index];
210                                 if (sensor->GetName() == key)
211                                         return static_cast<PyObjectPlus *>(sensor);
212                         }
213                         break;
214                 }
215                 case KX_PYGENSEQ_OB_TYPE_CONTROLLERS:
216                 {
217                         SCA_ControllerList& linkedcontrollers= ((KX_GameObject *)self_plus)->GetControllers();
218                         SCA_IController *controller;
219                         for (unsigned int index=0;index<linkedcontrollers.size();index++) {
220                                 controller= linkedcontrollers[index];
221                                 if (controller->GetName() == key)
222                                         return static_cast<PyObjectPlus *>(controller);
223                         }
224                         break;
225                 }
226                 case KX_PYGENSEQ_OB_TYPE_ACTUATORS:
227                 {
228                         SCA_ActuatorList& linkedactuators= ((KX_GameObject *)self_plus)->GetActuators();
229                         SCA_IActuator *actuator;
230                         for (unsigned int index=0;index<linkedactuators.size();index++) {
231                                 actuator= linkedactuators[index];
232                                 if (actuator->GetName() == key)
233                                         return static_cast<PyObjectPlus *>(actuator);
234                         }
235                         break;
236                 }
237                 case KX_PYGENSEQ_OB_TYPE_CONSTRAINTS:
238                 {
239                         return ((BL_ArmatureObject*)self_plus)->GetConstraint(key);
240                 }
241                 case KX_PYGENSEQ_OB_TYPE_CHANNELS:
242                 {
243                         return ((BL_ArmatureObject*)self_plus)->GetChannel(key);
244                 }
245         }
246         
247         return NULL;
248 }
249
250
251 static PyObject * KX_PythonSeq_subscript(PyObject * self, PyObject *key)
252 {
253         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
254         
255         if(self_plus==NULL) {
256                 PyErr_SetString(PyExc_SystemError, "val = seq[key], KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
257                 return NULL;
258         }
259         
260         if (PyLong_Check(key)) {
261                 return KX_PythonSeq_getIndex(self, PyLong_AsSsize_t( key ));
262         }
263         else if ( PyUnicode_Check(key) ) {
264                 char *name = _PyUnicode_AsString(key);
265                 PyObjectPlus *ret = KX_PythonSeq_subscript__internal(self, name);
266                 
267                 if(ret) {
268                         return ret->GetProxy();
269                 } else {
270                         PyErr_Format( PyExc_KeyError, "requested item \"%s\" does not exist", name);
271                         return NULL;
272                 }
273         }
274         else {
275                 PyErr_SetString( PyExc_TypeError, "expected a string or an index" );
276                 return NULL;
277         }
278 }
279
280
281 static int KX_PythonSeq_contains(PyObject *self, PyObject *key)
282 {
283         PyObjectPlus *self_plus= BGE_PROXY_REF(((KX_PythonSeq *)self)->base);
284         
285         if(self_plus==NULL) {
286                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: "BGE_PROXY_ERROR_MSG);
287                 return -1;
288         }
289         if(!PyUnicode_Check(key)) {
290                 PyErr_SetString(PyExc_SystemError, "key in seq, KX_PythonSeq: key must be a string");
291                 return -1;
292         }
293         
294         if(KX_PythonSeq_subscript__internal(self, _PyUnicode_AsString(key)))
295                 return 1;
296         
297         return 0;
298 }
299
300 /* Matches python dict.get(key, [default]) */
301 PyObject* KX_PythonSeq_get(PyObject * self, PyObject *args)
302 {
303         char *key;
304         PyObject* def = Py_None;
305         PyObjectPlus* ret_plus;
306
307         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
308                 return NULL;
309         
310         if((ret_plus = KX_PythonSeq_subscript__internal(self, key)))
311                 return ret_plus->GetProxy();
312         
313         Py_INCREF(def);
314         return def;
315 }
316
317 PySequenceMethods KX_PythonSeq_as_sequence = {
318         NULL,           /* Cant set the len otherwise it can evaluate as false */
319         NULL,           /* sq_concat */
320         NULL,           /* sq_repeat */
321         NULL,           /* sq_item */
322         NULL,           /* sq_slice */
323         NULL,           /* sq_ass_item */
324         NULL,           /* sq_ass_slice */
325         (objobjproc)KX_PythonSeq_contains,      /* sq_contains */
326 };
327
328 static PyMappingMethods KX_PythonSeq_as_mapping = {
329         KX_PythonSeq_len,       /* mp_length */
330         KX_PythonSeq_subscript, /* mp_subscript */
331         0,      /* mp_ass_subscript */
332 };
333
334 PyMethodDef KX_PythonSeq_methods[] = {
335         // dict style access for props
336         {"get",(PyCFunction) KX_PythonSeq_get, METH_VARARGS},
337         {NULL,NULL} //Sentinel
338 };
339
340 /*
341  * Initialize the interator index
342  */
343
344 static PyObject *KX_PythonSeq_getIter(KX_PythonSeq *self)
345 {
346         if(BGE_PROXY_REF(self->base)==NULL) {
347                 PyErr_SetString(PyExc_SystemError, "for i in seq: "BGE_PROXY_ERROR_MSG);
348                 return NULL;
349         }
350         
351         /* create a new iterator if were alredy using this one */
352         if (self->iter == -1) {
353                 self->iter = 0;
354                 Py_INCREF(self);
355                 return (PyObject *)self;
356         } else {
357                 return KX_PythonSeq_CreatePyObject(self->base, self->type);
358         }
359  }
360  
361
362 /*
363  * Return next KX_PythonSeq iter.
364  */
365  
366 static PyObject *KX_PythonSeq_nextIter(KX_PythonSeq *self)
367 {
368         PyObject *object = KX_PythonSeq_getIndex((PyObject *)self, self->iter);
369         
370         self->iter++;
371         if( object==NULL ) {
372                 self->iter= -1; /* for reuse */
373                 PyErr_SetString(PyExc_StopIteration,    "iterator at end");
374         }
375         return object; /* can be NULL for end of iterator */
376 }
377
378
379 static int KX_PythonSeq_compare( KX_PythonSeq * a, KX_PythonSeq * b )
380 {
381         return ( a->type == b->type && a->base == b->base) ? 0 : -1;    
382 }
383
384 static PyObject *KX_PythonSeq_richcmp(PyObject *a, PyObject *b, int op)
385 {
386         PyObject *res;
387         int ok= -1; /* zero is true */
388
389         if(BPy_KX_PythonSeq_Check(a) && BPy_KX_PythonSeq_Check(b))
390                 ok= KX_PythonSeq_compare((KX_PythonSeq *)a, (KX_PythonSeq *)b);
391         
392         switch (op) {
393         case Py_NE:
394                 ok = !ok; /* pass through */
395         case Py_EQ:
396                 res = ok ? Py_False : Py_True;
397                 break;
398
399         case Py_LT:
400         case Py_LE:
401         case Py_GT:
402         case Py_GE:
403                 res = Py_NotImplemented;
404                 break;
405         default:
406                 PyErr_BadArgument();
407                 return NULL;
408         }
409         
410         Py_INCREF(res);
411         return res;
412 }
413
414
415 /*
416  * repr function
417  * convert to a list and get its string value
418  */
419 static PyObject *KX_PythonSeq_repr( KX_PythonSeq * self )
420 {
421         PyObject *list = PySequence_List((PyObject *)self);
422         PyObject *repr = PyObject_Repr(list);
423         Py_DECREF(list);
424         return repr;
425 }
426
427
428 /*****************************************************************************/
429 /* Python KX_PythonSeq_Type structure definition:                               */
430 /*****************************************************************************/
431 PyTypeObject KX_PythonSeq_Type = {
432         PyVarObject_HEAD_INIT(NULL, 0)
433         /*  For printing, in format "<module>.<name>" */
434         "KX_PythonSeq",           /* char *tp_name; */
435         sizeof( KX_PythonSeq ),       /* int tp_basicsize; */
436         0,                          /* tp_itemsize;  For allocation */
437
438         /* Methods to implement standard operations */
439
440         ( destructor ) KX_PythonSeq_dealloc, /* destructor tp_dealloc; */
441         NULL,                       /* printfunc tp_print; */
442         NULL,                       /* getattrfunc tp_getattr; */
443         NULL,                       /* setattrfunc tp_setattr; */
444         NULL,                                           /* cmpfunc tp_compare; */
445         ( reprfunc ) KX_PythonSeq_repr,   /* reprfunc tp_repr; */
446
447         /* Method suites for standard classes */
448
449         NULL,                       /* PyNumberMethods *tp_as_number; */
450         &KX_PythonSeq_as_sequence,          /* PySequenceMethods *tp_as_sequence; */
451         &KX_PythonSeq_as_mapping,                       /* PyMappingMethods *tp_as_mapping; */
452
453         /* More standard operations (here for binary compatibility) */
454
455         NULL,                       /* hashfunc tp_hash; */
456         NULL,                       /* ternaryfunc tp_call; */
457         NULL,                       /* reprfunc tp_str; */
458         NULL,                       /* getattrofunc tp_getattro; */
459         NULL,                       /* setattrofunc tp_setattro; */
460
461         /* Functions to access object as input/output buffer */
462         NULL,                       /* PyBufferProcs *tp_as_buffer; */
463
464   /*** Flags to define presence of optional/expanded features ***/
465         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
466
467         NULL,                       /*  char *tp_doc;  Documentation string */
468   /*** Assigned meaning in release 2.0 ***/
469         /* call function for all accessible objects */
470         NULL,                                           /* traverseproc tp_traverse; */
471
472         /* delete references to contained objects */
473         NULL,                       /* inquiry tp_clear; */
474
475   /***  Assigned meaning in release 2.1 ***/
476   /*** rich comparisons ***/
477         (richcmpfunc)KX_PythonSeq_richcmp,      /* richcmpfunc tp_richcompare; */
478
479   /***  weak reference enabler ***/
480         0,                          /* long tp_weaklistoffset; */
481
482   /*** Added in release 2.2 ***/
483         /*   Iterators */
484         ( getiterfunc) KX_PythonSeq_getIter, /* getiterfunc tp_iter; */
485         ( iternextfunc ) KX_PythonSeq_nextIter, /* iternextfunc tp_iternext; */
486
487   /*** Attribute descriptor and subclassing stuff ***/
488         KX_PythonSeq_methods,       /* struct PyMethodDef *tp_methods; */
489         NULL,                       /* struct PyMemberDef *tp_members; */
490         NULL,       /* struct PyGetSetDef *tp_getset; */
491         NULL,                       /* struct _typeobject *tp_base; */
492         NULL,                       /* PyObject *tp_dict; */
493         NULL,                       /* descrgetfunc tp_descr_get; */
494         NULL,                       /* descrsetfunc tp_descr_set; */
495         0,                          /* long tp_dictoffset; */
496         NULL,                       /* initproc tp_init; */
497         NULL,                       /* allocfunc tp_alloc; */
498         NULL,                       /* newfunc tp_new; */
499         /*  Low-level free-memory routine */
500         NULL,                       /* freefunc tp_free;  */
501         /* For PyObject_IS_GC */
502         NULL,                       /* inquiry tp_is_gc;  */
503         NULL,                       /* PyObject *tp_bases; */
504         /* method resolution order */
505         NULL,                       /* PyObject *tp_mro;  */
506         NULL,                       /* PyObject *tp_cache; */
507         NULL,                       /* PyObject *tp_subclasses; */
508         NULL,                       /* PyObject *tp_weaklist; */
509         NULL
510 };