diff options
Diffstat (limited to 'source/blender/bpython/intern/opy_datablock.c')
-rw-r--r-- | source/blender/bpython/intern/opy_datablock.c | 1299 |
1 files changed, 1299 insertions, 0 deletions
diff --git a/source/blender/bpython/intern/opy_datablock.c b/source/blender/bpython/intern/opy_datablock.c new file mode 100644 index 00000000000..6804c834897 --- /dev/null +++ b/source/blender/bpython/intern/opy_datablock.c @@ -0,0 +1,1299 @@ +/* Datablock handling code. This handles the generic low level access to Blender + Datablocks. */ + +/* + * $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 ***** + */ + +/************************************************************************** + * This code provides low level, generalized access to the Blender Datablock + * objects. It basically creates a descriptor Python Object of type 'DataBlock' + * for each requested Blender datablock. + * This introduces the question of synchronization, for example: + * What happens if an Object is deleted? + * + * Blender Objects have their own 'reference counting', e.g. a Mesh datablock + * used by two Objects has a user count of 2. Datablocks with user count of 0 + * are not saved to Disk -- this is the current way Blender does + * 'garbage collection' + * Therefore, an object should normally not be deleted by Python, but rather + * unlinked from its parent object. + * Still, for other objects like Scene or Text objects, deletion from 'Main' + * is desired. + * The current workaround: + + * Some objects can be explicitely deleted (not recommended, but possible) -- + * they have a user count of 1, even if they are used by objects in some way, + * for example Text objects which are used by any other Blender object + * through a ScriptLink. + * + * Objects that are deleted through Python end up with a 'dead' descriptor; + * accessing the descriptor after deletion causes a Python exception. + * + * NASTY UGLY DIRTY, VUILE, DRECKIGES AND STILL REMAINING PROBLEM: + * + * It is (in the current API) possible to construct the case, that an + * Object is deleted in Blender, but the Python descriptor does not know + * about this. Accessing the descriptor (which simply contains a pointer to + * the raw datablock struct) will most probably end in colourful joy. + * + * TODO: + * possible solutions: + * - rewrite datablock handling that way, that the descriptor uses an id + * tag to retrieve that pointer through a getPointerbyID() function + * (if the object exists!) on each access. Slow. + * - make sure that deletion always happends by the descriptor and never + * delete the raw datastructure. This solution would imply a major + * redesign of user action handling (GUI actions calling python). + * Not likely to happen...better fusion raw and python object in this case. + * After all, still somewhat dirty. + * - make sure that no deletion can happen in Blender while a script + * still accesses the raw data - i.e. implement user counting of raw + * objects with descriptors. This would need an implementation of + * garbage collection in Blender. This might sound like the most feasible + * solution... + */ + + +#include "Python.h" +#include "BPY_macros.h" + +#include "opy_datablock.h" +#include "opy_nmesh.h" + +#include "opy_vector.h" /* matrix datatypes */ + +#include "BPY_tools.h" +#include "BPY_types.h" +#include "BPY_main.h" + +#include "MEM_guardedalloc.h" + +#include "b_interface.h" /* needed for most of the DNA datatypes */ + + +/* ---------------------------------------------------------------------- */ + +/*********************/ +/* Camera Datablocks */ + +DATABLOCK_GET(Cameramodule, camera, getCameraList()) + +static char Cameramodule_New_doc[] = +"() - returns new Camera object"; + +PyObject *Cameramodule_New (PyObject *self, PyObject *args) +{ + Camera *obj; + obj = camera_new(); + return DataBlock_fromData(obj); +} + +#ifdef FUTURE_PYTHON_API + +DataBlockProperty Camera_Properties[]= { + {"lens", "lens", DBP_TYPE_FLO, 0, 1.0, 250.0}, + {"clipStart","clipsta", DBP_TYPE_FLO, 0, 0.0, 100.0}, + {"clipEnd", "clipend", DBP_TYPE_FLO, 0, 1.0, 5000.0}, + {"type", "type", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"mode", "flag", DBP_TYPE_SHO, 0, 0.0, 0.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#else + +DataBlockProperty Camera_Properties[]= { + {"Lens", "lens", DBP_TYPE_FLO, 0, 1.0, 250.0}, + {"ClSta", "clipsta", DBP_TYPE_FLO, 0, 0.0, 100.0}, + {"ClEnd", "clipend", DBP_TYPE_FLO, 0, 1.0, 5000.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#endif + +static struct PyMethodDef Cameramodule_methods[] = { + {"New", Cameramodule_New, METH_VARARGS, Cameramodule_New_doc}, + {"get", Cameramodule_get, METH_VARARGS, Cameramodule_get_doc}, + {NULL, NULL} +}; + +DATABLOCK_ASSIGN_IPO(Camera, camera) // defines Camera_assignIpo + +static struct PyMethodDef Camera_methods[] = { + {"clrIpo", Camera_clrIpo, METH_VARARGS, Camera_clrIpo_doc}, + {"assignIpo", Camera_assignIpo, METH_VARARGS, Camera_assignIpo_doc}, + {NULL, NULL} +}; + +/***********************/ +/* Material Datablocks */ + + +/** returns a pointer to a new (malloced) material list created from + * a Python material list + */ + +Material **newMaterialList_fromPyList(PyObject *list) +{ + int i, len; + DataBlock *block = 0; + Material *mat; + Material **matlist; + + len = PySequence_Length(list); + if (len > 16) len = 16; + + matlist = newMaterialList(len); + + for (i= 0; i < len; i++) { + + block= (DataBlock *) PySequence_GetItem(list, i); + + if (DataBlock_isType(block, ID_MA)) { + mat = (Material *) block->data; + matlist[i] = mat; + } else { + // error; illegal type in material list + Py_DECREF(block); + MEM_freeN(matlist); + return NULL; + } + Py_DECREF(block); + } + return matlist; +} + +/** Return Python List from material pointer list 'matlist' with length + * 'len' + * + */ + +PyObject *PyList_fromMaterialList(Material **matlist, int len) +{ + PyObject *list; + int i; + + list = PyList_New(0); + if (!matlist) return list; + + for (i = 0; i < len; i++) { + Material *mat= matlist[i]; + PyObject *ob; + + if (mat) { + ob = DataBlock_fromData(mat); + PyList_Append(list, ob); + Py_DECREF(ob); // because Append increfs! + } + } + return list; +} + +DATABLOCK_GET(Materialmodule, material, getMaterialList()) + +DATABLOCK_NEW(Materialmodule, Material, material_new()) + +static struct PyMethodDef Materialmodule_methods[] = { + {"get", Materialmodule_get, METH_VARARGS, Materialmodule_get_doc}, + {"New", Materialmodule_New, METH_VARARGS, Materialmodule_New_doc}, + {NULL, NULL} +}; + +DATABLOCK_ASSIGN_IPO(Material, material) + +static struct PyMethodDef Material_methods[] = { + {"clrIpo", Material_clrIpo, METH_VARARGS, Material_clrIpo_doc}, + {"assignIpo", Material_assignIpo, METH_VARARGS, Material_assignIpo_doc}, + {NULL, NULL} +}; + +#ifdef FUTURE_PYTHON_API + +DataBlockProperty Material_Properties[]= { + {"R", "r", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"G", "g", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"B", "b", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"specR", "specr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"specG", "specg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"specB", "specb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"mirR", "mirr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"mirG", "mirg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"mirB", "mirb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ref", "ref", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"alpha", "alpha", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"emit", "emit", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"amb", "amb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"spec", "spec", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"specTransp", "spectra", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"haloSize", "hasize", DBP_TYPE_FLO, 0, 0.0, 10000.0}, + + {"mode", "mode", DBP_TYPE_INT, 0, 0.0, 0.0}, + {"hard", "har", DBP_TYPE_SHO, 0, 1.0, 128.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#else + +DataBlockProperty Material_Properties[]= { + {"R", "r", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"G", "g", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"B", "b", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"SpecR", "specr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"SpecG", "specg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"SpecB", "specb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"MirR", "mirr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"MirG", "mirg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"MirB", "mirb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Ref", "ref", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Alpha", "alpha", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Emit", "emit", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Amb", "amb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Spec", "spec", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"SpTra", "spectra", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"HaSize", "hasize", DBP_TYPE_FLO, 0, 0.0, 10000.0}, + + {"Mode", "mode", DBP_TYPE_INT, 0, 0.0, 0.0}, + {"Hard", "har", DBP_TYPE_SHO, 0, 1.0, 128.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#endif + +/*******************/ +/* Lamp Datablocks */ + +DATABLOCK_GET(Lampmodule, lamp, getLampList()) + +// DATABLOCK_NEW(Lampmodule, Lamp, lamp_new()) + +static char Lampmodule_New_doc[] = +"() - returns new Lamp object"; + +PyObject *Lampmodule_New (PyObject *self, PyObject *args) +{ + Lamp *obj; + obj = lamp_new(); + return DataBlock_fromData(obj); +} + +#ifdef FUTURE_PYTHON_API + +DataBlockProperty Lamp_Properties[]= { + {"mode", "mode", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"type", "type", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"R", "r", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"G", "g", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"B", "b", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"energy", "energy", DBP_TYPE_FLO, 0, 0.0, 10.0}, + {"dist", "dist", DBP_TYPE_FLO, 0, 0.01, 5000.0}, + {"spotSize", "spotsize", DBP_TYPE_FLO, 0, 1.0, 180.0}, + {"spotBlend", "spotblend", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"haloInt", "haint", DBP_TYPE_FLO, 0, 0.0, 5.0}, + {"quad1", "att1", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"quad2", "att2", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"bufferSize", "bufsize", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"samples", "samp", DBP_TYPE_SHO, 0, 1.0, 16.0}, + {"haloStep", "shadhalostep", DBP_TYPE_SHO, 0, 0.0, 12.0}, + {"clipStart", "clipsta", DBP_TYPE_FLO, 0, 0.1, 5000.0}, + {"clipEnd", "clipend", DBP_TYPE_FLO, 0, 0.1, 5000.0}, + {"bias", "bias", DBP_TYPE_FLO, 0, 0.01, 5.0}, + {"softness", "soft", DBP_TYPE_FLO, 0, 1.00, 100.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; +#else + +DataBlockProperty Lamp_Properties[]= { + {"mode", "mode", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"type", "type", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"R", "r", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"G", "g", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"B", "b", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Energ", "energy", DBP_TYPE_FLO, 0, 0.0, 10.0}, + {"Dist", "dist", DBP_TYPE_FLO, 0, 0.01, 5000.0}, + {"SpotSi", "spotsize", DBP_TYPE_FLO, 0, 1.0, 180.0}, + {"SpotBl", "spotblend", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"HaloInt", "haint", DBP_TYPE_FLO, 0, 1.0, 5.0}, + {"Quad1", "att1", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Quad2", "att2", DBP_TYPE_FLO, 0, 0.0, 1.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#endif + + +static struct PyMethodDef Lampmodule_methods[] = { + {"New", Lampmodule_New, METH_VARARGS, Lampmodule_New_doc}, + {"get", Lampmodule_get, METH_VARARGS, Lampmodule_get_doc}, +#ifdef CURRENT_PYTHON_API + {"Get", Lampmodule_get, METH_VARARGS, Lampmodule_get_doc}, +#endif + {NULL, NULL} +}; + +DATABLOCK_ASSIGN_IPO(Lamp, lamp) // defines Lamp_assignIpo + +static struct PyMethodDef Lamp_methods[] = { + {"clrIpo", Lamp_clrIpo, METH_VARARGS, Lamp_clrIpo_doc}, + {"assignIpo", Lamp_assignIpo, METH_VARARGS, Lamp_assignIpo_doc}, + {NULL, NULL} +}; + +/********************/ +/* World Datablocks */ + +DATABLOCK_GET(Worldmodule, world, getWorldList() ) + +#ifdef FUTURE_PYTHON_API + +DataBlockProperty World_Properties[]= { + + {"mode", "mode", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"skyType", "skytype", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"mistType", "mistype", DBP_TYPE_SHO, 0, 0.0, 0.0}, + {"horR", "horr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"horG", "horg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"horB", "horb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ambR", "ambr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ambG", "ambg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ambB", "ambb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"zenR", "zenr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"zenG", "zeng", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"zenB", "zenb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"exposure", "exposure", DBP_TYPE_FLO, 0, 0.0, 5.0}, + {"mistStart", "miststa", DBP_TYPE_FLO, 0, 0.0, 1000.0}, + {"mistDepth", "mistdist", DBP_TYPE_FLO, 0, 0.0, 1000.0}, + {"mistHeight", "misthi", DBP_TYPE_FLO, 0, 0.0, 100.0}, + {"starDensity", "stardist", DBP_TYPE_FLO, 0, 2.0, 1000.0}, + {"starMinDist", "starmindist", DBP_TYPE_FLO, 0, 0.0, 1000.0}, + {"starSize", "starsize", DBP_TYPE_FLO, 0, 0.0, 10.0}, + {"starColNoise", "starcolsize", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"gravity", "gravity", DBP_TYPE_FLO, 0, 0.0, 25.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#else + +DataBlockProperty World_Properties[]= { + {"HorR", "horr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"HorG", "horg", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"HorB", "horb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ZenR", "zenr", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ZenG", "zeng", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"ZenB", "zenb", DBP_TYPE_FLO, 0, 0.0, 1.0}, + {"Expos", "exposure", DBP_TYPE_FLO, 0, 0.0, 5.0}, + {"MisSta", "miststa", DBP_TYPE_FLO, 0, 0.0, 1000.0}, + {"MisDi", "mistdist", DBP_TYPE_FLO, 0, 0.0, 1000.0}, + {"MisHi", "misthi", DBP_TYPE_FLO, 0, 0.0, 100.0}, + {"StarDi", "stardist", DBP_TYPE_FLO, 0, 2.0, 1000.0}, + {"StarSi", "starsize", DBP_TYPE_FLO, 0, 0.0, 10.0}, + + {"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func}, + + {NULL} +}; + +#endif + +static char Worldmodule_getActive_doc[]="() - Returns the active world"; +static PyObject *Worldmodule_getActive (PyObject *self, PyObject *args) +{ + if (scene_getCurrent()->world) + return DataBlock_fromData(scene_getCurrent()->world); + else + return BPY_incr_ret(Py_None); +} + +static struct PyMethodDef Worldmodule_methods[] = { + // these for compatibility... + {"get", Worldmodule_get, METH_VARARGS, Worldmodule_get_doc}, +#ifdef CURRENT_PYTHON_API + {"Get", Worldmodule_get, METH_VARARGS, Worldmodule_get_doc}, +#endif + {"getCurrent", Worldmodule_getActive, METH_VARARGS, Worldmodule_getActive_doc}, + {NULL, NULL} +}; + + + +/* XXX these should go elsewhere */ + +PyObject *BPY_PyList_FromIDList(ListBase *list, DBConvertfunc convertfunc) +{ + PyObject *pylist= PyList_New(BLI_countlist(list)); + ID *id = list->first; + + int i=0; + + while (id) { + PyObject *ob= convertfunc(id); + + if (!ob) { + Py_DECREF(pylist); + return NULL; + } + PyList_SetItem(pylist, i, ob); + id = id->next; i++; + } + return pylist; +} + + +PyObject *py_find_from_list(ListBase *list, PyObject *args) { + char *name= NULL; + ID *id = list->first; + BPY_TRY(PyArg_ParseTuple(args, "|s", &name)); + + if (name) { + while (id) { + if (strcmp(name, getIDName(id))==0) + return DataBlock_fromData(id); + + id= id->next; + } + return BPY_incr_ret(Py_None); + + } else + return BPY_PyList_FromIDList(list, DataBlock_fromData); +} + +PyObject *named_enum_get(int val, NamedEnum *enums) { + while (enums->name) { + if (enums->num == val) return PyString_FromString(enums->name); + enums++; + } + PyErr_SetString(PyExc_AttributeError, "Internal error, Unknown enumerated type"); + return NULL; +} + +int named_enum_set(char *name, NamedEnum *enums) { + while (enums->name) { + if (STREQ(enums->name, name)) + return enums->num; + enums++; + } + + return -1; +} + +static int calc_offset_subsize(int *dlist, int *idx, int *subsize) { + int n= *dlist; + + if (n<=0) { + *subsize= -n; + return 0; + } else { + int ss; + int off= calc_offset_subsize(dlist+1, idx+1, &ss); + + *subsize= n*ss; + return off + (*idx)*ss; + } +} + +static int calc_offset(int *dlist, int *idx) { + int subsize; + return calc_offset_subsize(dlist, idx, &subsize); +} + +static void *get_db_ptr(DataBlockProperty *prop, char *structname, void *struct_ptr) { + int offset= BLO_findstruct_offset(structname, prop->struct_name); + void *ptr= struct_ptr; + + if (offset==-1) { + BPY_warn(("Internal error, Invalid prop entry\n")); + return NULL; + } + + ptr= (void *) (((char *)ptr) + offset); + + offset= calc_offset(prop->dlist, prop->idx); + ptr= (void *) (((char *)ptr) + offset); + + return ptr; +} + +PyObject *datablock_getattr(DataBlockProperty *props, char *structname, char *name, void *struct_ptr) { + if (STREQ(name, "properties") || STREQ(name, "__members__")) { + PyObject *l= PyList_New(0); + DataBlockProperty *p= props; + + while (p->public_name) { + PyList_Append(l, PyString_FromString(p->public_name)); + p++; + } + + return l; + } + + while (props->public_name) { + if (STREQ(name, props->public_name)) { + void *ptr = struct_ptr; + int val; + DBPtrToObFP conv_fp; + + if (props->handling==DBP_HANDLING_NONE || + props->handling==DBP_HANDLING_NENM) { + ptr= get_db_ptr(props, structname, struct_ptr); + if (!ptr) return NULL; + + } else if (props->handling==DBP_HANDLING_FUNC) { + DBGetPtrFP fp= (DBGetPtrFP) props->extra1; + ptr= fp(struct_ptr, props->struct_name, 0); + if (!ptr) return NULL; + } + + switch(props->type) { + case DBP_TYPE_CHA: + val= *((char *)ptr); + if (props->handling==DBP_HANDLING_NENM) + return named_enum_get(val, props->extra1); + else + return PyInt_FromLong(val); + case DBP_TYPE_SHO: + val= *((short *)ptr); + if (props->handling==DBP_HANDLING_NENM) + return named_enum_get(val, props->extra1); + else + return PyInt_FromLong(val); + case DBP_TYPE_INT: + val= *((int *)ptr); + if (props->handling==DBP_HANDLING_NENM) + return named_enum_get(val, props->extra1); + else + return PyInt_FromLong(val); + case DBP_TYPE_FLO: + return PyFloat_FromDouble ( *((float *)ptr) ); + case DBP_TYPE_VEC: + return newVectorObject ( ((float *)ptr), (int) props->min ); + case DBP_TYPE_FUN: + conv_fp= (DBPtrToObFP) props->extra2; + return conv_fp( ptr ); + default: + PyErr_SetString(PyExc_AttributeError, "Internal error, Unknown prop type"); + return NULL; + } + } + + props++; + } + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +int datablock_setattr(DataBlockProperty *props, char *structname, char *name, void *struct_ptr, PyObject *setto) { + + while (props->public_name) { + if (STREQ(props->public_name, name)) { + void *ptr = NULL; + int type; + DBSetPtrFP conv_fp; + int clamp= props->min!=props->max; + + int enum_val= -1; + char cha_data; + short sho_data; + int int_data; + float flo_data; + + type= props->stype; + if (type==DBP_TYPE_NON) type= props->type; + + if (props->handling==DBP_HANDLING_NONE) { + ptr= get_db_ptr(props, structname, struct_ptr); + if (!ptr) return 0; + + } else if (props->handling==DBP_HANDLING_FUNC) { + if (type!=DBP_TYPE_FUN) { + DBGetPtrFP fp= (DBGetPtrFP) props->extra1; + ptr= fp(struct_ptr, props->struct_name, 1); + if (!ptr) return 0; + } + } else if (props->handling==DBP_HANDLING_NENM) { + char *str; + if (!PyArg_Parse(setto, "s", &str)) return -1; + + ptr= get_db_ptr(props, structname, struct_ptr); + if (!ptr) return 0; + + enum_val= named_enum_set(str, props->extra1); + if (enum_val==-1) + return py_err_ret_int(PyExc_AttributeError, "invalid setting for field"); + } + + switch(type) { + case DBP_TYPE_CHA: + if (enum_val==-1) { + if (!PyArg_Parse(setto, "b", &cha_data)) return -1; + } else cha_data= (char) enum_val; + + if (clamp) { + CLAMP(cha_data, (char) props->min, (char) props->max); + } + *((char *)ptr)= cha_data; + return 0; + case DBP_TYPE_SHO: + if (enum_val==-1) { + if (!PyArg_Parse(setto, "h", &sho_data)) return -1; + } else sho_data= (short) enum_val; + + if (clamp) { + CLAMP(sho_data, (short) props->min, (short) props->max); + } + *((short *)ptr)= sho_data; + return 0; + case DBP_TYPE_INT: + if (enum_val==-1) { + if (!PyArg_Parse(setto, "i", &int_data)) return -1; + } else int_data= (int) enum_val; + + if (clamp) { + CLAMP(int_data, (int) props->min, (int) props->max); + } + *((int *)ptr)= int_data; + return 0; + case DBP_TYPE_FLO: + if (!PyArg_Parse(setto, "f", &flo_data)) return -1; + if (clamp) { + CLAMP(flo_data, (float) props->min, (float) props->max); + } + *((float *)ptr)= flo_data; + return 0; + case DBP_TYPE_VEC: + /* this is very dangerous!! TYPE_VEC also can contain non floats; see + * ipo curve attribute h1t, etc. */ + if (props->min == 3.0 ) { // vector triple + return BPY_parsefloatvector(setto, (float *) ptr, 3); + } else { + return py_err_ret_int(PyExc_AttributeError, "cannot directly assign, use slice assignment instead"); + } + return 0; + + case DBP_TYPE_FUN: + conv_fp= (DBSetPtrFP) props->extra3; + if (conv_fp) + return conv_fp( struct_ptr, props->struct_name, setto ); + else + return py_err_ret_int(PyExc_AttributeError, "cannot directly assign to item"); + default: + PyErr_SetString(PyExc_AttributeError, "Internal error, Unknown prop type"); + return -1; + } + } + + props++; + } + + PyErr_SetString(PyExc_AttributeError, name); + return -1; +} + +PyObject *datablock_assignIpo(DataBlock *block, DataBlock *ipoblock) +{ + Ipo **ipoptr; + Ipo *ipo; + + if (!DataBlock_isType(ipoblock, ID_IP)) { + PyErr_SetString(PyExc_TypeError, "expects Ipo object"); + return 0; + } + + ipo = PYBLOCK_AS_IPO(ipoblock); + + if (DataBlock_type(block) != ipo->blocktype) { + PyErr_SetString(PyExc_TypeError, "Ipo type does not match object type!"); + return 0; + } + + ipoptr = get_db_ptr(block->properties, "ipo", block->data); + if (!ipoptr) { + PyErr_SetString(PyExc_RuntimeError, "Object does not have an ipo!"); + return 0; + } + + *ipoptr = ipo; + Py_INCREF(Py_None); + return Py_None; +} + +/* deallocates a Python Datablock object */ +void DataBlock_dealloc(DataBlock *self) +{ +#ifdef REF_USERCOUNT + BOB_XDECUSER(DATABLOCK_ID(self)); // XXX abuse for ref count +#endif + PyMem_DEL(self); +} + +PyObject *DataBlock_repr(DataBlock *self) +{ + static char s[256]; + if (self->data) + sprintf (s, "[%.32s %.32s]", self->type, getIDName((ID*)self->data)); + else + sprintf (s, "[%.32s %.32s]", self->type, "<deleted>"); + return Py_BuildValue("s", s); +} + +/* ************************************************************************* */ +/* datablock linking */ + +/** Link data to Object */ + +static PyObject *link_Data_toObject(DataBlock *objectblk, DataBlock *datablk) +{ + Object *object = PYBLOCK_AS_OBJECT(objectblk); + + void *data = datablk->data; + if (!object_linkdata(object, data)) + { + PyErr_SetString(PyExc_TypeError, + "Object type different from Data type or linking for this type\ + not supported"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef USE_NMESH +/** Special function to link NMesh data to an Object */ +static PyObject *link_NMesh_toObject(DataBlock *objectblk, NMesh *nmesh) +{ + int retval; + Mesh *mesh = nmesh->mesh; + Object *obj = PYBLOCK_AS_OBJECT(objectblk); + + // if mesh was not created yet (mesh == 0), then do so: + if (!mesh) { + mesh = Mesh_fromNMesh(nmesh); // create and convert data + nmesh->mesh = mesh; + nmesh_updateMaterials(nmesh); + } + + retval = object_linkdata(obj, mesh); + if (!retval) { + PyErr_SetString(PyExc_RuntimeError, "failed to link NMesh data"); + if (!mesh) + printf("mesh data was null\n"); // XXX + return NULL; + } + synchronizeMaterialLists(obj, obj->data); + return Py_BuildValue("i", retval); +} + +#endif + +/** This is the generic function for linking objects with each other. + * It can be called on any DataBlock, as long as this makes sense. + * Example: + * + * from Blender import Object, Scene, NMesh + * ob = Object.get("Plane") + * scene = Scene.get("2") + * ob.link(scene) + * + * or + * + * nmesh = NMesh.GetRaw('Mesh') + * ob.link(nmesh) # instanciate mesh + * + */ + +static char DataBlock_link_doc[]= +"(object) - Links 'self' with the specified object.\n\ +Only the following object types can be linked to each other:\n\ + Scene -> Object\n\ + Object -> Data (Mesh, Curve, etc.)\n\ + Object -> Materials: [Material1, Material2, ...]\n\ +\n\ +The order of linking does not matter, i.e. the following both expressions\n\ +are valid:\n\ +\n\ + scene.link(object)\n\ +\n\ + object.link(scene)\n\ +"; + +PyObject *DataBlock_link(PyObject *self, PyObject *args) +{ + DataBlock *blockA= (DataBlock*) self; + PyObject *with; + DataBlock *blockB; + +#ifdef USE_NMESH + BPY_TRY(PyArg_ParseTuple(args, "O", &with)); + + blockB = (DataBlock *) with; +#else + BPY_TRY(PyArg_ParseTuple(args, "O!", &DataBlock_Type, &blockB)); +#endif + + switch (DataBlock_type(blockA)) { + case ID_OB: + // NMesh is no datablock object, so needs special treatment: +#ifdef USE_NMESH + if (NMesh_Check(with)) { + return link_NMesh_toObject(blockA, (NMesh *) with); + } +#endif + if (!DataBlock_Check(blockB)) { + PyErr_SetString(PyExc_TypeError, "Argument must be a DataBlock object!"); + return NULL; + } + return link_Data_toObject(blockA, blockB); + + default: + PyErr_SetString(PyExc_TypeError, "FATAL: implementation error, illegal link method"); + return NULL; + } +} + +/* unlinking currently disabled, but might me needed later + for other object types... + +static char DataBlock_unlink_doc[]= +"(object) - unlinks 'self' from the specified object.\n\ +See documentation for link() for valid object types."; + +static PyObject *DataBlock_unlink(PyObject *self, PyObject *args) +{ + DataBlock *blockA= (DataBlock*) self; + DataBlock *blockB; + + BPY_TRY(PyArg_ParseTuple(args, "O!", &DataBlock_Type, &blockB)); + switch (DataBlock_type(blockA)) { + case ID_SCE: + switch(DataBlock_type(blockB)) { + case ID_OB: + return unlink_Object_fromScene(blockA, blockB); + default: + PyErr_SetString(PyExc_TypeError, "Scene unlink: invalid Object type"); + return NULL; + } + default: + PyErr_SetString(PyExc_TypeError, "cannot unlink: invalid object type"); + return NULL; + + } + +} +*/ + +/** These are the methods common to each datablock */ + +static struct PyMethodDef commonDataBlock_methods[] = { + {"link", DataBlock_link, METH_VARARGS, DataBlock_link_doc}, +// {"unlink", DataBlock_unlink, METH_VARARGS, DataBlock_unlink_doc}, + {NULL} +}; + +PyObject *DataBlock_getattr(PyObject *self, char *name) { + DataBlock *block= (DataBlock*) self; + PyObject *ret = NULL; + CHECK_VALIDDATA(block, "block was deleted!") + + // Check for common attributes: + if (STREQ(name, "name")) + return PyString_FromString((((ID*)block->data)->name)+2); + else if (STREQ(name, "block_type")) + return PyString_FromString(block->type); + else if (STREQ(name, "users")) + return PyInt_FromLong(((ID*)block->data)->us); + + // + // the following datablock types have methods: + switch (DataBlock_type(block)) { + case ID_OB: + ret = Py_FindMethod(Object_methods, self, name); + break; + case ID_IP: + ret = Py_FindMethod(Ipo_methods, self, name); + break; + case ID_CA: + ret = Py_FindMethod(Camera_methods, self, name); + break; + case ID_MA: + ret = Py_FindMethod(Material_methods, self, name); + break; + case ID_LA: + ret = Py_FindMethod(Lamp_methods, self, name); + break; + case ID_TXT: + ret = Py_FindMethod(Text_methods, self, name); + break; + } + if (ret) return ret; + PyErr_Clear(); // no method found, clear error + + // try common datablock methods + ret = Py_FindMethod(commonDataBlock_methods, (PyObject*)self, name); + if (ret) return ret; + + PyErr_Clear(); + + // try attributes from property list + ret = datablock_getattr(block->properties, block->type, name, block->data); + return ret; +} + +int DataBlock_setattr(PyObject *self, char *name, PyObject *ob) { + DataBlock *block= (DataBlock*) self; + + CHECK_VALIDDATA(block, "block was deleted!") + + if (STREQ(name, "name")) { + if (!PyArg_Parse(ob, "s", &name)) return -1; + + new_id(block->type_list, (ID*)block->data, name); + + return 0; + } + return datablock_setattr(block->properties, block->type, name, block->data, ob); +} + + +PyTypeObject DataBlock_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "Block", /*tp_name*/ + sizeof(DataBlock), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor) DataBlock_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) DataBlock_getattr, /*tp_getattr*/ + (setattrfunc) DataBlock_setattr, /*tp_setattr*/ + (cmpfunc) 0, /*tp_compare*/ + (reprfunc) DataBlock_repr, /*tp_repr*/ +}; + +/**************************************************************************/ + +/**********************/ +/* Texture Datablocks */ +/* +DATABLOCK_GET(Texturemodule, texture, getTextureList()) + +static struct PyMethodDef Texture_methods[] = { + {"Get", Texture_Get, 1, Texture_Get_doc}, + {NULL, NULL} +}; +*/ + + + +/* ---------------------------------------------------------------------- */ + +int DataBlock_type(DataBlock *block) +{ + return (GET_ID_TYPE((ID *) block->data)); +} + +int ObjectDataIDType(DataBlock *block) +{ + Object *ob; + if (!DataBlock_isType(block, ID_OB)) + return -1; + + ob = (Object *) block->data; + return GET_ID_TYPE((ID *) ob->data); +} + +int DataBlock_isType(DataBlock *block, int type) +{ + ID *id; + + if (!DataBlock_Check(block)) return 0; + id= (ID *) block->data; + return (GET_ID_TYPE(id))==type; +} + +/** This function creates a Python datablock descriptor object from + * the specified data pointer. This pointer must point to a structure + * with a valid ID header. + */ + +PyObject *DataBlock_fromData(void *data) { + DataBlock *newb; + ID *id= (ID *) data; + int idn; + + if (!data) return BPY_incr_ret(Py_None); + + idn = GET_ID_TYPE(id); + + if (idn==ID_OB) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Object"; + newb->type_list= getObjectList(); + newb->properties= Object_Properties; + + } else if (idn==ID_ME) { +#ifdef USE_NMESH + return newNMesh(data); +#else + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Mesh"; + newb->type_list= getMeshList(); + newb->properties= Mesh_Properties; +#endif + +// } else if (idn==ID_CU) { + /* Special case, should be fixed + * by proper high-level NURBS access. + * + * Later. + */ + +// return newNCurveObject(data); + + } else if (idn==ID_LA) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Lamp"; + newb->type_list= getLampList(); + newb->properties= Lamp_Properties; + + } else if (idn==ID_CA) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Camera"; + newb->type_list= getCameraList(); + newb->properties= Camera_Properties; + + } else if (idn==ID_MA) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Material"; + newb->type_list= getMaterialList(); + newb->properties= Material_Properties; + + } else if (idn==ID_WO) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "World"; + newb->type_list= getWorldList(); + newb->properties= World_Properties; + + } else if (idn==ID_IP) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Ipo"; + newb->type_list= getIpoList(); + newb->properties= Ipo_Properties; + +#ifdef EXPERIMENTAL + } else if (idn==ID_TE) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Tex"; + newb->type_list= getTextureList(); + newb->properties= Texture_Properties; +#endif + + } else if (idn==ID_IM) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Image"; + newb->type_list= getImageList(); + newb->properties= Image_Properties; + + } else if (idn==ID_TXT) { + newb= PyObject_NEW(DataBlock, &DataBlock_Type); + newb->type= "Text"; + newb->type_list= getTextList(); + newb->properties= Text_Properties; + } else return BPY_err_ret_ob(PyExc_SystemError, "unable to create Block for data"); + + newb->data= data; +#ifdef REF_USERCOUNT + BOB_INCUSER(id); // XXX abuse for refcount +#endif + + return (PyObject *) newb; +} + +PyObject *get_DataBlock_func(void **ptr) { + ID *id= (ID*) *ptr; + return DataBlock_fromData(id); +} + +/* ---------------------------------------------------------------------- */ +/* INIT ROUTINE */ + + +void init_types(PyObject *dict) +{ + PyObject *tmod, *tdict; + + tmod= Py_InitModule("Blender.Types", Null_methods); + PyDict_SetItemString(dict, "Types", tmod); + + tdict= PyModule_GetDict(tmod); + + PyDict_SetItemString(tdict, "IpoCurve", (PyObject *)&PyIpoCurve_Type); + PyDict_SetItemString(tdict, "BezTriple", (PyObject *)&PyBezTriple_Type); + + PyDict_SetItemString(tdict, "ButtonType", (PyObject *)&Button_Type); + PyDict_SetItemString(tdict, "BufferType", (PyObject *)&Buffer_Type); + PyDict_SetItemString(tdict, "NMeshType", (PyObject *)&NMesh_Type); + PyDict_SetItemString(tdict, "NMFaceType", (PyObject *)&NMFace_Type); + PyDict_SetItemString(tdict, "NMVertType", (PyObject *)&NMVert_Type); + PyDict_SetItemString(tdict, "NMColType", (PyObject *)&NMCol_Type); + + PyDict_SetItemString(tdict, "BlockType", (PyObject *)&DataBlock_Type); + + /* Setup external types */ + PyDict_SetItemString(tdict, "VectorType", (PyObject *)&Vector_Type); + PyDict_SetItemString(tdict, "MatrixType", (PyObject *)&Matrix_Type); +} + +#undef BPY_ADDCONST +#define BPY_ADDCONST(dict, name) insertConst(dict, #name, PyInt_FromLong(LA_##name)) + +PyObject *initLamp(void) +{ + PyObject *mod, *dict, *d; + + mod= Py_InitModule(MODNAME(BLENDERMODULE) ".Lamp", Lampmodule_methods); + dict= PyModule_GetDict(mod); + d = ConstObject_New(); + PyDict_SetItemString(dict, "Types", d); + + /* type */ + BPY_ADDCONST(d, LOCAL); + BPY_ADDCONST(d, SUN); + BPY_ADDCONST(d, SPOT); + BPY_ADDCONST(d, HEMI); + + d = ConstObject_New(); + PyDict_SetItemString(dict, "Modes", d); + + /* mode */ + BPY_ADDCONST(d, SHAD); + BPY_ADDCONST(d, HALO); + BPY_ADDCONST(d, LAYER); + BPY_ADDCONST(d, QUAD); + BPY_ADDCONST(d, NEG); + BPY_ADDCONST(d, ONLYSHADOW); + BPY_ADDCONST(d, SPHERE); + BPY_ADDCONST(d, SQUARE); + BPY_ADDCONST(d, TEXTURE); + BPY_ADDCONST(d, OSATEX); + BPY_ADDCONST(d, DEEP_SHADOW); + + return mod; +} + +PyObject *initMaterial(void) +{ + PyObject *mod, *dict, *d; + + mod= Py_InitModule(MODNAME(BLENDERMODULE) ".Material", + Materialmodule_methods); + dict= PyModule_GetDict(mod); + d = ConstObject_New(); + PyDict_SetItemString(dict, "Modes", d); + + /* MATERIAL MODES + * ...some of these have really cryptic defines :-) + * We try to match them to the GUI descriptions... */ + +#undef BPY_ADDCONST +#define BPY_ADDCONST(dict, name) \ + insertConst(dict, #name, PyInt_FromLong(MA_##name)) + + insertConst(d, "TRACEABLE", PyInt_FromLong(MA_TRACEBLE)); + BPY_ADDCONST(d, SHADOW); + insertConst(d, "SHADELESS", PyInt_FromLong(MA_SHLESS)); + BPY_ADDCONST(d, WIRE); + insertConst(d, "VCOL_LIGHT", PyInt_FromLong(MA_VERTEXCOL)); + BPY_ADDCONST(d, HALO); + insertConst(d, "ZTRANSP", PyInt_FromLong(MA_ZTRA)); + insertConst(d, "VCOL_PAINT", PyInt_FromLong(MA_VERTEXCOLP)); + insertConst(d, "ZINVERT", PyInt_FromLong(MA_ZINV)); + BPY_ADDCONST(d, ONLYSHADOW); + BPY_ADDCONST(d, STAR); + insertConst(d, "TEXFACE", PyInt_FromLong(MA_FACETEXTURE)); + BPY_ADDCONST(d, NOMIST); + + /* HALO MODES */ + d = ConstObject_New(); + PyDict_SetItemString(dict, "HaloModes", d); + +#undef BPY_ADDCONST +#define BPY_ADDCONST(dict, name) \ + insertConst(dict, #name, PyInt_FromLong(MA_HALO_##name)) + + BPY_ADDCONST(d, RINGS); + BPY_ADDCONST(d, LINES); + insertConst(d, "TEX", PyInt_FromLong(MA_HALOTEX)); + insertConst(d, "PUNO", PyInt_FromLong(MA_HALOPUNO)); + BPY_ADDCONST(d, SHADE); + BPY_ADDCONST(d, FLARE); + + return mod; +} + +void init_Datablockmodules(PyObject *dict) { +#define MODLOAD(name) PyDict_SetItemString(dict, #name, Py_InitModule(MODNAME(BLENDERMODULE) "." #name, name##module_methods)) + + DataBlock_Type.ob_type = &PyType_Type; + PyIpoCurve_Type.ob_type= &PyType_Type; + PyBezTriple_Type.ob_type= &PyType_Type; + + PyDict_SetItemString(dict, "Object", initObject()); + PyDict_SetItemString(dict, "Lamp", initLamp()); + PyDict_SetItemString(dict, "Material", initMaterial()); + PyDict_SetItemString(dict, "Ipo", initIpo()); + PyDict_SetItemString(dict, "Scene", initScene()); + MODLOAD(Text); +// MODLOAD(Mesh); + MODLOAD(Camera); + MODLOAD(World); + MODLOAD(Image); +/* MODLOAD(Texture); */ +} |