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