/** Ipo module; access to Ipo datablocks in Blender
  * $Id: BPY_ipo.c,v 1.3 2002/11/25 12:01:57 mein Exp $
 *
 * ***** 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 Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
  *
  */
#include "MEM_guardedalloc.h"

#include "Python.h"
#include "BPY_macros.h"
#include "BPY_tools.h"

#include "b_interface.h" // most datatypes

#include "opy_datablock.h"

#include "DNA_curve_types.h"

#include "BSE_editipo.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* GLOBALS */

/* These should be put into a proper dictionary for quicker retrieval..*/

NamedEnum g_OB_ipocodes[] = {

	{ "LocX",   OB_LOC_X },
	{ "LocY",   OB_LOC_Y },
	{ "LocZ",   OB_LOC_Z },
	{ "dLocX",  OB_DLOC_X },
	{ "dLocY",  OB_DLOC_Y },
	{ "dLocZ",  OB_DLOC_Z },
	{ "RotX",   OB_ROT_X },
	{ "RotY",   OB_ROT_Y },
	{ "RotZ",   OB_ROT_Z },
	{ "dRotX",  OB_DROT_X },
	{ "dRotY",  OB_DROT_Y },
	{ "dRotZ",  OB_DROT_Z },
	{ "SizeX",  OB_SIZE_X },
	{ "SizeY",  OB_SIZE_Y },
	{ "SizeY",  OB_SIZE_Z },
	{ "dSizeX", OB_DSIZE_X },
	{ "dSizeY", OB_DSIZE_Y },
	{ "dSizeY", OB_DSIZE_Z },
	{ "Layer",  OB_LAY },
	{ "Time",   OB_TIME },
	{ 0, 0 }
};

NamedEnum g_MA_ipocodes[] = {

	{ "R",      MA_COL_R },
	{ "G",      MA_COL_G },
	{ "B",      MA_COL_B },
	{ "Alpha",  MA_ALPHA},
	{ "SpecR",  MA_SPEC_R },
	{ "SpecG",  MA_SPEC_G },
	{ "SpecB",  MA_SPEC_B },
	{ "MirR",   MA_MIR_R },
	{ "MirG",   MA_MIR_G },
	{ "MirB",   MA_MIR_B },
	{ "Emit",   MA_EMIT },
	{ "Amb",    MA_AMB },
	{ "Spec",   MA_SPEC },
	{ "Hard",   MA_HARD },
	{ "SpTra",  MA_SPTR },
	{ "Ang",    MA_ANG },
	{ "HaSize", MA_HASIZE },
	{ 0, 0 }
};

NamedEnum g_WO_ipocodes[] = {
	{ "HorR",   WO_HOR_R },
	{ "HorG",   WO_HOR_G },
	{ "HorB",   WO_HOR_B },
	{ "ZenR",   WO_ZEN_R },
	{ "ZenG",   WO_ZEN_G },
	{ "ZenB",   WO_ZEN_B },
	{ "Expos",  WO_EXPOS },
	{ "Misi",   WO_MISI },
	{ "MisDi",  WO_MISTDI },
	{ "MisSta", WO_MISTSTA },
	{ "MisHi",  WO_MISTHI },
	{ "StarR",  WO_STAR_R },
	{ "StarG",  WO_STAR_G },
	{ "StarB",  WO_STAR_B },
	{ "StarDi", WO_STARDIST },
	{ "StarSi", WO_STARSIZE },
	{ 0, 0 }
};

NamedEnum g_CA_ipocodes[] = {
	{ "Lens",  CAM_LENS },
	{ "ClSta", CAM_STA },
	{ "ClEnd", CAM_END },
	{ 0, 0 }
};

PyObject *g_ipoBlockTypes;           // global for ipo type container
PyObject *g_interpolationTypes; // global for interpolation type container
PyObject *g_extrapolationTypes; // global for extrapolation type container

typedef struct _PyBezTriple {
	PyObject_VAR_HEAD
	
	BezTriple bzt;
} PyBezTriple;


void pybzt_dealloc(PyObject *self) {
	PyMem_DEL(self);
}

PyObject *pybzt_repr(PyObject *self) {
	return PyString_FromString("[BezTriple]");
}

/* XXX */

NamedEnum bez_triple_flags[]= {
	{"Free", HD_FREE},
	{"Auto", HD_AUTO},
	{"Vect", HD_VECT},
	{"Align", HD_ALIGN},
	{NULL}
};

DataBlockProperty BezTriple_Properties[]= {
	{"h1", 	"vec[3][3]", 	DBP_TYPE_VEC, 0, 2.0, 0.0, {0,0}, {3,3,-sizeof(float)}}, 
	{"pt", 	"vec[3][3]", 	DBP_TYPE_VEC, 0, 2.0, 0.0, {1,0}, {3,3,-sizeof(float)}}, 
	{"h2", 	"vec[3][3]", 	DBP_TYPE_VEC, 0, 2.0, 0.0, {2,0}, {3,3,-sizeof(float)}}, 
	
	{"f1", 	"f1", 			DBP_TYPE_CHA, 0, 0.0, 1.0},
	{"f2", 	"f2", 			DBP_TYPE_CHA, 0, 0.0, 1.0},
	{"f3", 	"f3", 			DBP_TYPE_CHA, 0, 0.0, 1.0},

	{"h1Type", "h1", 		DBP_TYPE_SHO, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_NENM, bez_triple_flags},
	{"h2Type", "h2", 		DBP_TYPE_SHO, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_NENM, bez_triple_flags},

	{"h1t", "h1", 			DBP_TYPE_SHO, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_NENM, bez_triple_flags},
	{"h2t", "h2", 			DBP_TYPE_SHO, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_NENM, bez_triple_flags},
	
	{NULL}
};

PyObject *pybzt_getattr(PyObject *self, char *name) {
	PyBezTriple *pybzt= (PyBezTriple *) self;

	return datablock_getattr(BezTriple_Properties, "BezTriple", name, &pybzt->bzt);
}

int pybzt_setattr(PyObject *self, char *name, PyObject *ob) {
	PyBezTriple *pybzt= (PyBezTriple *) self;

	return datablock_setattr(BezTriple_Properties, "BezTriple", name, &pybzt->bzt, ob);
}

PyTypeObject PyBezTriple_Type = {
	PyObject_HEAD_INIT(NULL)
	0,								/*ob_size*/
	"BezTriple",					/*tp_name*/
	sizeof(PyBezTriple),			/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)	pybzt_dealloc,	/*tp_dealloc*/
	(printfunc)		0,	/*tp_print*/
	(getattrfunc)	pybzt_getattr,	/*tp_getattr*/
	(setattrfunc)	pybzt_setattr,	/*tp_setattr*/
	0,								/*tp_compare*/
	(reprfunc) pybzt_repr,								/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	0,								/*tp_hash*/	
};

static char pybzt_create_doc[]= "() - Create a new BezTriple object";
PyObject *pybzt_create(PyObject *self, PyObject *args) {
	PyBezTriple *py_bzt= PyObject_NEW(PyBezTriple, &PyBezTriple_Type);
	// BezTriple *bzt= &py_bzt->bzt;
	
	BPY_TRY(PyArg_ParseTuple(args, ""));
	
	memset(&py_bzt->bzt,0,sizeof(py_bzt->bzt));
	
	return (PyObject *) py_bzt;
}

PyObject *pybzt_from_bzt(BezTriple *bzt) {
	PyBezTriple *py_bzt= PyObject_NEW(PyBezTriple, &PyBezTriple_Type);
	
	memcpy(&py_bzt->bzt, bzt, sizeof(*bzt));
	
	return (PyObject *) py_bzt;
}


typedef struct _PyIpoCurve {
	PyObject_VAR_HEAD

	IpoCurve *icu;
} PyIpoCurve;


/********************/
/* IpoCurve methods */

#undef MethodDef
#define MethodDef(func) _MethodDef(func, IpoCurve)

#define DICT_FROM_CONSTDICT(x) \
	((constobject *) x)->dict

/** sets an enum int value 'by name' from the dictionary dict */

static PyObject *setEnum_fromDict(short *i, PyObject *dict, char *key, char *errmsg)
{
	PyObject *p;
	p = PyDict_GetItemString(dict, key);
	if (!p) {
		PyErr_SetString(PyExc_TypeError, errmsg);
		return NULL;
	}

	*i = (short) PyInt_AsLong(p);
	return BPY_incr_ret(Py_None);
}

static char IpoCurve_setInterpolation_doc[] = 
"(type) - Set interpolation to one of: ['Constant', 'Linear', 'Bezier']";

static PyObject *IpoCurve_setInterpolation(PyObject *self, PyObject *args)
{
	char *typename;
	IpoCurve *ipocurve = (IpoCurve *) ((PyIpoCurve *) self)->icu;

	BPY_TRY(PyArg_ParseTuple(args, "s", &typename));

	return setEnum_fromDict(&ipocurve->ipo, DICT_FROM_CONSTDICT(g_interpolationTypes),
		typename, "Improper interpolation type, see Ipo.InterpolationTypes");

}

static char IpoCurve_setExtrapolation_doc[] = 
"(type) - Set interpolation to one of: ['Constant', 'Linear', 'Cyclic', 'CyclicLinear']";

static PyObject *IpoCurve_setExtrapolation(PyObject *self, PyObject *args)
{
	char *typename;
	IpoCurve *ipocurve = (IpoCurve *) ((PyIpoCurve *) self)->icu;

	BPY_TRY(PyArg_ParseTuple(args, "s", &typename));


	return setEnum_fromDict(&ipocurve->extrap, DICT_FROM_CONSTDICT(g_extrapolationTypes), 
		typename, "Improper extrapolation type, see Ipo.ExtrapolationTypes");
}

static char IpoCurve_getInterpolation_doc[] = 
"() - Returns interpolation type";

static PyObject *IpoCurve_getInterpolation(PyObject *self, PyObject *args)
{
	IpoCurve *ipocurve = (IpoCurve *) ((PyIpoCurve *) self)->icu;

	switch (ipocurve->ipo) {
	case IPO_CONST:	return PyString_FromString("Constant");
	case IPO_LIN:	return PyString_FromString("Linear");
	case IPO_BEZ:	return PyString_FromString("Bezier");			
	default:        return PyString_FromString("<not defined>"); 
	}
}

static char IpoCurve_getExtrapolation_doc[] = 
"() - Returns extrapolation type";

static PyObject *IpoCurve_getExtrapolation(PyObject *self, PyObject *args)
{
	IpoCurve *ipocurve = (IpoCurve *) ((PyIpoCurve *) self)->icu;

	switch (ipocurve->extrap) {
	case IPO_HORIZ:	return PyString_FromString("Constant");
	case IPO_DIR:	return PyString_FromString("Linear");
	case IPO_CYCL:	return PyString_FromString("Cyclic");					
	case IPO_CYCLX:	return PyString_FromString("CyclicLinear");					
	default:        return PyString_FromString("<not defined>"); 
	}

}

static char IpoCurve_eval_doc[] = 
"(time = <current frame>) - evaluates ipo at time 'time' and returns result\n\
(float). If 'time' is not specified, the current frame value is taken";

static PyObject *IpoCurve_eval(PyObject *self, PyObject *args)
{
	PyIpoCurve *pIpocurve = (PyIpoCurve *) self;
	float time = CurrentFrame;

	BPY_TRY(PyArg_ParseTuple(args, "|f", &time));
	
	return PyFloat_FromDouble(eval_icu(pIpocurve->icu, time));
}

static char IpoCurve_update_doc[] = 
"() - update and recalculate IpoCurve";

static PyObject *IpoCurve_update(PyObject *self, PyObject *args)
{

	BPY_TRY(PyArg_ParseTuple(args, ""));

	testhandles_ipocurve(((PyIpoCurve *) self)->icu); // recalculate IPO

	Py_INCREF(Py_None);
	return Py_None;
}

static struct PyMethodDef IpoCurve_methods[] = {
	MethodDef(setInterpolation), 
	MethodDef(getInterpolation), 
	MethodDef(setExtrapolation), 
	MethodDef(getExtrapolation), 
	MethodDef(eval), 
	MethodDef(update), 
	{NULL, NULL}
};


PyObject *IpoCurve_getattr(PyObject *self, char *name) {
	PyIpoCurve *py_icu= (PyIpoCurve *) self;
	IpoCurve *icu= py_icu->icu;

	if (STREQ(name, "type")) {
		return IpoCurve_getInterpolation(self, Py_BuildValue(""));
	} else if (STREQ(name, "extend")) {
		return IpoCurve_getExtrapolation(self, Py_BuildValue(""));
	} else if (STREQ(name, "name")) {
		char icu_name[32]= "";
		
		switch (icu->blocktype) {
		case ID_OB:
			getname_ob_ei(icu->adrcode, icu_name, 0);
			break;
		case ID_MA:
			getname_mat_ei(icu->adrcode, icu_name);
			break;
		case ID_WO:
			getname_world_ei(icu->adrcode, icu_name);
			break;
		case ID_SEQ:
			getname_seq_ei(icu->adrcode, icu_name);
			break;
		case ID_CU:
			getname_cu_ei(icu->adrcode, icu_name);
			break;
		case ID_KE:
			getname_key_ei(icu->adrcode, icu_name);
			break;
		case ID_LA:
			getname_la_ei(icu->adrcode, icu_name);
			break;
		case ID_CA:
			getname_cam_ei(icu->adrcode, icu_name);
			break;
		default:
			return PyString_FromString("<unknown>");
		}
		
		return PyString_FromString(icu_name);
	} else if (STREQ(name, "points")) {
		PyObject *list= PyList_New(icu->totvert);
		BezTriple *bzt= icu->bezt;
		int i;
		
		for (i=0; i<icu->totvert; i++) {
			PyList_SetItem(list, i, pybzt_from_bzt(bzt));
			bzt++;
		}
		
		return list;
	} 
	return Py_FindMethod(IpoCurve_methods, (PyObject*)self, name);
}

int IpoCurve_setattr(PyObject *self, char *name, PyObject *ob) {
	PyIpoCurve *py_icu= (PyIpoCurve *) self;
	IpoCurve *icu= py_icu->icu;

	if (STREQ(name, "points")) {
		int i, len;
		BezTriple *bzt;
		
		if (!PySequence_Check(ob) || !BPY_check_sequence_consistency(ob, &PyBezTriple_Type))
			return py_err_ret_int(PyExc_AttributeError, "Expected list of BezTriples");

		len= PySequence_Length(ob);

		if (icu->bezt) // free existing (IF)
			MEM_freeN(icu->bezt);

		icu->totvert= len;
		if (len) icu->bezt= MEM_mallocN(len*sizeof(BezTriple), "beztriples");
		
		bzt= icu->bezt;
		for (i=0; i<len; i++) {
			PyBezTriple *pybzt= (PyBezTriple*) PySequence_GetItem(ob, i);
			
			memcpy(bzt, &pybzt->bzt, sizeof(BezTriple));
			bzt++;
			
			Py_DECREF(pybzt);
		}

		/* Twice for auto handles */
		calchandles_ipocurve(icu);
		calchandles_ipocurve(icu);

		boundbox_ipocurve(icu);
		sort_time_ipocurve(icu);
		
		return 0;
	}

	PyErr_SetString(PyExc_AttributeError, name);
	return -1;	
}

void IpoCurve_dealloc(PyObject *self) {
	PyMem_DEL(self);
}

PyObject *IpoCurve_repr(PyObject *self) {
	char s[256];
	sprintf (s, "[IpoCurve %.32s]", 
	         PyString_AsString(IpoCurve_getattr(self, "name")));
	return Py_BuildValue("s", s);
}

PyTypeObject PyIpoCurve_Type = {
	PyObject_HEAD_INIT(NULL)
	0,								/*ob_size*/
	"IpoCurve",						/*tp_name*/
	sizeof(PyIpoCurve),				/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)	IpoCurve_dealloc,	/*tp_dealloc*/
	(printfunc)		0,	/*tp_print*/
	(getattrfunc)	IpoCurve_getattr,	/*tp_getattr*/
	(setattrfunc)	IpoCurve_setattr,	/*tp_setattr*/
	0,								/*tp_compare*/
	(reprfunc) IpoCurve_repr,		/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	0,								/*tp_hash*/	
};

PyObject *IpoCurve_from_icu(IpoCurve *icu) {
	PyIpoCurve *ob= PyObject_NEW(PyIpoCurve, &PyIpoCurve_Type);
	
	ob->icu= icu;
	
	return (PyObject *) ob;
}

PyObject *make_icu_list (ListBase *curves) {
	ListBase lb= *curves;
	IpoCurve *icu= (IpoCurve *) lb.first;
	PyObject *list= PyList_New(0);
	PyObject *pyipo;
	
	while (icu) {
		pyipo = IpoCurve_from_icu(icu);
		PyList_Append(list, pyipo);
		Py_DECREF(pyipo);
		icu= icu->next;
	}
	
	return list;	
}

DataBlockProperty Ipo_Properties[]= {
	{"curves", "curve", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, make_icu_list}, 
	{NULL}	
};


/**********************/
/* Ipo module methods */

DATABLOCK_GET(Ipomodule, ipo, getIpoList())

static char Ipomodule_New_doc[] = 
"(type, name = <default>) - Creates a new Ipo block of the specified type,\n\
which must be of the appropriate datablock ID type (e.g. ID_OB, ID_MA, ...)";


static PyObject *Ipomodule_New(PyObject *self, PyObject *args)
{
	Ipo *ipo;
	int type;
	PyObject *p;
	char *name = NULL, *typename;

	BPY_TRY(PyArg_ParseTuple(args, "s|s", &typename, &name));
	p = PyDict_GetItemString(((constobject *)g_ipoBlockTypes)->dict, typename);
	if (!p) {
		PyErr_SetString(PyExc_TypeError, "Improper Ipo type, see Ipo.Types");
		return NULL;
	}
		
	type = PyInt_AsLong(p);

	if (!name) {
		switch(type) {
			case ID_OB: name = "Objpo"; break;
			case ID_MA: name = "MatIpo"; break;
			case ID_SEQ: name = "SeqIpo"; break;
			case ID_CU: name = "CurveIpo"; break;
			case ID_KE: name = "KeyIpo"; break;
			case ID_WO: name = "WorldIpo"; break;
			case ID_LA: name = "LampIpo"; break;
			case ID_CA: name = "CamIpo"; break;
			case ID_SO: name = "SndIpo"; break;
			case ID_AC: name = "ActionIpo"; break;
			default:
				PyErr_SetString(PyExc_TypeError, "Internal error, illegal type");
				return NULL;
		}		
	}		

	ipo = ipo_new(type, name);
	return DataBlock_fromData(ipo);
}

#undef MethodDef
#define MethodDef(func) _MethodDef(func, Ipomodule)
struct PyMethodDef Ipomodule_methods[] = {

	MethodDef(New),
	MethodDef(get),
	{"BezTriple", pybzt_create, METH_VARARGS, pybzt_create_doc},
	
	{NULL, NULL}
};

/********************/
/* Ipoblock methods */

/* slow and inefficient lookup function , use proper dictionaries in future */
short code_lookup(NamedEnum *codetab, char *name)
{
	int i = 0;
	
	while(codetab[i].name)
	{
		if (!strcmp(codetab[i].name, name))
			return codetab[i].num;
		i++;		
	}	
	return -1;
}

static char Ipo_addCurve_doc[]=
"(type, curve = None) - adds IpoCurve 'curve' to the IpoBlock under type id 'type'";
PyObject *Ipo_addCurve(PyObject *self, PyObject *args) 
{
	
	Ipo *ipo = (Ipo *) ((DataBlock *) self)->data;
	NamedEnum *lookup;

	short code;

	char *type;
	PyIpoCurve *curve = NULL;
	IpoCurve *ipocurve, *existingIpoCurve;

	BPY_TRY(PyArg_ParseTuple(args, "s|O!", &type, &PyIpoCurve_Type, &curve));

	switch (ipo->blocktype) {
	case ID_OB:
		lookup = g_OB_ipocodes;
		break;
	case ID_CA:
		lookup = g_CA_ipocodes;
		break;
	case ID_MA:
		lookup = g_MA_ipocodes;
		break;
	case ID_WO:
		lookup = g_WO_ipocodes;
		break;
	default:
		PyErr_SetString(PyExc_TypeError, "Ipo type not (YET) supported");
		return NULL;
	}
	code = code_lookup(lookup, type);
	if (code == -1) {
		PyErr_SetString(PyExc_TypeError, "Unknown IpoCurve type");
		return NULL;
	}	

	if (!curve) {                             
		ipocurve = ipocurve_new();            // malloc new ipocurve
	} else {                                  // add existing curve:
		ipocurve = ipocurve_copy(curve->icu); // copy ipocurve
	}

	ipocurve->adrcode = code;             // re-code ipo
	ipocurve->blocktype = ipo->blocktype;  

	existingIpoCurve = ipo_findcurve(ipo, code);
	if (existingIpoCurve) {
		BLI_remlink(&(ipo->curve), existingIpoCurve); // remove existing
		MEM_freeN(existingIpoCurve);
	}
	BLI_addtail(&(ipo->curve), ipocurve); // add curve to list
	return IpoCurve_from_icu(ipocurve);
}

static char Ipo_update_doc[]=
"() - Recalculate the ipo and update linked objects";

PyObject *Ipo_update(PyObject *self, PyObject *args) {
	DataBlock *ipoblock = (DataBlock *) self;
	Key *key;
	
	do_ipo((Ipo *) ipoblock->data);

	/* here we should signal all objects with keys that the ipo changed */
	
	key= getKeyList()->first;
	while(key) {
		if(key->ipo == (Ipo *)ipoblock->data) do_spec_key(key);
		key= key->id.next;
	}
	
	return BPY_incr_ret(Py_None);
}

#undef MethodDef
#define MethodDef(func) _MethodDef(func, Ipo)
struct PyMethodDef Ipo_methods[] = {
	MethodDef(addCurve),
	MethodDef(update),
	{NULL, NULL}
};


PyObject *initIpo(void)
{
	PyObject *mod, *dict, *d;

	mod= Py_InitModule(MODNAME(BLENDERMODULE) ".Ipo", Ipomodule_methods);
	dict = PyModule_GetDict(mod);

	// ipo block types
	d = ConstObject_New();
	PyDict_SetItemString(dict, "Types", d);
	g_ipoBlockTypes = d;

	insertConst(d, "Object", PyInt_FromLong(ID_OB));
	insertConst(d, "Material", PyInt_FromLong(ID_MA));
	insertConst(d, "Sequence", PyInt_FromLong(ID_SEQ));
	insertConst(d, "Curve", PyInt_FromLong(ID_CU));
	insertConst(d, "Key", PyInt_FromLong(ID_KE));
	insertConst(d, "World", PyInt_FromLong(ID_WO));
	insertConst(d, "Lamp", PyInt_FromLong(ID_LA));
	insertConst(d, "Camera", PyInt_FromLong(ID_CA));
	insertConst(d, "Sound", PyInt_FromLong(ID_SO));
	insertConst(d, "Action", PyInt_FromLong(ID_AC));

	// interpolation types:
	d = ConstObject_New();
	g_interpolationTypes = d;
	PyDict_SetItemString(dict, "InterpolationTypes", d);
	insertConst(d, "Constant", PyInt_FromLong(IPO_CONST));
	insertConst(d, "Linear", PyInt_FromLong(IPO_LIN));
	insertConst(d, "Bezier", PyInt_FromLong(IPO_BEZ));

	d = ConstObject_New();
	g_extrapolationTypes = d;
	PyDict_SetItemString(dict, "ExtrapolationTypes", d);
	insertConst(d, "Constant", PyInt_FromLong(IPO_HORIZ));
	insertConst(d, "Linear", PyInt_FromLong(IPO_DIR));
	insertConst(d, "Cyclic", PyInt_FromLong(IPO_CYCL));
	insertConst(d, "CyclicLinear", PyInt_FromLong(IPO_CYCLX));

	return mod;
}
