/* 
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 *
 * The Object module provides generic access to Objects of various types via
 * the Python interface.
 *
 *
 * Contributor(s): Michel Selten, Willian Germano, Jacques Guignot,
 * Joseph Gilbert, Stephen Swaney, Bala Gi, Campbell Barton
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
*/

#include "Object.h"
#include "NLA.h"
#include "logic.h"
#include <blendef.h>
#include <DNA_scene_types.h>
#include <DNA_property_types.h>
#include <BSE_edit.h>
#include <BKE_property.h>
#include <BKE_mball.h>
#include <BIF_editview.h>


/*****************************************************************************/
/* Python API function prototypes for the Blender module.					 */
/*****************************************************************************/
static PyObject *M_Object_New(PyObject *self, PyObject *args);
PyObject *M_Object_Get(PyObject *self, PyObject *args);
PyObject *M_Object_get(PyObject *self, PyObject *args);
static PyObject *M_Object_GetSelected (PyObject *self, PyObject *args);
static PyObject *M_Object_getSelected (PyObject *self, PyObject *args);

/*****************************************************************************/
/* The following string definitions are used for documentation strings.		 */
/* In Python these will be written to the console when doing a				 */
/* Blender.Object.__doc__													 */
/*****************************************************************************/
char M_Object_doc[] =
"The Blender Object module\n\n\
This module provides access to **Object Data** in Blender.\n";

char M_Object_New_doc[] =
"(type) - Add a new object of type 'type' in the current scene";

char M_Object_Get_doc[] =
"(name) - return the object with the name 'name', returns None if not\
	found.\n\
	If 'name' is not specified, it returns a list of all objects in the\n\
	current scene.";

char M_Object_GetSelected_doc[] =
"() - Returns a list of selected Objects in the active layer(s)\n\
The active object is the first in the list, if visible";

/*****************************************************************************/
/* Python method structure definition for Blender.Object module:			 */
/*****************************************************************************/
struct PyMethodDef M_Object_methods[] = {
	{"New",			(PyCFunction)M_Object_New,		   METH_VARARGS,
					M_Object_New_doc},
	{"Get",			(PyCFunction)M_Object_Get,		   METH_VARARGS,
					M_Object_Get_doc},
	{"get",			(PyCFunction)M_Object_get,		   METH_VARARGS,
					M_Object_Get_doc},
	{"GetSelected", (PyCFunction)M_Object_GetSelected, METH_VARARGS,
					M_Object_GetSelected_doc},
	{"getSelected", (PyCFunction)M_Object_getSelected, METH_VARARGS,
					M_Object_GetSelected_doc},
	{NULL, NULL, 0, NULL}
};

/*****************************************************************************/
/* Python BPy_Object methods declarations:									   */
/*****************************************************************************/
static PyObject *Object_buildParts (BPy_Object *self);
static PyObject *Object_clearIpo (BPy_Object *self);
static PyObject *Object_clrParent (BPy_Object *self, PyObject *args);
static PyObject *Object_clearTrack (BPy_Object *self, PyObject *args);
static PyObject *Object_getData (BPy_Object *self);
static PyObject *Object_getDeltaLocation (BPy_Object *self);
static PyObject *Object_getDrawMode (BPy_Object *self);
static PyObject *Object_getDrawType (BPy_Object *self);
static PyObject *Object_getEuler (BPy_Object *self);
static PyObject *Object_getInverseMatrix (BPy_Object *self);
static PyObject *Object_getIpo (BPy_Object *self);
static PyObject *Object_getLocation (BPy_Object *self, PyObject *args);
static PyObject *Object_getMaterials (BPy_Object *self, PyObject *args);
static PyObject *Object_getMatrix (BPy_Object *self, PyObject *args);
static PyObject *Object_getName (BPy_Object *self);
static PyObject *Object_getParent (BPy_Object *self);
static PyObject *Object_getSize (BPy_Object *self, PyObject *args);
static PyObject *Object_getTimeOffset (BPy_Object *self);
static PyObject *Object_getTracked (BPy_Object *self);
static PyObject *Object_getType (BPy_Object *self);
static PyObject *Object_getBoundBox (BPy_Object *self);
static PyObject *Object_getAction (BPy_Object *self);
static PyObject *Object_isSelected (BPy_Object *self);
static PyObject *Object_makeDisplayList (BPy_Object *self);
static PyObject *Object_link (BPy_Object *self, PyObject *args);
static PyObject *Object_makeParent (BPy_Object *self, PyObject *args);
static PyObject *Object_materialUsage (BPy_Object *self, PyObject *args);
static PyObject *Object_setDeltaLocation (BPy_Object *self, PyObject *args);
static PyObject *Object_setDrawMode (BPy_Object *self, PyObject *args);
static PyObject *Object_setDrawType (BPy_Object *self, PyObject *args);
static PyObject *Object_setEuler (BPy_Object *self, PyObject *args);\
static PyObject *Object_setMatrix (BPy_Object *self, PyObject *args);
static PyObject *Object_setIpo (BPy_Object *self, PyObject *args);
static PyObject *Object_setLocation (BPy_Object *self, PyObject *args);
static PyObject *Object_setMaterials (BPy_Object *self, PyObject *args);
static PyObject *Object_setName (BPy_Object *self, PyObject *args);
static PyObject *Object_setSize (BPy_Object *self, PyObject *args);
static PyObject *Object_setTimeOffset (BPy_Object *self, PyObject *args);
static PyObject *Object_makeTrack (BPy_Object *self, PyObject *args);
static PyObject *Object_shareFrom (BPy_Object *self, PyObject *args);
static PyObject *Object_Select (BPy_Object *self, PyObject *args);
static PyObject *Object_getAllProperties (BPy_Object *self);
static PyObject *Object_addProperty(BPy_Object *self, PyObject *args);
static PyObject *Object_removeProperty(BPy_Object *self, PyObject *args);
static PyObject *Object_getProperty(BPy_Object *self, PyObject *args);
static PyObject *Object_removeAllProperties(BPy_Object *self);
static PyObject *Object_copyAllPropertiesTo(BPy_Object *self, PyObject *args);
static PyObject *Object_getScriptLinks(BPy_Object *self, PyObject *args);
static PyObject *Object_addScriptLink(BPy_Object *self, PyObject *args);
static PyObject *Object_clearScriptLinks(BPy_Object *self);

/*****************************************************************************/
/* Python BPy_Object methods table:											   */
/*****************************************************************************/
static PyMethodDef BPy_Object_methods[] = {
	/* name, method, flags, doc */
  {"buildParts", (PyCFunction)Object_buildParts, METH_NOARGS,
	"Recalcs particle system (if any) "},
  {"getIpo", (PyCFunction)Object_getIpo, METH_NOARGS,
		"Returns the ipo of this object (if any) "},   
  {"clrParent", (PyCFunction)Object_clrParent, METH_VARARGS,
	"Clears parent object. Optionally specify:\n\
mode\n\tnonzero: Keep object transform\nfast\n\t>0: Don't update scene \
hierarchy (faster)"},
  {"clearTrack", (PyCFunction)Object_clearTrack, METH_VARARGS,
	"Make this object not track another anymore. Optionally specify:\n\
mode\n\t2: Keep object transform\nfast\n\t>0: Don't update scene \
hierarchy (faster)"},
  {"getData", (PyCFunction)Object_getData, METH_NOARGS,
	"Returns the datablock object containing the object's data, e.g. Mesh"},
  {"getDeltaLocation", (PyCFunction)Object_getDeltaLocation, METH_NOARGS,
	"Returns the object's delta location (x, y, z)"},
  {"getDrawMode", (PyCFunction)Object_getDrawMode, METH_NOARGS,
	"Returns the object draw modes"},
  {"getDrawType", (PyCFunction)Object_getDrawType, METH_NOARGS,
	"Returns the object draw type"},
  {"getAction", (PyCFunction)Object_getAction, METH_NOARGS,
	"Returns the active action for this object"},
  {"isSelected", (PyCFunction)Object_isSelected, METH_NOARGS,
	"Return a 1 or 0 depending on whether the object is selected"},  
  {"getEuler", (PyCFunction)Object_getEuler, METH_NOARGS,
	"Returns the object's rotation as Euler rotation vector\n\
(rotX, rotY, rotZ)"},
  {"getInverseMatrix", (PyCFunction)Object_getInverseMatrix, METH_NOARGS,
	"Returns the object's inverse matrix"},
  {"getLocation", (PyCFunction)Object_getLocation, METH_VARARGS,
	"Returns the object's location (x, y, z)"},
  {"getMaterials", (PyCFunction)Object_getMaterials, METH_VARARGS,
	"(i = 0) - Returns list of materials assigned to the object.\n\
if i is nonzero, empty slots are not ignored: they are returned as None's."},
  {"getMatrix", (PyCFunction)Object_getMatrix, METH_VARARGS,
	"Returns the object matrix - worlspace or localspace (default)"},
  {"getName", (PyCFunction)Object_getName, METH_NOARGS,
	"Returns the name of the object"},
  {"getParent", (PyCFunction)Object_getParent, METH_NOARGS,
	"Returns the object's parent object"},
  {"getSize", (PyCFunction)Object_getSize, METH_VARARGS,
	"Returns the object's size (x, y, z)"},
  {"getTimeOffset", (PyCFunction)Object_getTimeOffset, METH_NOARGS,
	"Returns the object's time offset"},
  {"getTracked", (PyCFunction)Object_getTracked, METH_NOARGS,
	"Returns the object's tracked object"},
  {"getType", (PyCFunction)Object_getType, METH_NOARGS,
	"Returns type of string of Object"},
  {"getBoundBox", (PyCFunction)Object_getBoundBox, METH_NOARGS,
	"Returns the object's bounding box"},
  {"makeDisplayList", (PyCFunction)Object_makeDisplayList, METH_NOARGS,
	"Update this object's Display List. Some changes like turning \n\
'SubSurf' on for a mesh need this method (followed by a Redraw) to \n\
show the changes on the 3d window."},
  {"link", (PyCFunction)Object_link, METH_VARARGS,
	"Links Object with data provided in the argument. The data must \n\
match the Object's type, so you cannot link a Lamp to a Mesh type object."},
  {"makeParent", (PyCFunction)Object_makeParent, METH_VARARGS,
	"Makes the object the parent of the objects provided in the \n\
argument which must be a list of valid Objects. Optional extra arguments:\n\
mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
fast:\n\t0: update scene hierarchy automatically\n\t\
don't update scene hierarchy (faster). In this case, you must\n\t\
explicitely update the Scene hierarchy."},
  {"materialUsage", (PyCFunction)Object_materialUsage, METH_VARARGS,
	"Determines the way the material is used and returns status.\n\
Possible arguments (provide as strings):\n\
\tData:   Materials assigned to the object's data are shown. (default)\n\
\tObject: Materials assigned to the object are shown."},
  {"setDeltaLocation", (PyCFunction)Object_setDeltaLocation, METH_VARARGS,
	"Sets the object's delta location which must be a vector triple."},
  {"setDrawMode", (PyCFunction)Object_setDrawMode, METH_VARARGS,
	"Sets the object's drawing mode. The argument can be a sum of:\n\
2:	axis\n4:  texspace\n8:	drawname\n16: drawimage\n32: drawwire"},
  {"setDrawType", (PyCFunction)Object_setDrawType, METH_VARARGS,
	"Sets the object's drawing type. The argument must be one of:\n\
1: Bounding box\n2: Wire\n3: Solid\n4: Shaded\n5: Textured"},
  {"setEuler", (PyCFunction)Object_setEuler, METH_VARARGS,
	"Set the object's rotation according to the specified Euler\n\
angles. The argument must be a vector triple"},
  {"setMatrix", (PyCFunction)Object_setMatrix, METH_VARARGS,
	"Set and apply a new matrix for the object"},
  {"setLocation", (PyCFunction)Object_setLocation, METH_VARARGS,
	"Set the object's location. The first argument must be a vector\n\
triple."},
  {"setMaterials", (PyCFunction)Object_setMaterials, METH_VARARGS,
	"Sets materials. The argument must be a list of valid material\n\
objects."},
  {"setName", (PyCFunction)Object_setName, METH_VARARGS,
	"Sets the name of the object"},
  {"setSize", (PyCFunction)Object_setSize, METH_VARARGS,
	"Set the object's size. The first argument must be a vector\n\
triple."},
  {"setTimeOffset", (PyCFunction)Object_setTimeOffset, METH_VARARGS,
	"Set the object's time offset."},
  {"makeTrack", (PyCFunction)Object_makeTrack, METH_VARARGS,
	"(trackedobj, fast = 0) - Make this object track another.\n\
	 (trackedobj) - the object that will be tracked.\n\
	 (fast = 0) - if 0: update the scene hierarchy automatically.  If you\n\
	 set 'fast' to a nonzero value, don't forget to update the scene yourself\n\
	 (see scene.update())."},
  {"shareFrom", (PyCFunction)Object_shareFrom, METH_VARARGS,
	"Link data of self with object specified in the argument. This\n\
works only if self and the object specified are of the same type."},
  {"select", (PyCFunction)Object_Select, METH_VARARGS,
	"( 1 or 0 )  - Set the selected state of the object.\n\
   1 is selected, 0 not selected "},
  {"setIpo", (PyCFunction)Object_setIpo, METH_VARARGS,
	"(Blender Ipo) - Sets the object's ipo"},
  {"clearIpo", (PyCFunction)Object_clearIpo, METH_NOARGS,
	"() - Unlink ipo from this object"},
  {"getAllProperties", (PyCFunction)Object_getAllProperties, METH_NOARGS,
  "() - Get all the properties from this object"},
  {"addProperty", (PyCFunction)Object_addProperty, METH_VARARGS,
  "() - Add a property to this object"},
  {"removeProperty", (PyCFunction)Object_removeProperty, METH_VARARGS,
  "() - Remove a property from  this object"},
  {"getProperty", (PyCFunction)Object_getProperty, METH_VARARGS,
  "() - Get a property from this object by name"},
   {"removeAllProperties", (PyCFunction)Object_removeAllProperties, METH_NOARGS,
  "() - removeAll a properties from this object"},
   {"copyAllPropertiesTo", (PyCFunction)Object_copyAllPropertiesTo, METH_VARARGS,
  "() - copy all properties from this object to another object"},
	{"getScriptLinks", (PyCFunction)Object_getScriptLinks, METH_VARARGS,
			"(eventname) - Get a list of this object's scriptlinks (Text names) "
			"of the given type\n"
	"(eventname) - string: FrameChanged or Redraw."},
	{"addScriptLink", (PyCFunction)Object_addScriptLink, METH_VARARGS,
			"(text, evt) - Add a new object scriptlink.\n"
	"(text) - string: an existing Blender Text name;\n"
	"(evt) string: FrameChanged or Redraw."},
	{"clearScriptLinks", (PyCFunction)Object_clearScriptLinks, METH_NOARGS,
			"() - Delete all scriptlinks from this object."},
  {NULL, NULL, 0, NULL}
};

/*****************************************************************************/
/* PythonTypeObject callback function prototypes							 */
/*****************************************************************************/
static void		 Object_dealloc (BPy_Object *obj);
static PyObject* Object_getAttr (BPy_Object *obj, char *name);
static int		 Object_setAttr (BPy_Object *obj, char *name, PyObject *v);
static PyObject* Object_repr	(BPy_Object *obj);
static int		 Object_compare (BPy_Object *a, BPy_Object *b);

/*****************************************************************************/
/* Python TypeObject structure definition.									 */
/*****************************************************************************/
PyTypeObject Object_Type =
{
  PyObject_HEAD_INIT(NULL)
  0,								/* ob_size */
  "Blender Object",					/* tp_name */
  sizeof (BPy_Object),				/* tp_basicsize */
  0,								/* tp_itemsize */
  /* methods */
  (destructor)Object_dealloc,		/* tp_dealloc */
  0,								/* tp_print */
  (getattrfunc)Object_getAttr,		/* tp_getattr */
  (setattrfunc)Object_setAttr,		/* tp_setattr */
  (cmpfunc)Object_compare,			/* tp_compare */
  (reprfunc)Object_repr,			/* tp_repr */
  0,								/* tp_as_number */
  0,								/* tp_as_sequence */
  0,								/* tp_as_mapping */
  0,								/* tp_as_hash */
  0,0,0,0,0,0,
  0,								/* tp_doc */ 
  0,0,0,0,0,0,
  BPy_Object_methods,				/* tp_methods */
  0,								/* tp_members */
};

/*****************************************************************************/
/* Function:			  M_Object_New										 */
/* Python equivalent:	  Blender.Object.New								 */
/*****************************************************************************/
PyObject *M_Object_New(PyObject *self, PyObject *args)
{
  struct Object * object;
  BPy_Object	  * blen_object;
  int		type;
  char	* str_type;
  char	* name = NULL;

  if (!PyArg_ParseTuple(args, "s|s", &str_type, &name))
  {
		EXPP_ReturnPyObjError (PyExc_TypeError, "string expected as argument");
		return (NULL);
  }

  if (strcmp (str_type, "Armature") == 0)	  type = OB_ARMATURE;
  else if (strcmp (str_type, "Camera") == 0)  type = OB_CAMERA;
  else if (strcmp (str_type, "Curve") == 0)   type = OB_CURVE;
/*	else if (strcmp (str_type, "Text") == 0)	type = OB_FONT; */
/*	else if (strcmp (str_type, "Ika") == 0)		type = OB_IKA; */
  else if (strcmp (str_type, "Lamp") == 0)	  type = OB_LAMP;
  else if (strcmp (str_type, "Lattice") == 0) type = OB_LATTICE;
	else if (strcmp (str_type, "Mball") == 0)	type = OB_MBALL; 
  else if (strcmp (str_type, "Mesh") == 0)	  type = OB_MESH;
  else if (strcmp (str_type, "Surf") == 0)	  type = OB_SURF;
/*	else if (strcmp (str_type, "Wave") == 0)	type = OB_WAVE; */
  else if (strcmp (str_type, "Empty") == 0)   type = OB_EMPTY;
  else
  {
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
	  	"Unknown type specified"));
  }

  /* Create a new object. */
  if (name == NULL)
  {
	  /* No name is specified, set the name to the type of the object. */
		name = str_type;
  }
  object = alloc_libblock (&(G.main->object), ID_OB, name);

  object->id.us = 0;
  object->flag = 0;
  object->type = type;
  

  /* transforms */
  QuatOne(object->quat);
  QuatOne(object->dquat);

  object->col[3]= 1.0;	  // alpha 

  object->size[0] = object->size[1] = object->size[2] = 1.0;
  object->loc[0] = object->loc[1] = object->loc[2] = 0.0;
  Mat4One(object->parentinv);
  Mat4One(object->obmat);
  object->dt = OB_SHADED; // drawtype

  if (U.flag & USER_MAT_ON_OB)
  {
		object->colbits = -1;
  }
  switch (object->type)
  {
		case OB_CAMERA: /* fall through. */
		case OB_LAMP:
		  object->trackflag = OB_NEGZ;
		  object->upflag = OB_POSY;
	  	break;
		default:
		  object->trackflag = OB_POSY;
	 	 object->upflag = OB_POSZ;
  }
  object->ipoflag = OB_OFFS_OB + OB_OFFS_PARENT;

  /* duplivert settings */
  object->dupon = 1;
  object->dupoff = 0;
  object->dupsta = 1;
  object->dupend = 100;

  /* Gameengine defaults*/
  object->mass = 1.0;
  object->inertia = 1.0;
  object->formfactor = 0.4;
  object->damping = 0.04;
  object->rdamping = 0.1;
  object->anisotropicFriction[0] = 1.0;
  object->anisotropicFriction[1] = 1.0;
  object->anisotropicFriction[2] = 1.0;
  object->gameflag = OB_PROP;

  object->lay = 1; // Layer, by default visible
  G.totobj++;

  object->data = NULL;

  /* Create a Python object from it. */
  blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
  blen_object->object = object;

  return ((PyObject*)blen_object);
}

/*****************************************************************************/
/* Function:			  M_Object_Get										 */
/* Python equivalent:	  Blender.Object.Get								 */
/*****************************************************************************/
PyObject *M_Object_Get(PyObject *self, PyObject *args)
{
	struct Object	* object;
	BPy_Object		* blen_object;
	char			* name = NULL;

	PyArg_ParseTuple(args, "|s", &name);

	if (name != NULL)
	{
		object = GetObjectByName (name);

		if (object == NULL)
		{
			/* No object exists with the name specified in the argument name. */
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,
						"Unknown object specified."));
		}
		blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
		blen_object->object = object;

		return ((PyObject*)blen_object);
	}
	else
	{
		/* No argument has been given. Return a list of all objects. */
		PyObject	* obj_list;
		Link		* link;
		int			  index;

		obj_list = PyList_New (BLI_countlist (&(G.main->object)));

		if (obj_list == NULL)
		{
			return (EXPP_ReturnPyObjError (PyExc_SystemError,
					"List creation failed."));
		}

		link = G.main->object.first;
		index = 0;
		while (link)
		{
			object = (Object*)link;
			blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type);
			blen_object->object = object;

			PyList_SetItem (obj_list, index, (PyObject*)blen_object);
			index++;
			link = link->next;
		}
		return (obj_list);
	}
}

/*****************************************************************************/
/* Function:			  M_Object_get										 */
/* Python equivalent:	  Blender.Object.get								 */
/*****************************************************************************/
PyObject *M_Object_get(PyObject *self, PyObject *args)
{
	PyErr_Warn (PyExc_DeprecationWarning,
		"The Object.get() function will be removed in Blender 2.29\n" \
		"Please update the script to use Object.Get");
	return (M_Object_Get (self, args));
}

/*****************************************************************************/
/* Function:			  M_Object_GetSelected								 */
/* Python equivalent:	  Blender.Object.getSelected						 */
/*****************************************************************************/
static PyObject *M_Object_GetSelected (PyObject *self, PyObject *args)
{
	BPy_Object		  * blen_object;
	PyObject		* list;
	Base			* base_iter;

    if (G.vd == NULL)
    {
        // No 3d view has been initialized yet, simply return None
        Py_INCREF (Py_None);
        return Py_None;
    }
	list = PyList_New (0);
	if ((G.scene->basact) &&
		((G.scene->basact->flag & SELECT) &&
		 (G.scene->basact->lay & G.vd->lay)))
	{
		/* Active object is first in the list. */
		blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
		if (blen_object == NULL)
		{
			Py_DECREF (list);
			Py_INCREF (Py_None);
			return (Py_None);
		}
		blen_object->object = G.scene->basact->object;
		PyList_Append (list, (PyObject*)blen_object);
	}

	base_iter = G.scene->base.first;
	while (base_iter)
	{
		if (((base_iter->flag & SELECT) &&
			 (base_iter->lay & G.vd->lay)) &&
			(base_iter != G.scene->basact))
		{
			blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type); 
			if (blen_object == NULL)
			{
				Py_DECREF (list);
				Py_INCREF (Py_None);
				return (Py_None);
			}
			blen_object->object = base_iter->object;
			PyList_Append (list, (PyObject*)blen_object);
		}
		base_iter = base_iter->next;
	}
	return (list);
}

/*****************************************************************************/
/* Function:			  M_Object_getSelected								 */
/* Python equivalent:	  Blender.Object.getSelected						 */
/*****************************************************************************/
static PyObject *M_Object_getSelected (PyObject *self, PyObject *args)
{
	PyErr_Warn (PyExc_DeprecationWarning,
				"The Object.getSelected() function will be removed in "\
				"Blender 2.29\n" \
				"Please update the script to use Object.GetSelected");
	return (M_Object_GetSelected (self, args));
}

/*****************************************************************************/
/* Function:			  initObject										 */
/*****************************************************************************/
PyObject *Object_Init (void)
{
	PyObject	* module;

	Object_Type.ob_type = &PyType_Type;

	module = Py_InitModule3("Blender.Object", M_Object_methods, M_Object_doc);

	return (module);
}

/*****************************************************************************/
/* Python BPy_Object methods:												   */
/*****************************************************************************/

static PyObject *Object_buildParts (BPy_Object *self)
{
  void build_particle_system(Object *ob);
  struct Object *obj = self->object;

  build_particle_system(obj);

  Py_INCREF (Py_None);
  return (Py_None);
}

static PyObject *Object_clearIpo(BPy_Object *self)
{
	Object *ob = self->object;
	Ipo *ipo = (Ipo *)ob->ipo;

	if (ipo) {
		ID *id = &ipo->id;
		if (id->us > 0) id->us--;
		ob->ipo = NULL;

		Py_INCREF (Py_True);
		return Py_True;
	}

	Py_INCREF (Py_False); /* no ipo found */
	return Py_False;
}

static PyObject *Object_clrParent (BPy_Object *self, PyObject *args)
{
  int mode=0;
  int fast=0;

  if (!PyArg_ParseTuple (args, "|ii", &mode, &fast))
  {
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
		  "expected one or two integers as arguments"));
  }

  /* Remove the link only, the object is still in the scene. */
  self->object->parent = NULL;

  if (mode == 2)
  {
		/* Keep transform */
		apply_obmat (self->object);
  }

  if (!fast)
  {
		sort_baselist (G.scene);
  }

  Py_INCREF (Py_None);
  return (Py_None);
}

static PyObject *Object_clearTrack (BPy_Object *self, PyObject *args)
{
  int mode=0;
  int fast=0;

  if (!PyArg_ParseTuple (args, "|ii", &mode, &fast))
  {
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
		  "expected one or two integers as arguments"));
  }

  /* Remove the link only, the object is still in the scene. */
  self->object->track = NULL;

  if (mode)
  {
		/* Keep transform */
		apply_obmat (self->object);
  }

  if (!fast)
  {
		sort_baselist (G.scene);
  }

  Py_INCREF (Py_None);
  return (Py_None);
}

/* adds object data to a Blender object, if object->data = NULL */
int EXPP_add_obdata(struct Object *object)
{
  if (object->data != NULL) return -1;

  switch(object->type)
  {
	case OB_ARMATURE:
	/* TODO: Do we need to add something to G? (see the OB_LAMP case) */
	  object->data = add_armature();
	  break;
	case OB_CAMERA:
	  /* TODO: Do we need to add something to G? (see the OB_LAMP case) */
	  object->data = add_camera();
	  break;
	case OB_CURVE:
	  object->data = add_curve(OB_CURVE);
	  G.totcurve++;
	  break;
	case OB_LAMP:
	  object->data = add_lamp();
	  G.totlamp++;
	  break;
	case OB_MESH:
	  object->data = add_mesh();
	  G.totmesh++;
	  break;
	case OB_LATTICE:
      object->data = (void *)add_lattice();
	  object->dt = OB_WIRE;
	  break;
	case OB_MBALL:
	  object->data = add_mball();
	  break;

	/* TODO the following types will be supported later
	case OB_SURF:
	  object->data = add_curve(OB_SURF);
	  G.totcurve++;
	  break;
	case OB_FONT:
	  object->data = add_curve(OB_FONT);
	  break;
	case OB_IKA:
	  object->data = add_ika();
	  object->dt = OB_WIRE;
	  break;
	case OB_WAVE:
	  object->data = add_wave();
	  break;
	*/
	default:
	  break;
  }

  if (!object->data) return -1;

  return 0;
}


static PyObject *Object_getData (BPy_Object *self)
{
	PyObject  * data_object;
	Object * object = self->object;

	/* if there's no obdata, try to create it */
	if (object->data == NULL)
	{
	  if (EXPP_add_obdata(object) != 0)
	  { /* couldn't create obdata */
		Py_INCREF (Py_None);
		return (Py_None);
	  }
	}

	data_object = NULL;

	switch (object->type)
	{
		case OB_ARMATURE:
			data_object = Armature_CreatePyObject (object->data);
			break;
		case OB_CAMERA:
			data_object = Camera_CreatePyObject (object->data);
			break;
		case OB_CURVE:
			data_object = Curve_CreatePyObject (object->data);
			break;
		case ID_IM:
			data_object = Image_CreatePyObject (object->data);
			break;
		case ID_IP:
			data_object = Ipo_CreatePyObject (object->data);
			break;
		case OB_LAMP:
			data_object = Lamp_CreatePyObject (object->data);
			break;
		case OB_LATTICE:
			data_object = Lattice_CreatePyObject (object->data);
			break;
		case ID_MA:
			break;
		case OB_MESH:
			data_object = NMesh_CreatePyObject (object->data, object);
			break;
		case ID_OB:
			data_object = Object_CreatePyObject (object->data);
			break;
		case ID_SCE:
			break;
		case ID_TXT:
			data_object = Text_CreatePyObject (object->data);
			break;
		case ID_WO:
			break;
		default:
			break;
	}
	if (data_object == NULL)
	{
		Py_INCREF (Py_None);
		return (Py_None);
	}
	else
	{
		return (data_object);
	}
}

static PyObject *Object_getDeltaLocation (BPy_Object *self)
{
	PyObject *attr = Py_BuildValue ("fff",
									self->object->dloc[0],
									self->object->dloc[1],
									self->object->dloc[2]);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.dloc attributes"));
}

static PyObject *Object_getDrawMode (BPy_Object *self)
{
	PyObject *attr = Py_BuildValue ("b", self->object->dtx);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.drawMode attribute"));
}

static PyObject *Object_getAction (BPy_Object *self)
{
	/*BPy_Action *py_action = NULL;*/

	if(!self->object->action){
		Py_INCREF (Py_None);
		return (Py_None);
	}else{
		return Action_CreatePyObject (self->object->action);
	}
}


static PyObject *Object_isSelected (BPy_Object *self)
{
	Base *base;
  
	base= FIRSTBASE;
	while (base) {
		if (base->object == self->object) {
			if (base->flag & SELECT) {
				Py_INCREF (Py_True);
				return Py_True;
			} else {
				Py_INCREF (Py_False);
				return Py_False;
			}
		}
		base= base->next;
	}
	return ( EXPP_ReturnPyObjError (PyExc_RuntimeError,
					 "Internal error: could not find objects selection state"));
}


static PyObject *Object_getDrawType (BPy_Object *self)
{
	PyObject *attr = Py_BuildValue ("b", self->object->dt);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.drawType attribute"));
}

static PyObject *Object_getEuler (BPy_Object *self)
{  
	EulerObject *eul;

	eul = (EulerObject*)newEulerObject(NULL);
	eul->eul[0] = self->object->rot[0];
	eul->eul[1] = self->object->rot[1];
	eul->eul[2] = self->object->rot[2];

	return (PyObject*)eul; 

}

static PyObject *Object_getInverseMatrix (BPy_Object *self)
{
	MatrixObject *inverse = (MatrixObject *)newMatrixObject(NULL, 4, 4);
	Mat4Invert (*inverse->matrix, self->object->obmat);

	return ((PyObject *)inverse);
}

static PyObject *Object_getIpo(BPy_Object *self)
{
  struct Ipo *ipo = self->object->ipo;

  if (!ipo)
	{
		Py_INCREF (Py_None);
		return Py_None;
  }

  return Ipo_CreatePyObject (ipo);
}

static PyObject *Object_getLocation (BPy_Object *self, PyObject *args)
{
	PyObject *attr = Py_BuildValue ("fff",
									self->object->loc[0],
									self->object->loc[1],
									self->object->loc[2]);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.loc attributes"));
}

static PyObject *Object_getMaterials (BPy_Object *self, PyObject *args)
{
	int all = 0;

	if (!PyArg_ParseTuple(args, "|i", &all)){
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
			"expected an int or nothing"));
	}

	return (EXPP_PyList_fromMaterialList (self->object->mat,
										  self->object->totcol, all));
}

static PyObject *Object_getMatrix (BPy_Object *self, PyObject *args)
{
	PyObject  *matrix;
	char *space = "localspace";	 /* default to local */

	if (!PyArg_ParseTuple(args, "|s", &space)){
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
			"expected a string or nothing"));
	}
	//new matrix
	matrix = newMatrixObject(NULL, 4, 4);

	if (BLI_streq(space, "worldspace")){  	/* Worldspace matrix */
		where_is_object(self->object);
		Mat4CpyMat4(*((MatrixObject*)matrix)->matrix, self->object->obmat);
	} else if (BLI_streq(space, "localspace")) { /* Localspace matrix*/
		object_to_mat4(self->object, *((MatrixObject*)matrix)->matrix);
	} else {
		return (EXPP_ReturnPyObjError (PyExc_RuntimeError, 
			"correct  	spaces are 'worldspace' and 'localspace', none defaults to localespace"));
	}
	return matrix;
}

static PyObject *Object_getName (BPy_Object *self)
{
	PyObject *attr = Py_BuildValue ("s", self->object->id.name+2);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get the name of the Object"));
}

static PyObject *Object_getParent (BPy_Object *self)
{
	PyObject *attr;

	if (self->object->parent == NULL)
		return EXPP_incr_ret (Py_None);

	attr = Object_CreatePyObject (self->object->parent);

	if (attr)
	{
		return (attr);
	}

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.parent attribute"));
}

static PyObject *Object_getSize (BPy_Object *self, PyObject *args)
{
	PyObject *attr = Py_BuildValue ("fff",
									self->object->size[0],
									self->object->size[1],
									self->object->size[2]);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.size attributes"));
}

static PyObject *Object_getTimeOffset (BPy_Object *self)
{
	PyObject *attr = Py_BuildValue ("f", self->object->sf);

	if (attr) return (attr);

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.sf attributes"));
}


static PyObject *Object_getTracked (BPy_Object *self)
{
	PyObject	*attr;

	if (self->object->track == NULL)
		return EXPP_incr_ret (Py_None);
	
	attr = Object_CreatePyObject (self->object->track);

	if (attr)
	{
		return (attr);
	}

	return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
			"couldn't get Object.track attribute"));
}

static PyObject *Object_getType (BPy_Object *self)
{
	switch (self->object->type)
	{
		case OB_ARMATURE:	return (Py_BuildValue ("s", "Armature"));
		case OB_CAMERA:		return (Py_BuildValue ("s", "Camera"));
		case OB_CURVE:		return (Py_BuildValue ("s", "Curve"));
		case OB_EMPTY:		return (Py_BuildValue ("s", "Empty"));
		case OB_FONT:		return (Py_BuildValue ("s", "Text"));
		case OB_IKA:		return (Py_BuildValue ("s", "Ika"));
		case OB_LAMP:		return (Py_BuildValue ("s", "Lamp"));
		case OB_LATTICE:	return (Py_BuildValue ("s", "Lattice"));
		case OB_MBALL:		return (Py_BuildValue ("s", "MBall"));
		case OB_MESH:		return (Py_BuildValue ("s", "Mesh"));
		case OB_SURF:		return (Py_BuildValue ("s", "Surf"));
		case OB_WAVE:		return (Py_BuildValue ("s", "Wave"));
		default:			return (Py_BuildValue ("s", "unknown"));
	}
}


static PyObject *Object_getBoundBox (BPy_Object *self)
{
  int i;
  float *vec = NULL;
  PyObject *vector, *bbox;

  if (!self->object->data)
	return EXPP_ReturnPyObjError (PyExc_AttributeError,
	  "This object isn't linked to any object data (mesh, curve, etc) yet");

  if (!self->object->bb) {  /* if no ob bbox, we look in obdata */
	Mesh *me;
	Curve *curve;
	switch (self->object->type) {
	  case OB_MESH:
		me = self->object->data;
		if (!me->bb) tex_space_mesh(me);
		vec = (float *)me->bb->vec;
		break;
	  case OB_CURVE:
	  case OB_FONT:
	  case OB_SURF:
		curve = self->object->data;
		if (!curve->bb) tex_space_curve(curve);
		vec = (float *)curve->bb->vec;
		break;
	  default:
		Py_INCREF (Py_None);
		return Py_None;
	}

	{      /* transform our obdata bbox by the obmat.
		  the obmat is 4x4 homogeneous coords matrix.
	          each bbox coord is xyz, so we make it homogenous
		  by padding it with w=1.0 and doing the matrix mult.
		  afterwards we divide by w to get back to xyz.
	       */
		/* printmatrix4( "obmat", self->object->obmat); */

		float tmpvec[4];  /* tmp vector for homogenous coords math */
		int i;
		float *from;

		bbox = PyList_New(8);
		if (!bbox)
			return EXPP_ReturnPyObjError (PyExc_MemoryError,
						      "couldn't create pylist");
		for( i = 0, from = vec;
		     i < 8;
		     i++, from += 3 ) {
			memcpy( tmpvec, from, 3*sizeof(float));
			tmpvec[3]=1.0f;  /* set w coord */
			Mat4MulVec4fl(  self->object->obmat, tmpvec );
			/* divide x,y,z by w */
			tmpvec[0] /= tmpvec[3];
			tmpvec[1] /= tmpvec[3];
			tmpvec[2] /= tmpvec[3];

#if 0
			{ /* debug print stuff */
				int i;

				printf("\nobj bbox transformed\n");
				for( i=0; i<4; ++i)
					printf( "%f ", tmpvec[i]);

				printf("\n");
			}
#endif
	
			/* because our bounding box is calculated and
			   does not have its own memory,
			   we must create vectors that allocate space */
		
			vector = newVectorObject( NULL, 3);
			memcpy( ((VectorObject*)vector)->vec, 
				tmpvec, 
				3*sizeof(float));
			PyList_SET_ITEM(bbox, i, vector);
		}
	}
  }
  else{  /* the ob bbox exists */
      vec = (float *)self->object->bb->vec;

      if (!vec)
	    return EXPP_ReturnPyObjError (PyExc_RuntimeError,
					  "couldn't retrieve bounding box data");

      bbox = PyList_New(8);

      if (!bbox)
	    return EXPP_ReturnPyObjError (PyExc_MemoryError,
		  "couldn't create pylist");

      /* create vectors referencing object bounding box coords */
      for (i = 0; i < 8; i++) {
	vector = newVectorObject(vec, 3);
	PyList_SET_ITEM(bbox, i, vector);
	vec += 3;
      }
  }

  return bbox;
}


static PyObject *Object_makeDisplayList (BPy_Object *self)
{
  Object *ob = self->object;

  if (ob->type == OB_FONT) text_to_curve(ob, 0);

  makeDispList(ob);

  Py_INCREF (Py_None);
  return Py_None;
}

static PyObject *Object_link (BPy_Object *self, PyObject *args)
{
	PyObject	* py_data;
	ID			* id;
	ID			* oldid;
	int			  obj_id;
	void		* data = NULL;

	if (!PyArg_ParseTuple (args, "O", &py_data))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
			"expected an object as argument"));
	}
	if (Armature_CheckPyObject (py_data))
		data = (void *)Armature_FromPyObject (py_data);
	if (Camera_CheckPyObject (py_data))
		data = (void *)Camera_FromPyObject (py_data);
	if (Lamp_CheckPyObject (py_data))
		data = (void *)Lamp_FromPyObject (py_data);
	if (Curve_CheckPyObject (py_data))
		data = (void *)Curve_FromPyObject (py_data);
	if (NMesh_CheckPyObject (py_data))
		data = (void *)Mesh_FromPyObject (py_data, self->object);
	if (Lattice_CheckPyObject (py_data))
		data = (void *)Lattice_FromPyObject (py_data);
	if (Metaball_CheckPyObject (py_data))
		data = (void *)Metaball_FromPyObject (py_data);

	/* have we set data to something good? */
	if( !data )
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
			"link argument type is not supported "));
	}

	oldid = (ID*) self->object->data;
	id = (ID*) data;
	obj_id = MAKE_ID2 (id->name[0], id->name[1]);

	switch (obj_id)
	{
		case ID_AR:
			if (self->object->type != OB_ARMATURE)
			{
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,
					"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_CA:
			if (self->object->type != OB_CAMERA)
			{
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,
					"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_LA:
			if (self->object->type != OB_LAMP)
			{
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,
					"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_ME:
			if (self->object->type != OB_MESH)
			{
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,
					"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_CU:
			if (self->object->type != OB_CURVE)
			{
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,
					"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_LT:
			if (self->object->type != OB_LATTICE)
			{
					return (EXPP_ReturnPyObjError (PyExc_AttributeError,
							"The 'link' object is incompatible with the base object"));
			}
			break;
		case ID_MB:
			if (self->object->type != OB_MBALL)
			{
					return (EXPP_ReturnPyObjError (PyExc_AttributeError,
							"The 'link' object is incompatible with the base object"));
			}
			break;
		default:
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"Linking this object type is not supported"));
	}
	self->object->data = data;

	if ( self->object->type == OB_MESH)
	{
		self->object->totcol = 0;
		EXPP_synchronizeMaterialLists(self->object);
	}

	id_us_plus (id);
	if (oldid)
	{
		if (oldid->us > 0)
		{
			oldid->us--;
		}
		else
		{
			return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
				"old object reference count below 0"));
		}
	}
	return EXPP_incr_ret (Py_None);
}

static PyObject *Object_makeParent (BPy_Object *self, PyObject *args)
{
	PyObject	* list;
	PyObject	* py_child;
	//BPy_Object	  * py_obj_child; unused
	Object		* child;
	Object		* parent;
	int			  noninverse = 0;
	int			  fast = 0;
	int			  i;

	/* Check if the arguments passed to makeParent are valid. */
	if (!PyArg_ParseTuple (args, "O|ii", &list, &noninverse, &fast))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
			"expected a list of objects and one or two integers as arguments"));
	}
	if (!PySequence_Check (list))
	{
		return (EXPP_ReturnPyObjError (PyExc_TypeError,
			"expected a list of objects"));
	}

	/* Check if the PyObject passed in list is a Blender object. */
	for (i=0 ; i<PySequence_Length (list) ; i++)
	{
		child = NULL;
		py_child = PySequence_GetItem (list, i);
		if (Object_CheckPyObject (py_child))
			child = (Object*) Object_FromPyObject (py_child);

		if (child == NULL)
		{
			return (EXPP_ReturnPyObjError (PyExc_TypeError,
				"Object Type expected"));
		}

		parent = (Object*)self->object;
		if (test_parent_loop (parent, child))
		{
			return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
				"parenting loop detected - parenting failed"));
		}
		child->partype = PAROBJECT;
		child->parent = parent;
		//py_obj_child = (BPy_Object *) py_child;
		if (noninverse == 1)
		{
			/* Parent inverse = unity */
			child->loc[0] = 0.0;
			child->loc[1] = 0.0;
			child->loc[2] = 0.0;
		}
		else
		{
			what_does_parent (child);
			Mat4Invert (child->parentinv, parent->obmat);
		}

		if (!fast)
		{
			sort_baselist (G.scene);
		}

		// We don't need the child object anymore.
		//Py_DECREF ((PyObject *) child);
	}
	return EXPP_incr_ret (Py_None);
}

static PyObject *Object_materialUsage (BPy_Object *self, PyObject *args)
{
	return (EXPP_ReturnPyObjError (PyExc_NotImplementedError,
			"materialUsage: not yet implemented"));
}

static PyObject *Object_setDeltaLocation (BPy_Object *self, PyObject *args)
{
	float	dloc1;
	float	dloc2;
	float	dloc3;
	int		status;

	if (PyObject_Length (args) == 3)
		status = PyArg_ParseTuple (args, "fff", &dloc1, &dloc2, &dloc3);
	else
		status = PyArg_ParseTuple (args, "(fff)", &dloc1, &dloc2, &dloc3);

	if (!status)
		return EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected list argument of 3 floats");

	self->object->dloc[0] = dloc1;
	self->object->dloc[1] = dloc2;
	self->object->dloc[2] = dloc3;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setDrawMode (BPy_Object *self, PyObject *args)
{
	char	dtx;

	if (!PyArg_ParseTuple (args, "b", &dtx))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected an integer as argument"));
	}
	self->object->dtx = dtx;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setDrawType (BPy_Object *self, PyObject *args)
{ 
	char	dt;

	if (!PyArg_ParseTuple (args, "b", &dt))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected an integer as argument"));
	}
	self->object->dt = dt;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setEuler (BPy_Object *self, PyObject *args)
{
	float	rot1;
	float	rot2;
	float	rot3;
	int	status = 0; /* failure */
	PyObject* ob;

	/* 
	   args is either a tuple/list of floats or an euler.
	   for backward compatibility, we also accept 3 floats.
	*/
	   
	/* do we have 3 floats? */
	if (PyObject_Length (args) == 3) {
		status = PyArg_ParseTuple (args, "fff", &rot1, &rot2, &rot3);
 	}
	else{ 	//test to see if it's a list or a euler
		if ( PyArg_ParseTuple (args, "O", &ob)){
			if(EulerObject_Check(ob)){
				rot1 = ((EulerObject*)ob)->eul[0];
				rot2 = ((EulerObject*)ob)->eul[1];
				rot3 = ((EulerObject*)ob)->eul[2];
				status = 1; /* success! */
			}
			else if(PySequence_Check(ob ))
				status = PyArg_ParseTuple (args, "(fff)", 
							   &rot1, &rot2, &rot3);
			else{  /* not an euler or tuple */

				/* python C api doc says don't decref this */
				/*Py_DECREF (ob); */
				
				status = 0; /* false */
			}
		}
		else{  /* arg parsing failed */
			status = 0;
		}
	}
		
	if( !status) /* parsing args failed */
		return (  EXPP_ReturnPyObjError( PyExc_AttributeError,
						 "expected euler or list/tuple of 3 floats "));

	self->object->rot[0] = rot1;
	self->object->rot[1] = rot2;
	self->object->rot[2] = rot3;

	Py_INCREF (Py_None);
	return (Py_None);
}


static PyObject *Object_setMatrix (BPy_Object *self, PyObject *args)
{
	MatrixObject* mat;
	int x,y;

	if (!PyArg_ParseTuple(args, "O!", &matrix_Type, &mat))
		return EXPP_ReturnPyObjError 
		   (PyExc_TypeError, "expected matrix object as argument");

	for(x = 0; x < 4; x++){
		for(y = 0; y < 4; y++){
			self->object->obmat[x][y] = mat->matrix[x][y];
		}
	}
	apply_obmat(self->object);

  	Py_INCREF (Py_None);
	return (Py_None);
}


static PyObject *Object_setIpo(BPy_Object *self, PyObject *args)
{
	PyObject *pyipo = 0;
	Ipo *ipo = NULL;
	Ipo *oldipo;

	if (!PyArg_ParseTuple(args, "O!", &Ipo_Type, &pyipo))
		return EXPP_ReturnPyObjError (PyExc_TypeError, "expected Ipo as argument");

	ipo = Ipo_FromPyObject(pyipo);

	if (!ipo) return EXPP_ReturnPyObjError (PyExc_RuntimeError, "null ipo!");

	if (ipo->blocktype != ID_OB)
		return EXPP_ReturnPyObjError (PyExc_TypeError,
			"this ipo is not an object ipo");

	oldipo = self->object->ipo;
	if (oldipo) {
		ID *id = &oldipo->id;
		if (id->us > 0) id->us--;
	}

	((ID *)&ipo->id)->us++;

	self->object->ipo = ipo;

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *Object_setLocation (BPy_Object *self, PyObject *args)
{
	float	loc1;
	float	loc2;
	float	loc3;
	int		status;

	if (PyObject_Length (args) == 3)
		status = PyArg_ParseTuple (args, "fff", &loc1, &loc2, &loc3);
	else
		status = PyArg_ParseTuple (args, "(fff)", &loc1, &loc2, &loc3);

	if (!status)
		return EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected list argument of 3 floats");

	self->object->loc[0] = loc1;
	self->object->loc[1] = loc2;
	self->object->loc[2] = loc3;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setMaterials (BPy_Object *self, PyObject *args)
{
	PyObject	 * list;
	int			   len;
	int			   i;
	Material	** matlist;

	if (!PyArg_ParseTuple (args, "O", &list))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected a list of materials as argument"));
	}

	len = PySequence_Length (list);
	if (len > 0)
	{
		matlist = EXPP_newMaterialList_fromPyList (list);
		if (!matlist)
		{
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"material list must be a list of valid materials!"));
		}
		if ((len < 0) || (len > MAXMAT))
		{
			return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
				"material list should have at least 1, at most 16 entries"));
		}

		if (self->object->mat)
		{
			EXPP_releaseMaterialList (self->object->mat, self->object->totcol);
		}
		/* Increase the user count on all materials */
		for (i=0 ; i<len ; i++)
		{
			if (matlist[i]) id_us_plus ((ID *) matlist[i]);
		}
		self->object->mat = matlist;
		self->object->totcol = len;
		self->object->actcol = len;

		switch (self->object->type)
		{
			case OB_CURVE:	/* fall through */
			case OB_FONT:	/* fall through */
			case OB_MESH:	/* fall through */
			case OB_MBALL:	/* fall through */
			case OB_SURF:
				EXPP_synchronizeMaterialLists (self->object);
				break;
			default:
				break;
		}
	}
	return EXPP_incr_ret (Py_None);
}

static PyObject *Object_setName (BPy_Object *self, PyObject *args)
{
	char  * name;
	char	buf[21];

	if (!PyArg_ParseTuple (args, "s", &name))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected a String as argument"));
	}

	PyOS_snprintf(buf, sizeof(buf), "%s", name);

	rename_id(&self->object->id, buf);

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setSize (BPy_Object *self, PyObject *args)
{
	float	sizex;
	float	sizey;
	float	sizez;
	int		status;

	if (PyObject_Length (args) == 3)
		status = PyArg_ParseTuple (args, "fff", &sizex, &sizey, &sizez);
	else
		status = PyArg_ParseTuple (args, "(fff)", &sizex, &sizey, &sizez);

	if (!status)
		return EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected list argument of 3 floats");

	self->object->size[0] = sizex;
	self->object->size[1] = sizey;
	self->object->size[2] = sizez;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_setTimeOffset (BPy_Object *self, PyObject *args)
{
	float newTimeOffset;

	if (!PyArg_ParseTuple (args, "f", &newTimeOffset))
	{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,
				"expected a float as argument"));
	}

	self->object->sf=newTimeOffset;

	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_makeTrack (BPy_Object *self, PyObject *args)
{
  BPy_Object *tracked = NULL;
	Object *ob = self->object;
	int fast = 0;
	
	if (!PyArg_ParseTuple (args, "O!|i", &Object_Type, &tracked, &fast))
		return EXPP_ReturnPyObjError (PyExc_TypeError,
			"expected an object and optionally also an int as arguments.");

	ob->track = tracked->object;

	if (!fast) sort_baselist(G.scene);

	return EXPP_incr_ret(Py_None);
}

static PyObject *Object_shareFrom (BPy_Object *self, PyObject *args)
{
	BPy_Object		* object;
	ID				* id;
	ID				* oldid;

	if (!PyArg_ParseTuple (args, "O", &object))
	{
		return EXPP_ReturnPyObjError (PyExc_TypeError,
				"expected an object argument");
	}
	if (!Object_CheckPyObject ((PyObject*)object))
	{
		return EXPP_ReturnPyObjError (PyExc_TypeError,
				"first argument is not of type 'Object'");
	}

	if (self->object->type != object->object->type)
	{
		return EXPP_ReturnPyObjError (PyExc_TypeError,
				"objects are not of same data type");
	}
	switch (self->object->type)
	{
		case OB_MESH:
		case OB_LAMP:
		case OB_CAMERA: /* we can probably add the other types, too */
		case OB_ARMATURE:
		case OB_CURVE:
		case OB_SURF:
		case OB_LATTICE:
			oldid = (ID*) self->object->data;
			id = (ID*) object->object->data;
			self->object->data = object->object->data;

			if ( self->object->type == OB_MESH && id ){
				self->object->totcol = 0;
				EXPP_synchronizeMaterialLists(self->object);
			}

			id_us_plus (id);
			if (oldid)
			{
				if (oldid->us > 0)
				{
					oldid->us--;
				}
				else
				{
					return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
							"old object reference count below 0"));
				}
			}
			Py_INCREF (Py_None);
			return (Py_None);
		default:
			return EXPP_ReturnPyObjError (PyExc_TypeError,
					"type not supported");
	}

	Py_INCREF (Py_None);
	return (Py_None);
}



static PyObject *Object_Select (BPy_Object *self, PyObject *args)
{
	Base *base;
	int sel;
  
	base= FIRSTBASE;
	if (!PyArg_ParseTuple (args, "i", &sel))
		return EXPP_ReturnPyObjError 
			(PyExc_TypeError, "expected an integer, 0 or 1");
    
	while (base) {
		if (base->object == self->object){
			if (sel == 1){
				base->flag |= SELECT;
				self->object->flag= base->flag;
				set_active_base( base );
			} else { 
				base->flag &= ~SELECT;
				self->object->flag= base->flag;
			}
			break;
		}
		base= base->next;
	}
  
	countall();  
  
	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *Object_getAllProperties(BPy_Object *self)
{
	PyObject *prop_list;
	bProperty *prop= NULL;

	prop_list = PyList_New(0);

	prop = self->object->prop.first;
	while(prop){
		PyList_Append(prop_list, Property_CreatePyObject(prop));
		prop = prop->next;
	}
	return prop_list;
}

static PyObject *Object_getProperty(BPy_Object *self, PyObject *args)
{
	char *prop_name = NULL;
	bProperty *prop= NULL;
	PyObject *py_prop = Py_None;

	if(!PyArg_ParseTuple (args, "s", &prop_name)){
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
			"expected a string"));
	}

	prop = get_property(self->object, prop_name);
	if(prop){
		py_prop = Property_CreatePyObject(prop);
	}else{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
			"couldn't find the property...."));
	}
	return py_prop;
}

static PyObject *Object_addProperty(BPy_Object *self, PyObject *args)
{
	bProperty *prop = NULL;
	char *prop_name = NULL;
	PyObject *prop_data = Py_None;
	char *prop_type = NULL;
	short type = -1;
	BPy_Property *py_prop = NULL;

	if (PyObject_Length (args) == 3 || PyObject_Length (args) == 2){
		if (!PyArg_ParseTuple (args, "sO|s", &prop_name, &prop_data, &prop_type)){
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
				"unable to get string, data, and optional string"));
		}
	}else if (PyObject_Length (args) == 1){
		if (!PyArg_ParseTuple (args, "O!", &property_Type, &py_prop)){
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
				"unable to get Property"));
		}
		if(py_prop->property != NULL){
				return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
					"Property is already added to an object"));
		}
	}else{
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
						"expected 1,2 or 3 arguments"));
	}

	//parse property type
	if(!py_prop){
		if(prop_type){
			if(BLI_streq(prop_type, "BOOL"))                type = PROP_BOOL;
			else if (BLI_streq(prop_type, "INT"))           type = PROP_INT;
			else if (BLI_streq(prop_type, "FLOAT"))     type = PROP_FLOAT;
			else if (BLI_streq(prop_type, "TIME"))        type = PROP_TIME;
			else if (BLI_streq(prop_type, "STRING"))  type = PROP_STRING;
			else return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
					"BOOL, INT, FLOAT, TIME or STRING expected"));
		}else{
			//use the default
			if(PyInt_Check(prop_data))                 type = PROP_INT;
			else if (PyFloat_Check(prop_data))    type = PROP_FLOAT;
			else if (PyString_Check(prop_data))  type = PROP_STRING;
		}
	}else{
		type = py_prop->type;
	}

	//initialize a new bProperty of the specified type
	prop = new_property(type);

	//parse data
	if(!py_prop){
		BLI_strncpy(prop->name, prop_name, 32);
		if(PyInt_Check(prop_data)){
			*((int*)&prop->data) = (int)PyInt_AsLong(prop_data);
		}else if (PyFloat_Check(prop_data)){
			*((float *)&prop->data) = (float)PyFloat_AsDouble(prop_data);
		}else if (PyString_Check(prop_data)){
			BLI_strncpy(prop->poin, PyString_AsString(prop_data), MAX_PROPSTRING);
		}
	}else{
		py_prop->property = prop;
		if(!updateProperyData(py_prop)){
			return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
					"Could not update property data - error"));
		}
	}

	//add to property listbase for the object
	BLI_addtail(&self->object->prop, prop);

	return EXPP_incr_ret  (Py_None);
}

static PyObject *Object_removeProperty(BPy_Object *self, PyObject *args)
{
	char *prop_name = NULL;
	BPy_Property *py_prop = NULL;
	bProperty *prop = NULL;

	// we have property and no optional arg
	if (!PyArg_ParseTuple (args, "O!", &property_Type, &py_prop)){
		if(!PyArg_ParseTuple (args, "s", &prop_name)){
			return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
				"expected a Property or a string"));
		}
	}

	//remove the link, free the data, and update the py struct
	if(py_prop){
		BLI_remlink(&self->object->prop, py_prop->property);
		if(updatePyProperty(py_prop)){
			free_property(py_prop->property);
			py_prop->property = NULL;
		}
	}else{
		prop = get_property(self->object, prop_name);
		if(prop){
			BLI_remlink(&self->object->prop, prop);
			free_property(prop);
		}
	}
	return EXPP_incr_ret  (Py_None);
}

static PyObject *Object_removeAllProperties(BPy_Object *self)
{
	free_properties(&self->object->prop);
	return EXPP_incr_ret  (Py_None);
}

static PyObject *Object_copyAllPropertiesTo(BPy_Object *self, PyObject *args)
{
	PyObject *dest = Py_None;
	bProperty *prop = NULL;
	bProperty *propn = NULL;

	if (!PyArg_ParseTuple (args, "O!", &Object_Type, &dest)){
		return (EXPP_ReturnPyObjError (PyExc_AttributeError,	
			"expected an Object"));
	}

	//make a copy of all it's properties
	prop = self->object->prop.first;
	while(prop) {
		propn= copy_property(prop);
		BLI_addtail(&((BPy_Object*)dest)->object->prop, propn);
		prop= prop->next;
	}

	return EXPP_incr_ret  (Py_None);
}

/* obj.addScriptLink */
static PyObject *Object_addScriptLink (BPy_Object *self, PyObject *args)
{
	Object *obj = self->object;
	ScriptLink *slink = NULL;

	slink = &(obj)->scriptlink;

	if (!EXPP_addScriptLink(slink, args, 0))
		return EXPP_incr_ret (Py_None);
	else return NULL;
}

/* obj.clearScriptLinks */
static PyObject *Object_clearScriptLinks (BPy_Object *self)
{
	Object *obj = self->object;
	ScriptLink *slink = NULL;

	slink = &(obj)->scriptlink;

	return EXPP_incr_ret(Py_BuildValue("i", EXPP_clearScriptLinks (slink)));
}

/* obj.getScriptLinks */
static PyObject *Object_getScriptLinks (BPy_Object *self, PyObject *args)
{
	Object *obj = self->object;
	ScriptLink *slink = NULL;
	PyObject *ret = NULL;

	slink = &(obj)->scriptlink;

	ret = EXPP_getScriptLinks(slink, args, 0);

	if (ret) return ret;
	else return NULL;
}

/*****************************************************************************/
/* Function:	Object_CreatePyObject										 */
/* Description: This function will create a new BlenObject from an existing  */
/*				Object structure.											 */
/*****************************************************************************/
PyObject* Object_CreatePyObject (struct Object *obj)
{
	BPy_Object	  * blen_object;

	if (!obj) return EXPP_incr_ret (Py_None);

	blen_object = (BPy_Object*)PyObject_NEW (BPy_Object, &Object_Type);

	if (blen_object == NULL)
	{
		return (NULL);
	}
	blen_object->object = obj;
	return ((PyObject*)blen_object);
}

/*****************************************************************************/
/* Function:	Object_CheckPyObject										 */
/* Description: This function returns true when the given PyObject is of the */
/*				type Object. Otherwise it will return false.				 */
/*****************************************************************************/
int Object_CheckPyObject (PyObject *py_obj)
{
	return (py_obj->ob_type == &Object_Type);
}

/*****************************************************************************/
/* Function:	Object_FromPyObject											 */
/* Description: This function returns the Blender object from the given		 */
/*				PyObject.													 */
/*****************************************************************************/
struct Object* Object_FromPyObject (PyObject *py_obj)
{
	BPy_Object	  * blen_obj;

	blen_obj = (BPy_Object*)py_obj;
	return (blen_obj->object);
}

/*****************************************************************************/
/* Description: Returns the object with the name specified by the argument	 */
/*				name. Note that the calling function has to remove the first */
/*				two characters of the object name. These two characters		 */
/*				specify the type of the object (OB, ME, WO, ...)			 */
/*				The function will return NULL when no object with the given  */
/*				name is found.												 */
/*****************************************************************************/
Object * GetObjectByName (char * name)
{
  Object  * obj_iter;

  obj_iter = G.main->object.first;
  while (obj_iter)
  {
	if (StringEqual (name, GetIdName (&(obj_iter->id))))
	{
	  return (obj_iter);
	}
	obj_iter = obj_iter->id.next;
  }

  /* There is no object with the given name */
  return (NULL);
}

/*****************************************************************************/
/* Function:	Object_dealloc												 */
/* Description: This is a callback function for the BlenObject type. It is	 */
/*				the destructor function.									 */
/*****************************************************************************/
static void Object_dealloc (BPy_Object *obj)
{
	PyObject_DEL (obj);
}

/*****************************************************************************/
/* Function:	Object_getAttr												 */
/* Description: This is a callback function for the BlenObject type. It is	 */
/*				the function that retrieves any value from Blender and		 */
/*				passes it to Python.										 */
/*****************************************************************************/
static PyObject* Object_getAttr (BPy_Object *obj, char *name)
{
	struct Object	* object;
	struct Ika		* ika;

	object = obj->object;
	if (StringEqual (name, "LocX"))
		return (PyFloat_FromDouble(object->loc[0]));
	if (StringEqual (name, "LocY"))
		return (PyFloat_FromDouble(object->loc[1]));
	if (StringEqual (name, "LocZ"))
		return (PyFloat_FromDouble(object->loc[2]));
	if (StringEqual (name, "loc"))
		return (Py_BuildValue ("fff", object->loc[0], object->loc[1],
							   object->loc[2]));
	if (StringEqual (name, "dLocX"))
		return (PyFloat_FromDouble(object->dloc[0]));
	if (StringEqual (name, "dLocY"))
		return (PyFloat_FromDouble(object->dloc[1]));
	if (StringEqual (name, "dLocZ"))
		return (PyFloat_FromDouble(object->dloc[2]));
	if (StringEqual (name, "dloc"))
		return (Py_BuildValue ("fff", object->dloc[0], object->dloc[1],
							   object->dloc[2]));
	if (StringEqual (name, "RotX"))
		return (PyFloat_FromDouble(object->rot[0]));
	if (StringEqual (name, "RotY"))
		return (PyFloat_FromDouble(object->rot[1]));
	if (StringEqual (name, "RotZ"))
		return (PyFloat_FromDouble(object->rot[2]));
	if (StringEqual (name, "rot"))
		return (Py_BuildValue ("fff", object->rot[0], object->rot[1],
							   object->rot[2]));
	if (StringEqual (name, "dRotX"))
		return (PyFloat_FromDouble(object->drot[0]));
	if (StringEqual (name, "dRotY"))
		return (PyFloat_FromDouble(object->drot[1]));
	if (StringEqual (name, "dRotZ"))
		return (PyFloat_FromDouble(object->drot[2]));
	if (StringEqual (name, "drot"))
		return (Py_BuildValue ("fff", object->drot[0], object->drot[1],
							   object->drot[2]));
	if (StringEqual (name, "SizeX"))
		return (PyFloat_FromDouble(object->size[0]));
	if (StringEqual (name, "SizeY"))
		return (PyFloat_FromDouble(object->size[1]));
	if (StringEqual (name, "SizeZ"))
		return (PyFloat_FromDouble(object->size[2]));
	if (StringEqual (name, "size"))
		return (Py_BuildValue ("fff", object->size[0], object->size[1],
							   object->size[2]));
	if (StringEqual (name, "dSizeX"))
		return (PyFloat_FromDouble(object->dsize[0]));
	if (StringEqual (name, "dSizeY"))
		return (PyFloat_FromDouble(object->dsize[1]));
	if (StringEqual (name, "dSizeZ"))
		return (PyFloat_FromDouble(object->dsize[2]));
	if (StringEqual (name, "dsize"))
		return (Py_BuildValue ("fff", object->dsize[0], object->dsize[1],
							   object->dsize[2]));
	if (strncmp (name,"Eff", 3) == 0)
	{
		if ( (object->type == OB_IKA) && (object->data != NULL) )
		{
			ika = object->data;
			switch (name[3])
			{
				case 'X':
					return (PyFloat_FromDouble (ika->effg[0]));
				case 'Y':
					return (PyFloat_FromDouble (ika->effg[1]));
				case 'Z':
					return (PyFloat_FromDouble (ika->effg[2]));
				default:
				/* Do we need to display a sensible error message here? */
					return (NULL);
			}
		}
		return (NULL);
	}
	if (StringEqual (name, "Layer"))
	  return (PyInt_FromLong(object->lay));
	if (StringEqual (name, "parent"))
	{
		if (object->parent)
			return (Object_CreatePyObject (object->parent));
		else 
	{
	  Py_INCREF (Py_None);
	  return (Py_None);
	}
	}

	if (StringEqual (name, "track"))
	  return (Object_CreatePyObject (object->track));
	if (StringEqual (name, "data"))
	  return (Object_getData (obj));
	if (StringEqual (name, "ipo"))
	{
		if (object->ipo == NULL)
		{
			/* There's no ipo linked to the object, return Py_None. */
			Py_INCREF (Py_None);
			return (Py_None);
		}
		return (Ipo_CreatePyObject (object->ipo));
	}
	if (StringEqual (name, "mat") || StringEqual (name, "matrix"))
		return (Object_getMatrix (obj, Py_BuildValue("(s)","localspace")));
	if (StringEqual (name, "matrixWorld"))
		return (Object_getMatrix (obj, Py_BuildValue("(s)","worldspace")));
	if (StringEqual (name, "matrixLocal"))
		return (Object_getMatrix (obj, Py_BuildValue("(s)","localspace")));
	if (StringEqual (name, "colbits"))
		return (Py_BuildValue ("h", object->colbits));
	if (StringEqual (name, "drawType"))
		return (Py_BuildValue ("b", object->dt));
	if (StringEqual (name, "drawMode"))
		return (Py_BuildValue ("b", object->dtx));
	if (StringEqual (name, "name"))
		return (Py_BuildValue ("s", object->id.name+2));
	if (StringEqual (name, "sel"))
		return (Object_isSelected (obj));
  
	/* not an attribute, search the methods table */
	return Py_FindMethod(BPy_Object_methods, (PyObject *)obj, name);
}

/*****************************************************************************/
/* Function:	Object_setAttr												 */
/* Description: This is a callback function for the BlenObject type. It is	 */
/*				the function that retrieves any value from Python and sets	 */
/*				it accordingly in Blender.									 */
/*****************************************************************************/
static int Object_setAttr (BPy_Object *obj, char *name, PyObject *value)
{
	PyObject		* valtuple;
	struct Object	* object;
	struct Ika		* ika;

	/* First put the value(s) in a tuple. For some variables, we want to */
	/* pass the values to a function, and these functions only accept */
	/* PyTuples. */
	valtuple = Py_BuildValue ("(O)", value);
	if (!valtuple)
	{
		return EXPP_ReturnIntError(PyExc_MemoryError,
						 "Object_setAttr: couldn't create PyTuple");
	}

	object = obj->object;
	if (StringEqual (name, "LocX"))
		return (!PyArg_Parse (value, "f", &(object->loc[0])));
	if (StringEqual (name, "LocY"))
		return (!PyArg_Parse (value, "f", &(object->loc[1])));
	if (StringEqual (name, "LocZ"))
		return (!PyArg_Parse (value, "f", &(object->loc[2])));
	if (StringEqual (name, "loc"))
	{
		if (Object_setLocation (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "dLocX"))
		return (!PyArg_Parse (value, "f", &(object->dloc[0])));
	if (StringEqual (name, "dLocY"))
		return (!PyArg_Parse (value, "f", &(object->dloc[1])));
	if (StringEqual (name, "dLocZ"))
		return (!PyArg_Parse (value, "f", &(object->dloc[2])));
	if (StringEqual (name, "dloc"))
	{
		if (Object_setDeltaLocation (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "RotX"))
		return (!PyArg_Parse (value, "f", &(object->rot[0])));
	if (StringEqual (name, "RotY"))
		return (!PyArg_Parse (value, "f", &(object->rot[1])));
	if (StringEqual (name, "RotZ"))
		return (!PyArg_Parse (value, "f", &(object->rot[2])));
	if (StringEqual (name, "rot"))
	{
		if (Object_setEuler (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "dRotX"))
		return (!PyArg_Parse (value, "f", &(object->drot[0])));
	if (StringEqual (name, "dRotY"))
		return (!PyArg_Parse (value, "f", &(object->drot[1])));
	if (StringEqual (name, "dRotZ"))
		return (!PyArg_Parse (value, "f", &(object->drot[2])));
	if (StringEqual (name, "drot"))
		return (!PyArg_ParseTuple (value, "fff", &(object->drot[0]),
							  &(object->drot[1]), &(object->drot[2])));
	if (StringEqual (name, "SizeX"))
		return (!PyArg_Parse (value, "f", &(object->size[0])));
	if (StringEqual (name, "SizeY"))
		return (!PyArg_Parse (value, "f", &(object->size[1])));
	if (StringEqual (name, "SizeZ"))
		return (!PyArg_Parse (value, "f", &(object->size[2])));
	if (StringEqual (name, "size"))
		return (!PyArg_ParseTuple  (value, "fff", &(object->size[0]),
							  &(object->size[1]), &(object->size[2])));
	if (StringEqual (name, "dSizeX"))
		return (!PyArg_Parse (value, "f", &(object->dsize[0])));
	if (StringEqual (name, "dSizeY"))
		return (!PyArg_Parse (value, "f", &(object->dsize[1])));
	if (StringEqual (name, "dSizeZ"))
		return (!PyArg_Parse (value, "f", &(object->dsize[2])));
	if (StringEqual (name, "dsize"))
		return (!PyArg_ParseTuple  (value, "fff", &(object->dsize[0]),
							  &(object->dsize[1]), &(object->dsize[2])));
	if (strncmp (name,"Eff", 3) == 0)
	{
		if ( (object->type == OB_IKA) && (object->data != NULL) )
		{
			ika = object->data;
			switch (name[3])
			{
				case 'X':
					return (!PyArg_Parse (value, "f", &(ika->effg[0])));
				case 'Y':
					return (!PyArg_Parse (value, "f", &(ika->effg[1])));
				case 'Z':
					return (!PyArg_Parse (value, "f", &(ika->effg[2])));
				default:
					/* Do we need to display a sensible error message here? */
					return (0);
			}
		}
		return (0);
	}
	if (StringEqual (name, "Layer"))
	{
        /*  usage note: caller of this func needs to do a 
	   Blender.Redraw(-1) to update and redraw the interface */

		Base *base;
		int newLayer;
		int local;
		if(PyArg_Parse (value, "i", &newLayer)){
			/* uppper 2 bytes are for local view */
			newLayer &= 0x00FFFFFF;  
			if( newLayer == 0 ) /* bail if nothing to do */
				return( 0 );

			/* update any bases pointing to our object */
			base = FIRSTBASE;
			if( base->object == obj->object ){
				local = base->lay &= 0xFF000000;
				base->lay = local | newLayer;
				object->lay = base->lay;
			}
			countall();
		}
		else{
			return EXPP_ReturnIntError(PyExc_AttributeError,
						   "expected int as bitmask");
		}
			
		return( 0 );
	}
	if (StringEqual (name, "parent"))
	{
		/* This is not allowed. */
		EXPP_ReturnPyObjError (PyExc_AttributeError,
					"Setting the parent is not allowed.");
		return (0);
	}
	if (StringEqual (name, "track"))
	{
		if (Object_makeTrack (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "data"))
	{
		/* This is not allowed. */
		EXPP_ReturnPyObjError (PyExc_AttributeError,
					"Setting the data is not allowed.");
		return (0);
	}
	if (StringEqual (name, "ipo"))
	{
		/* This is not allowed. */
		EXPP_ReturnPyObjError (PyExc_AttributeError,
					"Setting the ipo is not allowed.");
		return (0);
	}
	if (StringEqual (name, "mat"))
	{
		/* This is not allowed. */
		EXPP_ReturnPyObjError (PyExc_AttributeError,
					"Setting the matrix is not allowed.");
		return (0);
	}
	if (StringEqual (name, "matrix"))
	{
		/* This is not allowed. */
		EXPP_ReturnPyObjError (PyExc_AttributeError,
					"Please use .setMatrix(matrix)");
		return (0);
	}
	if (StringEqual (name, "colbits"))
		return (!PyArg_Parse (value, "h", &(object->colbits)));
	if (StringEqual (name, "drawType"))
	{
		if (Object_setDrawType (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "drawMode"))
	{
		if (Object_setDrawMode (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
	if (StringEqual (name, "name"))
	{
		if (Object_setName (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
  
	if (StringEqual (name, "sel"))
	{
		if (Object_Select (obj, valtuple) != Py_None)
			return (-1);
		else
			return (0);
	}
  
	printf ("Unknown variable.\n");
	return (0);
}

/*****************************************************************************/
/* Function:	Object_compare												 */
/* Description: This is a callback function for the BPy_Object type. It		 */
/*				compares two Object_Type objects. Only the "==" and "!="	 */
/*				comparisons are meaninful. Returns 0 for equality and -1 if  */
/*				they don't point to the same Blender Object struct.			 */
/*				In Python it becomes 1 if they are equal, 0 otherwise.		 */
/*****************************************************************************/
static int Object_compare (BPy_Object *a, BPy_Object *b)
{
  Object *pa = a->object, *pb = b->object;
  return (pa == pb) ? 0:-1;
}

/*****************************************************************************/
/* Function:	Object_repr													 */
/* Description: This is a callback function for the BPy_Object type. It		 */
/*				builds a meaninful string to represent object objects.		 */
/*****************************************************************************/
static PyObject *Object_repr (BPy_Object *self)
{
  return PyString_FromFormat("[Object \"%s\"]", self->object->id.name+2);
}
