Python API update. Again by Anders Nilsson.
[blender-staging.git] / source / blender / python / api2_2x / Object.c
1 /* 
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
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  *
26  * The Object module provides generic access to Objects of various types via
27  * the Python interface.
28  *
29  *
30  * Contributor(s): Michel Selten, Willian Germano, Jacques Guignot,
31  * Joseph Gilbert, Stephen Swaney, Bala Gi
32  *
33  * ***** END GPL/BL DUAL LICENSE BLOCK *****
34 */
35
36 #include "Object.h"
37
38 /*****************************************************************************/
39 /* Python API function prototypes for the Blender module.                                        */
40 /*****************************************************************************/
41 static PyObject *M_Object_New(PyObject *self, PyObject *args);
42 PyObject *M_Object_Get(PyObject *self, PyObject *args);
43 PyObject *M_Object_get(PyObject *self, PyObject *args);
44 static PyObject *M_Object_GetSelected (PyObject *self, PyObject *args);
45 static PyObject *M_Object_getSelected (PyObject *self, PyObject *args);
46
47 /*****************************************************************************/
48 /* The following string definitions are used for documentation strings.          */
49 /* In Python these will be written to the console when doing a                           */
50 /* Blender.Object.__doc__                                                                                                        */
51 /*****************************************************************************/
52 char M_Object_doc[] =
53 "The Blender Object module\n\n\
54 This module provides access to **Object Data** in Blender.\n";
55
56 char M_Object_New_doc[] =
57 "(type) - Add a new object of type 'type' in the current scene";
58
59 char M_Object_Get_doc[] =
60 "(name) - return the object with the name 'name', returns None if not\
61         found.\n\
62         If 'name' is not specified, it returns a list of all objects in the\n\
63         current scene.";
64
65 char M_Object_GetSelected_doc[] =
66 "() - Returns a list of selected Objects in the active layer(s)\n\
67 The active object is the first in the list, if visible";
68
69 /*****************************************************************************/
70 /* Python method structure definition for Blender.Object module:                         */
71 /*****************************************************************************/
72 struct PyMethodDef M_Object_methods[] = {
73         {"New",                 (PyCFunction)M_Object_New,                 METH_VARARGS,
74                                         M_Object_New_doc},
75         {"Get",                 (PyCFunction)M_Object_Get,                 METH_VARARGS,
76                                         M_Object_Get_doc},
77         {"get",                 (PyCFunction)M_Object_get,                 METH_VARARGS,
78                                         M_Object_Get_doc},
79         {"GetSelected", (PyCFunction)M_Object_GetSelected, METH_VARARGS,
80                                         M_Object_GetSelected_doc},
81         {"getSelected", (PyCFunction)M_Object_getSelected, METH_VARARGS,
82                                         M_Object_GetSelected_doc},
83         {NULL, NULL, 0, NULL}
84 };
85
86 /*****************************************************************************/
87 /* Python BPy_Object methods declarations:                                                                         */
88 /*****************************************************************************/
89 static PyObject *Object_buildParts (BPy_Object *self);
90 static PyObject *Object_clearIpo (BPy_Object *self);
91 static PyObject *Object_clrParent (BPy_Object *self, PyObject *args);
92 static PyObject *Object_getActionIpos (BPy_Object *self);
93 static PyObject *Object_getData (BPy_Object *self);
94 static PyObject *Object_getDeltaLocation (BPy_Object *self);
95 static PyObject *Object_getDrawMode (BPy_Object *self);
96 static PyObject *Object_getDrawType (BPy_Object *self);
97 static PyObject *Object_getEuler (BPy_Object *self);
98 static PyObject *Object_getInverseMatrix (BPy_Object *self);
99 static PyObject *Object_getIpo (BPy_Object *self);
100 static PyObject *Object_getLocation (BPy_Object *self, PyObject *args);
101 static PyObject *Object_getMaterials (BPy_Object *self);
102 static PyObject *Object_getMatrix (BPy_Object *self);
103 static PyObject *Object_getName (BPy_Object *self);
104 static PyObject *Object_getParent (BPy_Object *self);
105 static PyObject *Object_getSize (BPy_Object *self, PyObject *args);
106 static PyObject *Object_getTimeOffset (BPy_Object *self);
107 static PyObject *Object_getTracked (BPy_Object *self);
108 static PyObject *Object_getType (BPy_Object *self);
109 static PyObject *Object_getBoundBox (BPy_Object *self);
110 static PyObject *Object_makeDisplayList (BPy_Object *self);
111 static PyObject *Object_link (BPy_Object *self, PyObject *args);
112 static PyObject *Object_makeParent (BPy_Object *self, PyObject *args);
113 static PyObject *Object_materialUsage (BPy_Object *self, PyObject *args);
114 static PyObject *Object_setDeltaLocation (BPy_Object *self, PyObject *args);
115 static PyObject *Object_setDrawMode (BPy_Object *self, PyObject *args);
116 static PyObject *Object_setDrawType (BPy_Object *self, PyObject *args);
117 static PyObject *Object_setEuler (BPy_Object *self, PyObject *args);\
118 static PyObject *Object_setMatrix (BPy_Object *self, PyObject *args);
119 static PyObject *Object_setIpo (BPy_Object *self, PyObject *args);
120 static PyObject *Object_setLocation (BPy_Object *self, PyObject *args);
121 static PyObject *Object_setMaterials (BPy_Object *self, PyObject *args);
122 static PyObject *Object_setName (BPy_Object *self, PyObject *args);
123 static PyObject *Object_setSize (BPy_Object *self, PyObject *args);
124 static PyObject *Object_setTimeOffset (BPy_Object *self, PyObject *args);
125 static PyObject *Object_shareFrom (BPy_Object *self, PyObject *args);
126
127 /*****************************************************************************/
128 /* Python BPy_Object methods table:                                                                                        */
129 /*****************************************************************************/
130 static PyMethodDef BPy_Object_methods[] = {
131         /* name, method, flags, doc */
132   {"buildParts", (PyCFunction)Object_buildParts, METH_NOARGS,
133         "Recalcs particle system (if any) "},
134   {"getIpo", (PyCFunction)Object_getIpo, METH_NOARGS,
135                 "Returns the ipo of this object (if any) "},   
136   {"clrParent", (PyCFunction)Object_clrParent, METH_VARARGS,
137         "Clears parent object. Optionally specify:\n\
138 mode\n\t2: Keep object transform\nfast\n\t>0: Don't update scene \
139 hierarchy (faster)"},
140   {"getActionIpos", (PyCFunction)Object_getActionIpos, METH_NOARGS,
141         "() - Return a dict of (name:ipo)-keys containing each channel in the object's action"},
142   {"getData", (PyCFunction)Object_getData, METH_NOARGS,
143         "Returns the datablock object containing the object's data, e.g. Mesh"},
144   {"getDeltaLocation", (PyCFunction)Object_getDeltaLocation, METH_NOARGS,
145         "Returns the object's delta location (x, y, z)"},
146   {"getDrawMode", (PyCFunction)Object_getDrawMode, METH_NOARGS,
147         "Returns the object draw modes"},
148   {"getDrawType", (PyCFunction)Object_getDrawType, METH_NOARGS,
149         "Returns the object draw type"},
150   {"getEuler", (PyCFunction)Object_getEuler, METH_NOARGS,
151         "Returns the object's rotation as Euler rotation vector\n\
152 (rotX, rotY, rotZ)"},
153   {"getInverseMatrix", (PyCFunction)Object_getInverseMatrix, METH_NOARGS,
154         "Returns the object's inverse matrix"},
155   {"getLocation", (PyCFunction)Object_getLocation, METH_VARARGS,
156         "Returns the object's location (x, y, z)"},
157   {"getMaterials", (PyCFunction)Object_getMaterials, METH_NOARGS,
158         "Returns list of materials assigned to the object"},
159   {"getMatrix", (PyCFunction)Object_getMatrix, METH_NOARGS,
160         "Returns the object matrix"},
161   {"getName", (PyCFunction)Object_getName, METH_NOARGS,
162         "Returns the name of the object"},
163   {"getParent", (PyCFunction)Object_getParent, METH_NOARGS,
164         "Returns the object's parent object"},
165   {"getSize", (PyCFunction)Object_getSize, METH_VARARGS,
166         "Returns the object's size (x, y, z)"},
167   {"getTimeOffset", (PyCFunction)Object_getTimeOffset, METH_NOARGS,
168         "Returns the object's time offset"},
169   {"getTracked", (PyCFunction)Object_getTracked, METH_NOARGS,
170         "Returns the object's tracked object"},
171   {"getType", (PyCFunction)Object_getType, METH_NOARGS,
172         "Returns type of string of Object"},
173   {"getBoundBox", (PyCFunction)Object_getBoundBox, METH_NOARGS,
174         "Returns the object's bounding box"},
175   {"makeDisplayList", (PyCFunction)Object_makeDisplayList, METH_NOARGS,
176         "Update this object's Display List. Some changes like turning \n\
177 'SubSurf' on for a mesh need this method (followed by a Redraw) to \n\
178 show the changes on the 3d window."},
179   {"link", (PyCFunction)Object_link, METH_VARARGS,
180         "Links Object with data provided in the argument. The data must \n\
181 match the Object's type, so you cannot link a Lamp to a Mesh type object."},
182   {"makeParent", (PyCFunction)Object_makeParent, METH_VARARGS,
183         "Makes the object the parent of the objects provided in the \n\
184 argument which must be a list of valid Objects. Optional extra arguments:\n\
185 mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
186 fase:\n\t0: update scene hierarchy automatically\n\t\
187 don't update scene hierarchy (faster). In this case, you must\n\t\
188 explicitely update the Scene hierarchy."},
189   {"materialUsage", (PyCFunction)Object_materialUsage, METH_VARARGS,
190         "Determines the way the material is used and returns status.\n\
191 Possible arguments (provide as strings):\n\
192 \tData:   Materials assigned to the object's data are shown. (default)\n\
193 \tObject: Materials assigned to the object are shown."},
194   {"setDeltaLocation", (PyCFunction)Object_setDeltaLocation, METH_VARARGS,
195         "Sets the object's delta location which must be a vector triple."},
196   {"setDrawMode", (PyCFunction)Object_setDrawMode, METH_VARARGS,
197         "Sets the object's drawing mode. The argument can be a sum of:\n\
198 2:      axis\n4:  texspace\n8:  drawname\n16: drawimage\n32: drawwire"},
199   {"setDrawType", (PyCFunction)Object_setDrawType, METH_VARARGS,
200         "Sets the object's drawing type. The argument must be one of:\n\
201 1: Bounding box\n2: Wire\n3: Solid\n4: Shaded\n5: Textured"},
202   {"setEuler", (PyCFunction)Object_setEuler, METH_VARARGS,
203         "Set the object's rotation according to the specified Euler\n\
204 angles. The argument must be a vector triple"},
205   {"setMatrix", (PyCFunction)Object_setMatrix, METH_VARARGS,
206         "Set and apply a new matrix for the object"},
207   {"setLocation", (PyCFunction)Object_setLocation, METH_VARARGS,
208         "Set the object's location. The first argument must be a vector\n\
209 triple."},
210   {"setMaterials", (PyCFunction)Object_setMaterials, METH_VARARGS,
211         "Sets materials. The argument must be a list of valid material\n\
212 objects."},
213   {"setName", (PyCFunction)Object_setName, METH_VARARGS,
214         "Sets the name of the object"},
215   {"setSize", (PyCFunction)Object_setSize, METH_VARARGS,
216         "Set the object's size. The first argument must be a vector\n\
217 triple."},
218   {"setTimeOffset", (PyCFunction)Object_setTimeOffset, METH_VARARGS,
219         "Set the object's time offset."},
220   {"shareFrom", (PyCFunction)Object_shareFrom, METH_VARARGS,
221         "Link data of self with object specified in the argument. This\n\
222 works only if self and the object specified are of the same type."},
223   {"setIpo", (PyCFunction)Object_setIpo, METH_VARARGS,
224         "(Blender Ipo) - Sets the object's ipo"},
225   {"clearIpo", (PyCFunction)Object_clearIpo, METH_NOARGS,
226         "() - Unlink ipo from this object"},
227   {0}
228 };
229
230 /*****************************************************************************/
231 /* PythonTypeObject callback function prototypes                                                         */
232 /*****************************************************************************/
233 static void              Object_dealloc (BPy_Object *obj);
234 static PyObject* Object_getAttr (BPy_Object *obj, char *name);
235 static int               Object_setAttr (BPy_Object *obj, char *name, PyObject *v);
236 static PyObject* Object_repr    (BPy_Object *obj);
237 static int               Object_compare (BPy_Object *a, BPy_Object *b);
238
239 /*****************************************************************************/
240 /* Python TypeObject structure definition.                                                                       */
241 /*****************************************************************************/
242 PyTypeObject Object_Type =
243 {
244   PyObject_HEAD_INIT(NULL)
245   0,                                                            /* ob_size */
246   "Blender Object",                                     /* tp_name */
247   sizeof (BPy_Object),                          /* tp_basicsize */
248   0,                                                            /* tp_itemsize */
249   /* methods */
250   (destructor)Object_dealloc,           /* tp_dealloc */
251   0,                                                            /* tp_print */
252   (getattrfunc)Object_getAttr,          /* tp_getattr */
253   (setattrfunc)Object_setAttr,          /* tp_setattr */
254   (cmpfunc)Object_compare,                      /* tp_compare */
255   (reprfunc)Object_repr,                        /* tp_repr */
256   0,                                                            /* tp_as_number */
257   0,                                                            /* tp_as_sequence */
258   0,                                                            /* tp_as_mapping */
259   0,                                                            /* tp_as_hash */
260   0,0,0,0,0,0,
261   0,                                                            /* tp_doc */ 
262   0,0,0,0,0,0,
263   BPy_Object_methods,                           /* tp_methods */
264   0,                                                            /* tp_members */
265 };
266
267 /*****************************************************************************/
268 /* Function:                      M_Object_New                                                                           */
269 /* Python equivalent:     Blender.Object.New                                                             */
270 /*****************************************************************************/
271 PyObject *M_Object_New(PyObject *self, PyObject *args)
272 {
273   struct Object * object;
274   BPy_Object      * blen_object;
275   int           type;
276   char  * str_type;
277   char  * name = NULL;
278
279   if (!PyArg_ParseTuple(args, "s|s", &str_type, &name))
280   {
281                 PythonReturnErrorObject (PyExc_TypeError, "string expected as argument");
282                 return (NULL);
283   }
284
285   if (strcmp (str_type, "Armature") == 0)         type = OB_ARMATURE;
286   else if (strcmp (str_type, "Camera") == 0)  type = OB_CAMERA;
287   else if (strcmp (str_type, "Curve") == 0)   type = OB_CURVE;
288 /*      else if (strcmp (str_type, "Text") == 0)        type = OB_FONT; */
289 /*      else if (strcmp (str_type, "Ika") == 0)         type = OB_IKA; */
290   else if (strcmp (str_type, "Lamp") == 0)        type = OB_LAMP;
291   else if (strcmp (str_type, "Lattice") == 0) type = OB_LATTICE;
292 /*      else if (strcmp (str_type, "Mball") == 0)       type = OB_MBALL; */
293   else if (strcmp (str_type, "Mesh") == 0)        type = OB_MESH;
294   else if (strcmp (str_type, "Surf") == 0)        type = OB_SURF;
295 /*      else if (strcmp (str_type, "Wave") == 0)        type = OB_WAVE; */
296   else if (strcmp (str_type, "Empty") == 0)   type = OB_EMPTY;
297   else
298   {
299                 return (PythonReturnErrorObject (PyExc_AttributeError,
300                 "Unknown type specified"));
301   }
302
303   /* Create a new object. */
304   if (name == NULL)
305   {
306           /* No name is specified, set the name to the type of the object. */
307                 name = str_type;
308   }
309   object = alloc_libblock (&(G.main->object), ID_OB, name);
310
311   object->id.us = 0;
312   object->flag = 0;
313   object->type = type;
314   
315
316   /* transforms */
317   QuatOne(object->quat);
318   QuatOne(object->dquat);
319
320   object->col[3]= 1.0;    // alpha 
321
322   object->size[0] = object->size[1] = object->size[2] = 1.0;
323   object->loc[0] = object->loc[1] = object->loc[2] = 0.0;
324   Mat4One(object->parentinv);
325   Mat4One(object->obmat);
326   object->dt = OB_SHADED; // drawtype
327
328   if (U.flag & USER_MAT_ON_OB)
329   {
330                 object->colbits = -1;
331   }
332   switch (object->type)
333   {
334                 case OB_CAMERA: /* fall through. */
335                 case OB_LAMP:
336                   object->trackflag = OB_NEGZ;
337                   object->upflag = OB_POSY;
338                 break;
339                 default:
340                   object->trackflag = OB_POSY;
341                  object->upflag = OB_POSZ;
342   }
343   object->ipoflag = OB_OFFS_OB + OB_OFFS_PARENT;
344
345   /* duplivert settings */
346   object->dupon = 1;
347   object->dupoff = 0;
348   object->dupsta = 1;
349   object->dupend = 100;
350
351   /* Gameengine defaults*/
352   object->mass = 1.0;
353   object->inertia = 1.0;
354   object->formfactor = 0.4;
355   object->damping = 0.04;
356   object->rdamping = 0.1;
357   object->anisotropicFriction[0] = 1.0;
358   object->anisotropicFriction[1] = 1.0;
359   object->anisotropicFriction[2] = 1.0;
360   object->gameflag = OB_PROP;
361
362   object->lay = 1; // Layer, by default visible
363   G.totobj++;
364
365   object->data = NULL;
366
367   /* Create a Python object from it. */
368   blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
369   blen_object->object = object;
370
371   return ((PyObject*)blen_object);
372 }
373
374 /*****************************************************************************/
375 /* Function:                      M_Object_Get                                                                           */
376 /* Python equivalent:     Blender.Object.Get                                                             */
377 /*****************************************************************************/
378 PyObject *M_Object_Get(PyObject *self, PyObject *args)
379 {
380         struct Object   * object;
381         BPy_Object              * blen_object;
382         char                    * name = NULL;
383
384         PyArg_ParseTuple(args, "|s", &name);
385
386         if (name != NULL)
387         {
388                 object = GetObjectByName (name);
389
390                 if (object == NULL)
391                 {
392                         /* No object exists with the name specified in the argument name. */
393                         return (PythonReturnErrorObject (PyExc_AttributeError,
394                                                 "Unknown object specified."));
395                 }
396                 blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
397                 blen_object->object = object;
398
399                 return ((PyObject*)blen_object);
400         }
401         else
402         {
403                 /* No argument has been given. Return a list of all objects. */
404                 PyObject        * obj_list;
405                 Link            * link;
406                 int                       index;
407
408                 obj_list = PyList_New (BLI_countlist (&(G.main->object)));
409
410                 if (obj_list == NULL)
411                 {
412                         return (PythonReturnErrorObject (PyExc_SystemError,
413                                         "List creation failed."));
414                 }
415
416                 link = G.main->object.first;
417                 index = 0;
418                 while (link)
419                 {
420                         object = (Object*)link;
421                         blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type);
422                         blen_object->object = object;
423
424                         PyList_SetItem (obj_list, index, (PyObject*)blen_object);
425                         index++;
426                         link = link->next;
427                 }
428                 return (obj_list);
429         }
430 }
431
432 /*****************************************************************************/
433 /* Function:                      M_Object_get                                                                           */
434 /* Python equivalent:     Blender.Object.get                                                             */
435 /*****************************************************************************/
436 PyObject *M_Object_get(PyObject *self, PyObject *args)
437 {
438         PyErr_Warn (PyExc_DeprecationWarning,
439                 "The Object.get() function will be removed in Blender 2.29\n" \
440                 "Please update the script to use Object.Get");
441         return (M_Object_Get (self, args));
442 }
443
444 /*****************************************************************************/
445 /* Function:                      M_Object_GetSelected                                                           */
446 /* Python equivalent:     Blender.Object.getSelected                                             */
447 /*****************************************************************************/
448 static PyObject *M_Object_GetSelected (PyObject *self, PyObject *args)
449 {
450         BPy_Object                * blen_object;
451         PyObject                * list;
452         Base                    * base_iter;
453
454     if (G.vd == NULL)
455     {
456         // No 3d view has been initialized yet, simply return None
457         Py_INCREF (Py_None);
458         return Py_None;
459     }
460         list = PyList_New (0);
461         if ((G.scene->basact) &&
462                 ((G.scene->basact->flag & SELECT) &&
463                  (G.scene->basact->lay & G.vd->lay)))
464         {
465                 /* Active object is first in the list. */
466                 blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
467                 if (blen_object == NULL)
468                 {
469                         Py_DECREF (list);
470                         Py_INCREF (Py_None);
471                         return (Py_None);
472                 }
473                 blen_object->object = G.scene->basact->object;
474                 PyList_Append (list, (PyObject*)blen_object);
475         }
476
477         base_iter = G.scene->base.first;
478         while (base_iter)
479         {
480                 if (((base_iter->flag & SELECT) &&
481                          (base_iter->lay & G.vd->lay)) &&
482                         (base_iter != G.scene->basact))
483                 {
484                         blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
485                         if (blen_object == NULL)
486                         {
487                                 Py_DECREF (list);
488                                 Py_INCREF (Py_None);
489                                 return (Py_None);
490                         }
491                         blen_object->object = base_iter->object;
492                         PyList_Append (list, (PyObject*)blen_object);
493                 }
494                 base_iter = base_iter->next;
495         }
496         return (list);
497 }
498
499 /*****************************************************************************/
500 /* Function:                      M_Object_getSelected                                                           */
501 /* Python equivalent:     Blender.Object.getSelected                                             */
502 /*****************************************************************************/
503 static PyObject *M_Object_getSelected (PyObject *self, PyObject *args)
504 {
505         PyErr_Warn (PyExc_DeprecationWarning,
506                                 "The Object.getSelected() function will be removed in "\
507                                 "Blender 2.29\n" \
508                                 "Please update the script to use Object.GetSelected");
509         return (M_Object_GetSelected (self, args));
510 }
511
512 /*****************************************************************************/
513 /* Function:                      initObject                                                                             */
514 /*****************************************************************************/
515 PyObject *Object_Init (void)
516 {
517         PyObject        * module;
518
519         Object_Type.ob_type = &PyType_Type;
520
521         module = Py_InitModule3("Blender.Object", M_Object_methods, M_Object_doc);
522
523         return (module);
524 }
525
526 /*****************************************************************************/
527 /* Python BPy_Object methods:                                                                                              */
528 /*****************************************************************************/
529
530 static PyObject *Object_buildParts (BPy_Object *self)
531 {
532   void build_particle_system(Object *ob);
533   struct Object *obj = self->object;
534
535   build_particle_system(obj);
536
537   Py_INCREF (Py_None);
538   return (Py_None);
539 }
540
541 static PyObject *Object_clearIpo(BPy_Object *self)
542 {
543         Object *ob = self->object;
544         Ipo *ipo = (Ipo *)ob->ipo;
545
546         if (ipo) {
547                 ID *id = &ipo->id;
548                 if (id->us > 0) id->us--;
549                 ob->ipo = NULL;
550
551                 Py_INCREF (Py_True);
552                 return Py_True;
553         }
554
555         Py_INCREF (Py_False); /* no ipo found */
556         return Py_False;
557 }
558
559 static PyObject *Object_clrParent (BPy_Object *self, PyObject *args)
560 {
561   int mode=0;
562   int fast=0;
563
564   if (!PyArg_ParseTuple (args, "|ii", &mode, &fast))
565   {
566                 return (PythonReturnErrorObject (PyExc_AttributeError,
567                   "expected one or two integers as arguments"));
568   }
569
570   /* Remove the link only, the object is still in the scene. */
571   self->object->parent = NULL;
572
573   if (mode == 2)
574   {
575                 /* Keep transform */
576                 apply_obmat (self->object);
577   }
578
579   if (!fast)
580   {
581                 sort_baselist (G.scene);
582   }
583
584   Py_INCREF (Py_None);
585   return (Py_None);
586 }
587
588 /* adds object data to a Blender object, if object->data = NULL */
589 int EXPP_add_obdata(struct Object *object)
590 {
591   if (object->data != NULL) return -1;
592
593   switch(object->type)
594   {
595         case OB_ARMATURE:
596         /* TODO: Do we need to add something to G? (see the OB_LAMP case) */
597           object->data = add_armature();
598           break;
599         case OB_CAMERA:
600           /* TODO: Do we need to add something to G? (see the OB_LAMP case) */
601           object->data = add_camera();
602           break;
603         case OB_CURVE:
604           object->data = add_curve(OB_CURVE);
605           G.totcurve++;
606           break;
607         case OB_LAMP:
608           object->data = add_lamp();
609           G.totlamp++;
610           break;
611         case OB_MESH:
612           object->data = add_mesh();
613           G.totmesh++;
614           break;
615         case OB_LATTICE:
616       object->data = (void *)add_lattice();
617           object->dt = OB_WIRE;
618           break;
619
620         /* TODO the following types will be supported later
621         case OB_SURF:
622           object->data = add_curve(OB_SURF);
623           G.totcurve++;
624           break;
625         case OB_FONT:
626           object->data = add_curve(OB_FONT);
627           break;
628         case OB_MBALL:
629           object->data = add_mball();
630           break;
631         case OB_IKA:
632           object->data = add_ika();
633           object->dt = OB_WIRE;
634           break;
635         case OB_WAVE:
636           object->data = add_wave();
637           break;
638         */
639         default:
640           break;
641   }
642
643   if (!object->data) return -1;
644
645   return 0;
646 }
647
648 static PyObject *Object_getActionIpos (BPy_Object *self)
649 {
650         Object *obj=self->object;
651         PyObject *dict=PyDict_New ();
652         
653         if (obj->type==OB_ARMATURE) {
654                 
655                 if (obj->action!=0) {
656                 
657                         bAction *action=obj->action;
658                         bActionChannel *bone=(bActionChannel*)(action->chanbase.first);
659                         
660                         // Go through the list of bones
661                         while (bone!=0) {
662                                 
663                                 // Does this bone have an ipo?
664                                 if (bone->ipo!=0) {
665                                         
666                                         PyObject *ipo_attr=Ipo_CreatePyObject (bone->ipo);
667                                         
668                                         if (ipo_attr) {
669
670                                                 // Insert dict entry using the bone name as key
671                                                 if (PyDict_SetItemString (dict, bone->name, ipo_attr)!=0) {
672                                                         Py_DECREF ( ipo_attr );
673                                                         Py_DECREF ( dict );
674                                                         
675                                                         return EXPP_ReturnPyObjError (PyExc_RuntimeError,
676                                                                         "Object_getActionIpos: couldn't set dict item");
677                                                 }
678                                                 
679                                                 Py_DECREF (ipo_attr);
680                                                 
681                                         } else {
682                                                 
683                                                 Py_DECREF ( dict );
684                                                 
685                                                 return (PythonReturnErrorObject (PyExc_RuntimeError,
686                                                 "Object_getActionIpos: could not create Ipo object"));
687
688                                         }
689                                 }
690                                 
691                                 bone=bone->next;
692                         }
693                 }       
694         }
695         
696         return dict;
697 }
698
699
700 static PyObject *Object_getData (BPy_Object *self)
701 {
702         PyObject  * data_object;
703         Object * object = self->object;
704
705         /* if there's no obdata, try to create it */
706         if (object->data == NULL)
707         {
708           if (EXPP_add_obdata(object) != 0)
709           { /* couldn't create obdata */
710                 Py_INCREF (Py_None);
711                 return (Py_None);
712           }
713         }
714
715         data_object = NULL;
716
717         switch (object->type)
718         {
719                 case OB_ARMATURE:
720                         data_object = Armature_CreatePyObject (object->data);
721                         break;
722                 case OB_CAMERA:
723                         data_object = Camera_CreatePyObject (object->data);
724                         break;
725                 case OB_CURVE:
726                         data_object = Curve_CreatePyObject (object->data);
727                         break;
728                 case ID_IM:
729                         data_object = Image_CreatePyObject (object->data);
730                         break;
731                 case ID_IP:
732                         data_object = Ipo_CreatePyObject (object->data);
733                         break;
734                 case OB_LAMP:
735                         data_object = Lamp_CreatePyObject (object->data);
736                         break;
737                 case OB_LATTICE:
738                         data_object = Lattice_CreatePyObject (object->data);
739                         break;
740                 case ID_MA:
741                         break;
742                 case OB_MESH:
743                         data_object = NMesh_CreatePyObject (object->data, object);
744                         break;
745                 case ID_OB:
746                         data_object = Object_CreatePyObject (object->data);
747                         break;
748                 case ID_SCE:
749                         break;
750                 case ID_TXT:
751                         data_object = Text_CreatePyObject (object->data);
752                         break;
753                 case ID_WO:
754                         break;
755                 default:
756                         break;
757         }
758         if (data_object == NULL)
759         {
760                 Py_INCREF (Py_None);
761                 return (Py_None);
762         }
763         else
764         {
765                 return (data_object);
766         }
767 }
768
769 static PyObject *Object_getDeltaLocation (BPy_Object *self)
770 {
771         PyObject *attr = Py_BuildValue ("fff",
772                                                                         self->object->dloc[0],
773                                                                         self->object->dloc[1],
774                                                                         self->object->dloc[2]);
775
776         if (attr) return (attr);
777
778         return (PythonReturnErrorObject (PyExc_RuntimeError,
779                         "couldn't get Object.dloc attributes"));
780 }
781
782 static PyObject *Object_getDrawMode (BPy_Object *self)
783 {
784         PyObject *attr = Py_BuildValue ("b", self->object->dtx);
785
786         if (attr) return (attr);
787
788         return (PythonReturnErrorObject (PyExc_RuntimeError,
789                         "couldn't get Object.drawMode attribute"));
790 }
791
792 static PyObject *Object_getDrawType (BPy_Object *self)
793 {
794         PyObject *attr = Py_BuildValue ("b", self->object->dt);
795
796         if (attr) return (attr);
797
798         return (PythonReturnErrorObject (PyExc_RuntimeError,
799                         "couldn't get Object.drawType attribute"));
800 }
801
802 static PyObject *Object_getEuler (BPy_Object *self)
803 {  
804         EulerObject *eul;
805
806         eul = (EulerObject*)newEulerObject(NULL);
807         eul->eul[0] = self->object->rot[0];
808         eul->eul[1] = self->object->rot[1];
809         eul->eul[2] = self->object->rot[2];
810
811         return (PyObject*)eul; 
812
813 }
814
815 static PyObject *Object_getInverseMatrix (BPy_Object *self)
816 {
817         MatrixObject *inverse = (MatrixObject *)newMatrixObject(NULL, 4, 4);
818         
819         Mat4Invert (*inverse->matrix, self->object->obmat);
820
821         return ((PyObject *)inverse);
822
823 }
824
825 static PyObject *Object_getIpo(BPy_Object *self)
826 {
827   struct Ipo *ipo = self->object->ipo;
828
829   if (!ipo)
830         {
831                 Py_INCREF (Py_None);
832                 return Py_None;
833   }
834
835   return Ipo_CreatePyObject (ipo);
836 }
837
838 static PyObject *Object_getLocation (BPy_Object *self, PyObject *args)
839 {
840         PyObject *attr = Py_BuildValue ("fff",
841                                                                         self->object->loc[0],
842                                                                         self->object->loc[1],
843                                                                         self->object->loc[2]);
844
845         if (attr) return (attr);
846
847         return (PythonReturnErrorObject (PyExc_RuntimeError,
848                         "couldn't get Object.loc attributes"));
849 }
850
851 static PyObject *Object_getMaterials (BPy_Object *self)
852 {
853         return (EXPP_PyList_fromMaterialList (self->object->mat,
854                                                                                   self->object->totcol));
855 }
856
857 static PyObject *Object_getMatrix (BPy_Object *self)
858 {
859         Object  * ob;
860
861         ob = self->object;
862
863         return (PyObject*)newMatrixObject((float*)ob->obmat, 4, 4);
864 }
865
866 static PyObject *Object_getName (BPy_Object *self)
867 {
868         PyObject *attr = Py_BuildValue ("s", self->object->id.name+2);
869
870         if (attr) return (attr);
871
872         return (PythonReturnErrorObject (PyExc_RuntimeError,
873                         "couldn't get the name of the Object"));
874 }
875
876 static PyObject *Object_getParent (BPy_Object *self)
877 {
878         PyObject *attr;
879
880         if (self->object->parent == NULL)
881                 return EXPP_incr_ret (Py_None);
882
883         attr = Object_CreatePyObject (self->object->parent);
884
885         if (attr)
886         {
887                 return (attr);
888         }
889
890         return (PythonReturnErrorObject (PyExc_RuntimeError,
891                         "couldn't get Object.parent attribute"));
892 }
893
894 static PyObject *Object_getSize (BPy_Object *self, PyObject *args)
895 {
896         PyObject *attr = Py_BuildValue ("fff",
897                                                                         self->object->size[0],
898                                                                         self->object->size[1],
899                                                                         self->object->size[2]);
900
901         if (attr) return (attr);
902
903         return (PythonReturnErrorObject (PyExc_RuntimeError,
904                         "couldn't get Object.size attributes"));
905 }
906
907 static PyObject *Object_getTimeOffset (BPy_Object *self)
908 {
909         PyObject *attr = Py_BuildValue ("f", self->object->sf);
910
911         if (attr) return (attr);
912
913         return (PythonReturnErrorObject (PyExc_RuntimeError,
914                         "couldn't get Object.sf attributes"));
915 }
916
917
918 static PyObject *Object_getTracked (BPy_Object *self)
919 {
920         PyObject        *attr;
921
922         if (self->object->track == NULL)
923                 return EXPP_incr_ret (Py_None);
924         
925         attr = Object_CreatePyObject (self->object->track);
926
927         if (attr)
928         {
929                 return (attr);
930         }
931
932         return (PythonReturnErrorObject (PyExc_RuntimeError,
933                         "couldn't get Object.track attribute"));
934 }
935
936 static PyObject *Object_getType (BPy_Object *self)
937 {
938         switch (self->object->type)
939         {
940                 case OB_ARMATURE:       return (Py_BuildValue ("s", "Armature"));
941                 case OB_CAMERA:         return (Py_BuildValue ("s", "Camera"));
942                 case OB_CURVE:          return (Py_BuildValue ("s", "Curve"));
943                 case OB_EMPTY:          return (Py_BuildValue ("s", "Empty"));
944                 case OB_FONT:           return (Py_BuildValue ("s", "Text"));
945                 case OB_IKA:            return (Py_BuildValue ("s", "Ika"));
946                 case OB_LAMP:           return (Py_BuildValue ("s", "Lamp"));
947                 case OB_LATTICE:        return (Py_BuildValue ("s", "Lattice"));
948                 case OB_MBALL:          return (Py_BuildValue ("s", "MBall"));
949                 case OB_MESH:           return (Py_BuildValue ("s", "Mesh"));
950                 case OB_SURF:           return (Py_BuildValue ("s", "Surf"));
951                 case OB_WAVE:           return (Py_BuildValue ("s", "Wave"));
952                 default:                        return (Py_BuildValue ("s", "unknown"));
953         }
954 }
955
956 static PyObject *Object_getBoundBox (BPy_Object *self)
957 {
958   int i;
959   float *vec = NULL;
960   PyObject *vector, *bbox;
961
962   if (!self->object->data)
963         return EXPP_ReturnPyObjError (PyExc_AttributeError,
964           "This object isn't linked to any object data (mesh, curve, etc) yet");
965
966   if (!self->object->bb) {
967         Mesh *me;
968         Curve *curve;
969         switch (self->object->type) {
970           case OB_MESH:
971                 me = self->object->data;
972                 if (!me->bb) tex_space_mesh(me);
973                 vec = (float *)me->bb->vec;
974                 break;
975           case OB_CURVE:
976           case OB_FONT:
977           case OB_SURF:
978                 curve = self->object->data;
979                 if (!curve->bb) tex_space_curve(curve);
980                 vec = (float *)curve->bb->vec;
981                 break;
982           default:
983                 Py_INCREF (Py_None);
984                 return Py_None;
985         }
986   }
987   else vec = (float *)self->object->bb->vec;
988
989   if (!vec)
990         return EXPP_ReturnPyObjError (PyExc_RuntimeError,
991                   "couldn't retrieve bounding box data");
992
993   bbox = PyList_New(8);
994
995   if (!bbox)
996         return EXPP_ReturnPyObjError (PyExc_MemoryError,
997                   "couldn't create pylist");
998
999   for (i = 0; i < 8; i++) {
1000         vector = newVectorObject(vec, 3);
1001         PyList_SET_ITEM(bbox, i, vector);
1002         vec += 3;
1003   }
1004
1005   return bbox;
1006 }
1007
1008 static PyObject *Object_makeDisplayList (BPy_Object *self)
1009 {
1010   Object *ob = self->object;
1011
1012   if (ob->type == OB_FONT) text_to_curve(ob, 0);
1013
1014   makeDispList(ob);
1015
1016   Py_INCREF (Py_None);
1017   return Py_None;
1018 }
1019
1020 static PyObject *Object_link (BPy_Object *self, PyObject *args)
1021 {
1022         PyObject        * py_data;
1023         ID                      * id;
1024         ID                      * oldid;
1025         int                       obj_id;
1026         void            * data = NULL;
1027
1028         if (!PyArg_ParseTuple (args, "O", &py_data))
1029         {
1030                 return (PythonReturnErrorObject (PyExc_AttributeError,
1031                         "expected an object as argument"));
1032         }
1033         if (Camera_CheckPyObject (py_data))
1034                 data = (void *)Camera_FromPyObject (py_data);
1035         if (Lamp_CheckPyObject (py_data))
1036                 data = (void *)Lamp_FromPyObject (py_data);
1037         if (Curve_CheckPyObject (py_data))
1038                 data = (void *)Curve_FromPyObject (py_data);
1039         if (NMesh_CheckPyObject (py_data))
1040                 data = (void *)Mesh_FromPyObject (py_data, self->object);
1041         if (Lattice_CheckPyObject (py_data))
1042                 data = (void *)Lattice_FromPyObject (py_data);
1043
1044         /* have we set data to something good? */
1045         if( !data )
1046         {
1047                 return (PythonReturnErrorObject (PyExc_AttributeError,
1048                         "link argument type is not supported "));
1049         }
1050
1051         oldid = (ID*) self->object->data;
1052         id = (ID*) data;
1053         obj_id = MAKE_ID2 (id->name[0], id->name[1]);
1054
1055         switch (obj_id)
1056         {
1057                 case ID_CA:
1058                         if (self->object->type != OB_CAMERA)
1059                         {
1060                                 return (PythonReturnErrorObject (PyExc_AttributeError,
1061                                         "The 'link' object is incompatible with the base object"));
1062                         }
1063                         break;
1064                 case ID_LA:
1065                         if (self->object->type != OB_LAMP)
1066                         {
1067                                 return (PythonReturnErrorObject (PyExc_AttributeError,
1068                                         "The 'link' object is incompatible with the base object"));
1069                         }
1070                         break;
1071                 case ID_ME:
1072                         if (self->object->type != OB_MESH)
1073                         {
1074                                 return (PythonReturnErrorObject (PyExc_AttributeError,
1075                                         "The 'link' object is incompatible with the base object"));
1076                         }
1077                         break;
1078                 case ID_CU:
1079                         if (self->object->type != OB_CURVE)
1080                         {
1081                                 return (PythonReturnErrorObject (PyExc_AttributeError,
1082                                         "The 'link' object is incompatible with the base object"));
1083                         }
1084                         break;
1085                 case ID_LT:
1086                         if (self->object->type != OB_LATTICE)
1087                         {
1088                                         return (PythonReturnErrorObject (PyExc_AttributeError,
1089                                                         "The 'link' object is incompatible with the base object"));
1090                         }
1091                         break;
1092                 default:
1093                         return (PythonReturnErrorObject (PyExc_AttributeError,
1094                                 "Linking this object type is not supported"));
1095         }
1096         self->object->data = data;
1097
1098         if ( self->object->type == OB_MESH)
1099         {
1100                 self->object->totcol = 0;
1101                 EXPP_synchronizeMaterialLists(self->object, id);
1102         }
1103
1104         id_us_plus (id);
1105         if (oldid)
1106         {
1107                 if (oldid->us > 0)
1108                 {
1109                         oldid->us--;
1110                 }
1111                 else
1112                 {
1113                         return (PythonReturnErrorObject (PyExc_RuntimeError,
1114                                 "old object reference count below 0"));
1115                 }
1116         }
1117         return EXPP_incr_ret (Py_None);
1118 }
1119
1120 static PyObject *Object_makeParent (BPy_Object *self, PyObject *args)
1121 {
1122         PyObject        * list;
1123         PyObject        * py_child;
1124         //BPy_Object      * py_obj_child; unused
1125         Object          * child;
1126         Object          * parent;
1127         int                       noninverse = 0;
1128         int                       fast = 0;
1129         int                       i;
1130
1131         /* Check if the arguments passed to makeParent are valid. */
1132         if (!PyArg_ParseTuple (args, "O|ii", &list, &noninverse, &fast))
1133         {
1134                 return (PythonReturnErrorObject (PyExc_AttributeError,
1135                         "expected a list of objects and one or two integers as arguments"));
1136         }
1137         if (!PySequence_Check (list))
1138         {
1139                 return (PythonReturnErrorObject (PyExc_TypeError,
1140                         "expected a list of objects"));
1141         }
1142
1143         /* Check if the PyObject passed in list is a Blender object. */
1144         for (i=0 ; i<PySequence_Length (list) ; i++)
1145         {
1146                 child = NULL;
1147                 py_child = PySequence_GetItem (list, i);
1148                 if (Object_CheckPyObject (py_child))
1149                         child = (Object*) Object_FromPyObject (py_child);
1150
1151                 if (child == NULL)
1152                 {
1153                         return (PythonReturnErrorObject (PyExc_TypeError,
1154                                 "Object Type expected"));
1155                 }
1156
1157                 parent = (Object*)self->object;
1158                 if (test_parent_loop (parent, child))
1159                 {
1160                         return (PythonReturnErrorObject (PyExc_RuntimeError,
1161                                 "parenting loop detected - parenting failed"));
1162                 }
1163                 child->partype = PAROBJECT;
1164                 child->parent = parent;
1165                 //py_obj_child = (BPy_Object *) py_child;
1166                 if (noninverse == 1)
1167                 {
1168                         /* Parent inverse = unity */
1169                         child->loc[0] = 0.0;
1170                         child->loc[1] = 0.0;
1171                         child->loc[2] = 0.0;
1172                 }
1173                 else
1174                 {
1175                         what_does_parent (child);
1176                         Mat4Invert (child->parentinv, parent->obmat);
1177                 }
1178
1179                 if (!fast)
1180                 {
1181                         sort_baselist (G.scene);
1182                 }
1183
1184                 // We don't need the child object anymore.
1185                 //Py_DECREF ((PyObject *) child);
1186         }
1187         return EXPP_incr_ret (Py_None);
1188 }
1189
1190 static PyObject *Object_materialUsage (BPy_Object *self, PyObject *args)
1191 {
1192         return (PythonReturnErrorObject (PyExc_NotImplementedError,
1193                         "materialUsage: not yet implemented"));
1194 }
1195
1196 static PyObject *Object_setDeltaLocation (BPy_Object *self, PyObject *args)
1197 {
1198         float   dloc1;
1199         float   dloc2;
1200         float   dloc3;
1201         int             status;
1202
1203         if (PyObject_Length (args) == 3)
1204                 status = PyArg_ParseTuple (args, "fff", &dloc1, &dloc2, &dloc3);
1205         else
1206                 status = PyArg_ParseTuple (args, "(fff)", &dloc1, &dloc2, &dloc3);
1207
1208         if (!status)
1209                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1210                                 "expected list argument of 3 floats");
1211
1212         self->object->dloc[0] = dloc1;
1213         self->object->dloc[1] = dloc2;
1214         self->object->dloc[2] = dloc3;
1215
1216         Py_INCREF (Py_None);
1217         return (Py_None);
1218 }
1219
1220 static PyObject *Object_setDrawMode (BPy_Object *self, PyObject *args)
1221 {
1222         char    dtx;
1223
1224         if (!PyArg_ParseTuple (args, "b", &dtx))
1225         {
1226                 return (PythonReturnErrorObject (PyExc_AttributeError,
1227                                 "expected an integer as argument"));
1228         }
1229         self->object->dtx = dtx;
1230
1231         Py_INCREF (Py_None);
1232         return (Py_None);
1233 }
1234
1235 static PyObject *Object_setDrawType (BPy_Object *self, PyObject *args)
1236
1237         char    dt;
1238
1239         if (!PyArg_ParseTuple (args, "b", &dt))
1240         {
1241                 return (PythonReturnErrorObject (PyExc_AttributeError,
1242                                 "expected an integer as argument"));
1243         }
1244         self->object->dt = dt;
1245
1246         Py_INCREF (Py_None);
1247         return (Py_None);
1248 }
1249
1250 static PyObject *Object_setEuler (BPy_Object *self, PyObject *args)
1251 {
1252         float   rot1;
1253         float   rot2;
1254         float   rot3;
1255         int             status;
1256         PyObject* ob;
1257
1258         if (!PyArg_ParseTuple (args, "O", &ob))
1259                 return (PythonReturnErrorObject (PyExc_AttributeError,
1260                                 "unknown type passed to function (setEuler)"));
1261
1262         //test to see if it's a list or a euler
1263         if(PyList_Check(ob)){
1264                 if (PyObject_Length (args) == 3)
1265                         status = PyArg_ParseTuple (args, "fff", &rot1, &rot2, &rot3);
1266                 else
1267                         status = PyArg_ParseTuple (args, "(fff)", &rot1, &rot2, &rot3);
1268                 if (!status)
1269                         return EXPP_ReturnPyObjError (PyExc_AttributeError,
1270                                         "expected list argument of 3 floats");
1271         }else if(EulerObject_Check(ob)){
1272                 rot1 = ((EulerObject*)ob)->eul[0];
1273                 rot2 = ((EulerObject*)ob)->eul[1];
1274                 rot3 = ((EulerObject*)ob)->eul[2];
1275         }else{
1276                 Py_DECREF (ob);
1277                 return (PythonReturnErrorObject (PyExc_AttributeError,
1278                                 "expected list of floats or euler"));
1279         }
1280
1281         self->object->rot[0] = rot1;
1282         self->object->rot[1] = rot2;
1283         self->object->rot[2] = rot3;
1284
1285         Py_INCREF (Py_None);
1286         return (Py_None);
1287 }
1288
1289 static PyObject *Object_setMatrix (BPy_Object *self, PyObject *args)
1290 {
1291         MatrixObject* mat;
1292         int x,y;
1293
1294         if (!PyArg_ParseTuple(args, "O!", &matrix_Type, &mat))
1295                 return EXPP_ReturnPyObjError 
1296                    (PyExc_TypeError, "expected matrix object as argument");
1297
1298         for(x = 0; x < 4; x++){
1299                 for(y = 0; y < 4; y++){
1300                         self->object->obmat[x][y] = mat->matrix[x][y];
1301                 }
1302         }
1303         apply_obmat(self->object);
1304
1305         Py_INCREF (Py_None);
1306         return (Py_None);
1307 }
1308
1309 static PyObject *Object_setIpo(BPy_Object *self, PyObject *args)
1310 {
1311         PyObject *pyipo = 0;
1312         Ipo *ipo = NULL;
1313         Ipo *oldipo;
1314
1315         if (!PyArg_ParseTuple(args, "O!", &Ipo_Type, &pyipo))
1316                 return EXPP_ReturnPyObjError (PyExc_TypeError, "expected Ipo as argument");
1317
1318         ipo = Ipo_FromPyObject(pyipo);
1319
1320         if (!ipo) return EXPP_ReturnPyObjError (PyExc_RuntimeError, "null ipo!");
1321
1322         if (ipo->blocktype != ID_OB)
1323                 return EXPP_ReturnPyObjError (PyExc_TypeError,
1324                         "this ipo is not an object ipo");
1325
1326         oldipo = self->object->ipo;
1327         if (oldipo) {
1328                 ID *id = &oldipo->id;
1329                 if (id->us > 0) id->us--;
1330         }
1331
1332         ((ID *)&ipo->id)->us++;
1333
1334         self->object->ipo = ipo;
1335
1336         Py_INCREF(Py_None);
1337         return Py_None;
1338 }
1339
1340 static PyObject *Object_setLocation (BPy_Object *self, PyObject *args)
1341 {
1342         float   loc1;
1343         float   loc2;
1344         float   loc3;
1345         int             status;
1346
1347         if (PyObject_Length (args) == 3)
1348                 status = PyArg_ParseTuple (args, "fff", &loc1, &loc2, &loc3);
1349         else
1350                 status = PyArg_ParseTuple (args, "(fff)", &loc1, &loc2, &loc3);
1351
1352         if (!status)
1353                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1354                                 "expected list argument of 3 floats");
1355
1356         self->object->loc[0] = loc1;
1357         self->object->loc[1] = loc2;
1358         self->object->loc[2] = loc3;
1359
1360         Py_INCREF (Py_None);
1361         return (Py_None);
1362 }
1363
1364 static PyObject *Object_setMaterials (BPy_Object *self, PyObject *args)
1365 {
1366         PyObject         * list;
1367         int                        len;
1368         int                        i;
1369         Material        ** matlist;
1370
1371         if (!PyArg_ParseTuple (args, "O", &list))
1372         {
1373                 return (PythonReturnErrorObject (PyExc_AttributeError,
1374                                 "expected a list of materials as argument"));
1375         }
1376
1377         len = PySequence_Length (list);
1378         if (len > 0)
1379         {
1380                 matlist = EXPP_newMaterialList_fromPyList (list);
1381                 if (!matlist)
1382                 {
1383                         return (PythonReturnErrorObject (PyExc_AttributeError,
1384                                 "material list must be a list of valid materials!"));
1385                 }
1386                 if ((len < 0) || (len > MAXMAT))
1387                 {
1388                         return (PythonReturnErrorObject (PyExc_RuntimeError,
1389                                 "illegal material index!"));
1390                 }
1391
1392                 if (self->object->mat)
1393                 {
1394                         EXPP_releaseMaterialList (self->object->mat, len);
1395                 }
1396                 /* Increase the user count on all materials */
1397                 for (i=0 ; i<len ; i++)
1398                 {
1399                         id_us_plus ((ID *) matlist[i]);
1400                 }
1401                 self->object->mat = matlist;
1402                 self->object->totcol = len;
1403                 self->object->actcol = -1;
1404
1405                 switch (self->object->type)
1406                 {
1407                         case OB_CURVE:  /* fall through */
1408                         case OB_FONT:   /* fall through */
1409                         case OB_MESH:   /* fall through */
1410                         case OB_MBALL:  /* fall through */
1411                         case OB_SURF:
1412                                 EXPP_synchronizeMaterialLists (self->object,
1413                                                                                            self->object->data);
1414                                 break;
1415                         default:
1416                                 break;
1417                 }
1418         }
1419         return EXPP_incr_ret (Py_None);
1420 }
1421
1422 static PyObject *Object_setName (BPy_Object *self, PyObject *args)
1423 {
1424         char  * name;
1425         char    buf[21];
1426
1427         if (!PyArg_ParseTuple (args, "s", &name))
1428         {
1429                 return (PythonReturnErrorObject (PyExc_AttributeError,
1430                                 "expected a String as argument"));
1431         }
1432
1433         PyOS_snprintf(buf, sizeof(buf), "%s", name);
1434
1435         rename_id(&self->object->id, buf);
1436
1437         Py_INCREF (Py_None);
1438         return (Py_None);
1439 }
1440
1441 static PyObject *Object_setSize (BPy_Object *self, PyObject *args)
1442 {
1443         float   sizex;
1444         float   sizey;
1445         float   sizez;
1446         int             status;
1447
1448         if (PyObject_Length (args) == 3)
1449                 status = PyArg_ParseTuple (args, "fff", &sizex, &sizey, &sizez);
1450         else
1451                 status = PyArg_ParseTuple (args, "(fff)", &sizex, &sizey, &sizez);
1452
1453         if (!status)
1454                 return EXPP_ReturnPyObjError (PyExc_AttributeError,
1455                                 "expected list argument of 3 floats");
1456
1457         self->object->size[0] = sizex;
1458         self->object->size[1] = sizey;
1459         self->object->size[2] = sizez;
1460
1461         Py_INCREF (Py_None);
1462         return (Py_None);
1463 }
1464
1465 static PyObject *Object_setTimeOffset (BPy_Object *self, PyObject *args)
1466 {
1467         float newTimeOffset;
1468
1469         if (!PyArg_ParseTuple (args, "f", &newTimeOffset))
1470         {
1471                 return (PythonReturnErrorObject (PyExc_AttributeError,
1472                                 "expected a float as argument"));
1473         }
1474
1475         self->object->sf=newTimeOffset;
1476
1477         Py_INCREF (Py_None);
1478         return (Py_None);
1479 }
1480
1481 static PyObject *Object_shareFrom (BPy_Object *self, PyObject *args)
1482 {
1483         BPy_Object              * object;
1484         ID                              * id;
1485         ID                              * oldid;
1486
1487         if (!PyArg_ParseTuple (args, "O", &object))
1488         {
1489                 PythonReturnErrorObject (PyExc_AttributeError,
1490                                 "expected an object argument");
1491                 return (NULL);
1492         }
1493         if (!Object_CheckPyObject ((PyObject*)object))
1494         {
1495                 PythonReturnErrorObject (PyExc_TypeError,
1496                                 "argument 1 is not of type 'Object'");
1497                 return (NULL);
1498         }
1499
1500         if (self->object->type != object->object->type)
1501         {
1502                 PythonReturnErrorObject (PyExc_TypeError,
1503                                 "objects are not of same data type");
1504                 return (NULL);
1505         }
1506         switch (self->object->type)
1507         {
1508                 case OB_MESH:
1509                 case OB_LAMP:
1510                 case OB_CAMERA: /* we can probably add the other types, too */
1511                 case OB_ARMATURE:
1512                 case OB_CURVE:
1513                 case OB_SURF:
1514                 case OB_LATTICE:
1515                         oldid = (ID*) self->object->data;
1516                         id = (ID*) object->object->data;
1517                         self->object->data = object->object->data;
1518
1519                         if ( self->object->type == OB_MESH && id ){
1520                                 self->object->totcol = 0;
1521                                 EXPP_synchronizeMaterialLists(self->object, id);
1522                         }
1523                         
1524                         id_us_plus (id);
1525                         if (oldid)
1526                         {
1527                                 if (oldid->us > 0)
1528                                 {
1529                                         oldid->us--;
1530                                 }
1531                                 else
1532                                 {
1533                                         return (PythonReturnErrorObject (PyExc_RuntimeError,
1534                                                         "old object reference count below 0"));
1535                                 }
1536                         }
1537                         Py_INCREF (Py_None);
1538                         return (Py_None);
1539                 default:
1540                         PythonReturnErrorObject (PyExc_TypeError,
1541                                         "type not supported");
1542                         return (NULL);
1543         }
1544
1545         Py_INCREF (Py_None);
1546         return (Py_None);
1547 }
1548
1549 /*****************************************************************************/
1550 /* Function:    Object_CreatePyObject                                                                            */
1551 /* Description: This function will create a new BlenObject from an existing  */
1552 /*                              Object structure.                                                                                        */
1553 /*****************************************************************************/
1554 PyObject* Object_CreatePyObject (struct Object *obj)
1555 {
1556         BPy_Object        * blen_object;
1557
1558         blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type);
1559
1560         if (blen_object == NULL)
1561         {
1562                 return (NULL);
1563         }
1564         blen_object->object = obj;
1565         return ((PyObject*)blen_object);
1566 }
1567
1568 /*****************************************************************************/
1569 /* Function:    Object_CheckPyObject                                                                             */
1570 /* Description: This function returns true when the given PyObject is of the */
1571 /*                              type Object. Otherwise it will return false.                             */
1572 /*****************************************************************************/
1573 int Object_CheckPyObject (PyObject *py_obj)
1574 {
1575         return (py_obj->ob_type == &Object_Type);
1576 }
1577
1578 /*****************************************************************************/
1579 /* Function:    Object_FromPyObject                                                                                      */
1580 /* Description: This function returns the Blender object from the given          */
1581 /*                              PyObject.                                                                                                        */
1582 /*****************************************************************************/
1583 struct Object* Object_FromPyObject (PyObject *py_obj)
1584 {
1585         BPy_Object        * blen_obj;
1586
1587         blen_obj = (BPy_Object*)py_obj;
1588         return (blen_obj->object);
1589 }
1590
1591 /*****************************************************************************/
1592 /* Description: Returns the object with the name specified by the argument       */
1593 /*                              name. Note that the calling function has to remove the first */
1594 /*                              two characters of the object name. These two characters          */
1595 /*                              specify the type of the object (OB, ME, WO, ...)                         */
1596 /*                              The function will return NULL when no object with the given  */
1597 /*                              name is found.                                                                                           */
1598 /*****************************************************************************/
1599 Object * GetObjectByName (char * name)
1600 {
1601   Object  * obj_iter;
1602
1603   obj_iter = G.main->object.first;
1604   while (obj_iter)
1605   {
1606         if (StringEqual (name, GetIdName (&(obj_iter->id))))
1607         {
1608           return (obj_iter);
1609         }
1610         obj_iter = obj_iter->id.next;
1611   }
1612
1613   /* There is no object with the given name */
1614   return (NULL);
1615 }
1616
1617 /*****************************************************************************/
1618 /* Function:    Object_dealloc                                                                                           */
1619 /* Description: This is a callback function for the BlenObject type. It is       */
1620 /*                              the destructor function.                                                                         */
1621 /*****************************************************************************/
1622 static void Object_dealloc (BPy_Object *obj)
1623 {
1624         PyObject_DEL (obj);
1625 }
1626
1627 /*****************************************************************************/
1628 /* Function:    Object_getAttr                                                                                           */
1629 /* Description: This is a callback function for the BlenObject type. It is       */
1630 /*                              the function that retrieves any value from Blender and           */
1631 /*                              passes it to Python.                                                                             */
1632 /*****************************************************************************/
1633 static PyObject* Object_getAttr (BPy_Object *obj, char *name)
1634 {
1635         struct Object   * object;
1636         struct Ika              * ika;
1637
1638         object = obj->object;
1639         if (StringEqual (name, "LocX"))
1640                 return (PyFloat_FromDouble(object->loc[0]));
1641         if (StringEqual (name, "LocY"))
1642                 return (PyFloat_FromDouble(object->loc[1]));
1643         if (StringEqual (name, "LocZ"))
1644                 return (PyFloat_FromDouble(object->loc[2]));
1645         if (StringEqual (name, "loc"))
1646                 return (Py_BuildValue ("fff", object->loc[0], object->loc[1],
1647                                                            object->loc[2]));
1648         if (StringEqual (name, "dLocX"))
1649                 return (PyFloat_FromDouble(object->dloc[0]));
1650         if (StringEqual (name, "dLocY"))
1651                 return (PyFloat_FromDouble(object->dloc[1]));
1652         if (StringEqual (name, "dLocZ"))
1653                 return (PyFloat_FromDouble(object->dloc[2]));
1654         if (StringEqual (name, "dloc"))
1655                 return (Py_BuildValue ("fff", object->dloc[0], object->dloc[1],
1656                                                            object->dloc[2]));
1657         if (StringEqual (name, "RotX"))
1658                 return (PyFloat_FromDouble(object->rot[0]));
1659         if (StringEqual (name, "RotY"))
1660                 return (PyFloat_FromDouble(object->rot[1]));
1661         if (StringEqual (name, "RotZ"))
1662                 return (PyFloat_FromDouble(object->rot[2]));
1663         if (StringEqual (name, "rot"))
1664                 return (Py_BuildValue ("fff", object->rot[0], object->rot[1],
1665                                                            object->rot[2]));
1666         if (StringEqual (name, "dRotX"))
1667                 return (PyFloat_FromDouble(object->drot[0]));
1668         if (StringEqual (name, "dRotY"))
1669                 return (PyFloat_FromDouble(object->drot[1]));
1670         if (StringEqual (name, "dRotZ"))
1671                 return (PyFloat_FromDouble(object->drot[2]));
1672         if (StringEqual (name, "drot"))
1673                 return (Py_BuildValue ("fff", object->drot[0], object->drot[1],
1674                                                            object->drot[2]));
1675         if (StringEqual (name, "SizeX"))
1676                 return (PyFloat_FromDouble(object->size[0]));
1677         if (StringEqual (name, "SizeY"))
1678                 return (PyFloat_FromDouble(object->size[1]));
1679         if (StringEqual (name, "SizeZ"))
1680                 return (PyFloat_FromDouble(object->size[2]));
1681         if (StringEqual (name, "size"))
1682                 return (Py_BuildValue ("fff", object->size[0], object->size[1],
1683                                                            object->size[2]));
1684         if (StringEqual (name, "dSizeX"))
1685                 return (PyFloat_FromDouble(object->dsize[0]));
1686         if (StringEqual (name, "dSizeY"))
1687                 return (PyFloat_FromDouble(object->dsize[1]));
1688         if (StringEqual (name, "dSizeZ"))
1689                 return (PyFloat_FromDouble(object->dsize[2]));
1690         if (StringEqual (name, "dsize"))
1691                 return (Py_BuildValue ("fff", object->dsize[0], object->dsize[1],
1692                                                            object->dsize[2]));
1693         if (strncmp (name,"Eff", 3) == 0)
1694         {
1695                 if ( (object->type == OB_IKA) && (object->data != NULL) )
1696                 {
1697                         ika = object->data;
1698                         switch (name[3])
1699                         {
1700                                 case 'X':
1701                                         return (PyFloat_FromDouble (ika->effg[0]));
1702                                 case 'Y':
1703                                         return (PyFloat_FromDouble (ika->effg[1]));
1704                                 case 'Z':
1705                                         return (PyFloat_FromDouble (ika->effg[2]));
1706                                 default:
1707                                 /* Do we need to display a sensible error message here? */
1708                                         return (NULL);
1709                         }
1710                 }
1711                 return (NULL);
1712         }
1713         if (StringEqual (name, "Layer"))
1714           return (PyInt_FromLong(object->lay));
1715         if (StringEqual (name, "parent"))
1716         {
1717                 if (object->parent)
1718                         return (Object_CreatePyObject (object->parent));
1719                 else 
1720         {
1721           Py_INCREF (Py_None);
1722           return (Py_None);
1723         }
1724         }
1725
1726         if (StringEqual (name, "track"))
1727           return (Object_CreatePyObject (object->track));
1728         if (StringEqual (name, "data"))
1729           return (Object_getData (obj));
1730         if (StringEqual (name, "ipo"))
1731         {
1732                 if (object->ipo == NULL)
1733                 {
1734                         /* There's no ipo linked to the object, return Py_None. */
1735                         Py_INCREF (Py_None);
1736                         return (Py_None);
1737                 }
1738                 return (Ipo_CreatePyObject (object->ipo));
1739         }
1740         if (StringEqual (name, "mat"))
1741                 return (Object_getMatrix (obj));
1742         if (StringEqual (name, "matrix"))
1743                 return (Object_getMatrix (obj));
1744         if (StringEqual (name, "colbits"))
1745                 return (Py_BuildValue ("h", object->colbits));
1746         if (StringEqual (name, "drawType"))
1747                 return (Py_BuildValue ("b", object->dt));
1748         if (StringEqual (name, "drawMode"))
1749                 return (Py_BuildValue ("b", object->dtx));
1750         if (StringEqual (name, "name"))
1751                 return (Py_BuildValue ("s", object->id.name+2));
1752
1753         /* not an attribute, search the methods table */
1754         return Py_FindMethod(BPy_Object_methods, (PyObject *)obj, name);
1755 }
1756
1757 /*****************************************************************************/
1758 /* Function:    Object_setAttr                                                                                           */
1759 /* Description: This is a callback function for the BlenObject type. It is       */
1760 /*                              the function that retrieves any value from Python and sets       */
1761 /*                              it accordingly in Blender.                                                                       */
1762 /*****************************************************************************/
1763 static int Object_setAttr (BPy_Object *obj, char *name, PyObject *value)
1764 {
1765         PyObject                * valtuple;
1766         struct Object   * object;
1767         struct Ika              * ika;
1768
1769         /* First put the value(s) in a tuple. For some variables, we want to */
1770         /* pass the values to a function, and these functions only accept */
1771         /* PyTuples. */
1772         valtuple = Py_BuildValue ("(O)", value);
1773         if (!valtuple)
1774         {
1775                 return EXPP_ReturnIntError(PyExc_MemoryError,
1776                                                  "Object_setAttr: couldn't create PyTuple");
1777         }
1778
1779         object = obj->object;
1780         if (StringEqual (name, "LocX"))
1781                 return (!PyArg_Parse (value, "f", &(object->loc[0])));
1782         if (StringEqual (name, "LocY"))
1783                 return (!PyArg_Parse (value, "f", &(object->loc[1])));
1784         if (StringEqual (name, "LocZ"))
1785                 return (!PyArg_Parse (value, "f", &(object->loc[2])));
1786         if (StringEqual (name, "loc"))
1787         {
1788                 if (Object_setLocation (obj, valtuple) != Py_None)
1789                         return (-1);
1790                 else
1791                         return (0);
1792         }
1793         if (StringEqual (name, "dLocX"))
1794                 return (!PyArg_Parse (value, "f", &(object->dloc[0])));
1795         if (StringEqual (name, "dLocY"))
1796                 return (!PyArg_Parse (value, "f", &(object->dloc[1])));
1797         if (StringEqual (name, "dLocZ"))
1798                 return (!PyArg_Parse (value, "f", &(object->dloc[2])));
1799         if (StringEqual (name, "dloc"))
1800         {
1801                 if (Object_setDeltaLocation (obj, valtuple) != Py_None)
1802                         return (-1);
1803                 else
1804                         return (0);
1805         }
1806         if (StringEqual (name, "RotX"))
1807                 return (!PyArg_Parse (value, "f", &(object->rot[0])));
1808         if (StringEqual (name, "RotY"))
1809                 return (!PyArg_Parse (value, "f", &(object->rot[1])));
1810         if (StringEqual (name, "RotZ"))
1811                 return (!PyArg_Parse (value, "f", &(object->rot[2])));
1812         if (StringEqual (name, "rot"))
1813         {
1814                 if (Object_setEuler (obj, valtuple) != Py_None)
1815                         return (-1);
1816                 else
1817                         return (0);
1818         }
1819         if (StringEqual (name, "dRotX"))
1820                 return (!PyArg_Parse (value, "f", &(object->drot[0])));
1821         if (StringEqual (name, "dRotY"))
1822                 return (!PyArg_Parse (value, "f", &(object->drot[1])));
1823         if (StringEqual (name, "dRotZ"))
1824                 return (!PyArg_Parse (value, "f", &(object->drot[2])));
1825         if (StringEqual (name, "drot"))
1826                 return (!PyArg_ParseTuple (value, "fff", &(object->drot[0]),
1827                                                           &(object->drot[1]), &(object->drot[2])));
1828         if (StringEqual (name, "SizeX"))
1829                 return (!PyArg_Parse (value, "f", &(object->size[0])));
1830         if (StringEqual (name, "SizeY"))
1831                 return (!PyArg_Parse (value, "f", &(object->size[1])));
1832         if (StringEqual (name, "SizeZ"))
1833                 return (!PyArg_Parse (value, "f", &(object->size[2])));
1834         if (StringEqual (name, "size"))
1835                 return (!PyArg_ParseTuple  (value, "fff", &(object->size[0]),
1836                                                           &(object->size[1]), &(object->size[2])));
1837         if (StringEqual (name, "dSizeX"))
1838                 return (!PyArg_Parse (value, "f", &(object->dsize[0])));
1839         if (StringEqual (name, "dSizeY"))
1840                 return (!PyArg_Parse (value, "f", &(object->dsize[1])));
1841         if (StringEqual (name, "dSizeZ"))
1842                 return (!PyArg_Parse (value, "f", &(object->dsize[2])));
1843         if (StringEqual (name, "dsize"))
1844                 return (!PyArg_ParseTuple  (value, "fff", &(object->dsize[0]),
1845                                                           &(object->dsize[1]), &(object->dsize[2])));
1846         if (strncmp (name,"Eff", 3) == 0)
1847         {
1848                 if ( (object->type == OB_IKA) && (object->data != NULL) )
1849                 {
1850                         ika = object->data;
1851                         switch (name[3])
1852                         {
1853                                 case 'X':
1854                                         return (!PyArg_Parse (value, "f", &(ika->effg[0])));
1855                                 case 'Y':
1856                                         return (!PyArg_Parse (value, "f", &(ika->effg[1])));
1857                                 case 'Z':
1858                                         return (!PyArg_Parse (value, "f", &(ika->effg[2])));
1859                                 default:
1860                                         /* Do we need to display a sensible error message here? */
1861                                         return (0);
1862                         }
1863                 }
1864                 return (0);
1865         }
1866         if (StringEqual (name, "Layer"))
1867                 return (!PyArg_Parse (value, "i", &(object->lay)));
1868         if (StringEqual (name, "parent"))
1869         {
1870                 /* This is not allowed. */
1871                 PythonReturnErrorObject (PyExc_AttributeError,
1872                                         "Setting the parent is not allowed.");
1873                 return (0);
1874         }
1875         if (StringEqual (name, "track"))
1876         {
1877                 /* This is not allowed. */
1878                 PythonReturnErrorObject (PyExc_AttributeError,
1879                                         "Setting the track is not allowed.");
1880                 return (0);
1881         }
1882         if (StringEqual (name, "data"))
1883         {
1884                 /* This is not allowed. */
1885                 PythonReturnErrorObject (PyExc_AttributeError,
1886                                         "Setting the data is not allowed.");
1887                 return (0);
1888         }
1889         if (StringEqual (name, "ipo"))
1890         {
1891                 /* This is not allowed. */
1892                 PythonReturnErrorObject (PyExc_AttributeError,
1893                                         "Setting the ipo is not allowed.");
1894                 return (0);
1895         }
1896         if (StringEqual (name, "mat"))
1897         {
1898                 /* This is not allowed. */
1899                 PythonReturnErrorObject (PyExc_AttributeError,
1900                                         "Setting the matrix is not allowed.");
1901                 return (0);
1902         }
1903         if (StringEqual (name, "matrix"))
1904         {
1905                 /* This is not allowed. */
1906                 PythonReturnErrorObject (PyExc_AttributeError,
1907                                         "Please use .setMatrix(matrix)");
1908                 return (0);
1909         }
1910         if (StringEqual (name, "colbits"))
1911                 return (!PyArg_Parse (value, "h", &(object->colbits)));
1912         if (StringEqual (name, "drawType"))
1913         {
1914                 if (Object_setDrawType (obj, valtuple) != Py_None)
1915                         return (-1);
1916                 else
1917                         return (0);
1918         }
1919         if (StringEqual (name, "drawMode"))
1920         {
1921                 if (Object_setDrawMode (obj, valtuple) != Py_None)
1922                         return (-1);
1923                 else
1924                         return (0);
1925         }
1926         if (StringEqual (name, "name"))
1927         {
1928                 if (Object_setName (obj, valtuple) != Py_None)
1929                         return (-1);
1930                 else
1931                         return (0);
1932         }
1933
1934         printf ("Unknown variable.\n");
1935         return (0);
1936 }
1937
1938 /*****************************************************************************/
1939 /* Function:    Object_compare                                                                                           */
1940 /* Description: This is a callback function for the BPy_Object type. It          */
1941 /*                              compares two Object_Type objects. Only the "==" and "!="         */
1942 /*                              comparisons are meaninful. Returns 0 for equality and -1 if  */
1943 /*                              they don't point to the same Blender Object struct.                      */
1944 /*                              In Python it becomes 1 if they are equal, 0 otherwise.           */
1945 /*****************************************************************************/
1946 static int Object_compare (BPy_Object *a, BPy_Object *b)
1947 {
1948   Object *pa = a->object, *pb = b->object;
1949   return (pa == pb) ? 0:-1;
1950 }
1951
1952 /*****************************************************************************/
1953 /* Function:    Object_repr                                                                                                      */
1954 /* Description: This is a callback function for the BPy_Object type. It          */
1955 /*                              builds a meaninful string to represent object objects.           */
1956 /*****************************************************************************/
1957 static PyObject *Object_repr (BPy_Object *self)
1958 {
1959   return PyString_FromFormat("[Object \"%s\"]", self->object->id.name+2);
1960 }
1961