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/opy_datablock.c
Kent Mein d0e346d544 updated .c files to include:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Just need to finish cpp files now :)

Kent
--
mein@cs.umn.edu
2002-11-25 12:02:15 +00:00

1304 lines
36 KiB
C

/* 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 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* ---------------------------------------------------------------------- */
/*********************/
/* 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); */
}