This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/bpython/intern/BPY_ipo.c
Hans Lambermont 12315f4d0e Initial revision
2002-10-12 11:37:38 +00:00

718 lines
18 KiB
C

/** Ipo module; access to Ipo datablocks in Blender
* $Id$
*
* ***** 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"
/* 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;
}