#ifdef HAVE_CONFIG_H #include <config.h> #endif Just need to finish cpp files now :) Kent -- mein@cs.umn.edu
504 lines
15 KiB
C
504 lines
15 KiB
C
/** Object module; access to Object objects 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 "Python.h"
|
|
#include "BPY_macros.h"
|
|
#include "MEM_guardedalloc.h"
|
|
#include "opy_vector.h" /* matrix datatypes */
|
|
|
|
#include "b_interface.h" // most datatypes
|
|
|
|
#include "opy_datablock.h"
|
|
|
|
#include "BLI_arithb.h" /* Mat4Invert */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
/* PROTOS */
|
|
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
|
|
/**************************************************/
|
|
/* Object properties for access by datablock code */
|
|
|
|
#define NULLFUNC 0
|
|
#define NULLHANDLING 0
|
|
|
|
/* structure: see opy_datablock.h */
|
|
/* attrname, DNA_membername, type stype, min, max, index,dlist,
|
|
handlingflag, extra1Ptr, extra2Ptr, extra3Ptr */
|
|
|
|
DataBlockProperty Object_Properties[]= {
|
|
{"LocX", "loc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"LocY", "loc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"LocZ", "loc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"loc", "loc[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"dLocX", "dloc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"dLocY", "dloc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"dLocZ", "dloc[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"dloc", "dloc[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"RotX", "rot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"RotY", "rot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"RotZ", "rot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"rot", "rot[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"dRotX", "drot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"dRotY", "drot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"dRotZ", "drot[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"drot", "drot[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"SizeX", "size[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"SizeY", "size[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"SizeZ", "size[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"size", "size[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"dSizeX", "dsize[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {0}, {3, -sizeof(float)}},
|
|
{"dSizeY", "dsize[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {1}, {3, -sizeof(float)}},
|
|
{"dSizeZ", "dsize[3]", DBP_TYPE_FLO, 0, 0.0, 0.0, {2}, {3, -sizeof(float)}},
|
|
{"dsize", "dsize[3]", DBP_TYPE_VEC, 0, 3.0},
|
|
|
|
{"EffX", "effx", DBP_TYPE_FLO, DBP_TYPE_FUN, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, 0, Object_special_setattr},
|
|
{"EffY", "effy", DBP_TYPE_FLO, DBP_TYPE_FUN, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, 0, Object_special_setattr},
|
|
{"EffZ", "effz", DBP_TYPE_FLO, DBP_TYPE_FUN, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, 0, Object_special_setattr},
|
|
|
|
{"Layer", "layer", DBP_TYPE_INT, DBP_TYPE_FUN, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, 0, Object_special_setattr},
|
|
{"layer", "layer", DBP_TYPE_INT, DBP_TYPE_FUN, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, 0, Object_special_setattr},
|
|
|
|
{"parent", "*parent", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func},
|
|
{"track", "*track", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func},
|
|
{"data", "*data", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func},
|
|
{"ipo", "*ipo", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, 0, 0, get_DataBlock_func},
|
|
|
|
{"mat", "matrix", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, newMatrixObject},
|
|
{"matrix", "matrix", DBP_TYPE_FUN, 0, 0.0, 0.0, {0}, {0}, DBP_HANDLING_FUNC, Object_special_getattr, newMatrixObject},
|
|
|
|
{"colbits", "colbits", DBP_TYPE_SHO, 0, 0.0, 0.0},
|
|
{"drawType", "dt", DBP_TYPE_CHA, 0, 0.0, 0.0},
|
|
{"drawMode", "dtx", DBP_TYPE_CHA, 0, 0.0, 0.0},
|
|
|
|
{NULL}
|
|
};
|
|
|
|
/*************************/
|
|
/* Object module methods */
|
|
|
|
DATABLOCK_GET(Objectmodule, object, getObjectList())
|
|
|
|
char Objectmodule_New_doc[] = "(type) - Add a new object of type 'type' in the current scene";
|
|
static PyObject *Objectmodule_New(PyObject *self, PyObject *args)
|
|
{
|
|
Object *ob;
|
|
int type;
|
|
|
|
if (!PyArg_ParseTuple(args, "i", &type)) {
|
|
PyErr_SetString(PyExc_TypeError, "type expected");
|
|
return 0;
|
|
}
|
|
/* add object */
|
|
ob = object_new(type);
|
|
return DataBlock_fromData(ob);
|
|
}
|
|
|
|
static char Objectmodule_getSelected_doc[]=
|
|
"() - Returns a list of selected Objects in the active layer(s)\n\
|
|
The active object is the first in the list, if visible";
|
|
|
|
static PyObject *Objectmodule_getSelected (PyObject *self, PyObject *args)
|
|
{
|
|
PyObject *ob, *list;
|
|
Base *base;
|
|
Object *tmp;
|
|
|
|
list= PyList_New(0);
|
|
|
|
if (ActiveBase && SelectedAndLayer(ActiveBase)) {
|
|
tmp = ActiveObject; /* active object is first in list */
|
|
if (!tmp) goto no_selection;
|
|
ob = DataBlock_fromData(tmp);
|
|
PyList_Append(list, ob); Py_DECREF(ob); // because previous call increfs
|
|
}
|
|
|
|
base = FirstBase;
|
|
while (base) {
|
|
if (SelectedAndLayer(base) && base != ActiveBase) {
|
|
PyObject *ob = DataBlock_fromData(ObjectfromBase(base));
|
|
if (!ob) goto no_selection;
|
|
PyList_Append(list, ob); Py_DECREF(ob);
|
|
}
|
|
base= base->next;
|
|
}
|
|
return list;
|
|
no_selection:
|
|
Py_DECREF(list);
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
|
struct PyMethodDef Objectmodule_methods[] = {
|
|
{"New", Objectmodule_New, METH_VARARGS, Objectmodule_New_doc},
|
|
// emulation :
|
|
{"Get", Objectmodule_get, METH_VARARGS, Objectmodule_get_doc}, // XXX
|
|
{"get", Objectmodule_get, METH_VARARGS, Objectmodule_get_doc},
|
|
{"getSelected", Objectmodule_getSelected, METH_VARARGS, Objectmodule_getSelected_doc},
|
|
{NULL, NULL}
|
|
};
|
|
|
|
/*************************/
|
|
/* Object object methods */
|
|
|
|
/* Object_get is defined as macro; see opy_datablock.h */
|
|
|
|
|
|
static char Object_getType_doc[] = "() - returns Object type";
|
|
|
|
static PyObject *Object_getType(PyObject *self, PyObject *args)
|
|
{
|
|
Object *ob= PYBLOCK_AS_OBJECT(self);
|
|
return Py_BuildValue("i", (short) ob->type);
|
|
}
|
|
|
|
static char Object_getMatrix_doc[] = "() - returns 4D matrix of object";
|
|
|
|
static PyObject *Object_getMatrix(PyObject *self, PyObject *args)
|
|
{
|
|
Object *ob= PYBLOCK_AS_OBJECT(self);
|
|
return newMatrixObject(ob->obmat);
|
|
}
|
|
|
|
static char Object_getInverseMatrix_doc[] = "() - returns inverse 4D matrix of object";
|
|
|
|
static PyObject *Object_getInverseMatrix(PyObject *self, PyObject *args)
|
|
{
|
|
Object *ob= PYBLOCK_AS_OBJECT(self);
|
|
float inverse[4][4];
|
|
Mat4Invert(inverse, ob->obmat);
|
|
return newMatrixObject(inverse);
|
|
}
|
|
|
|
static char Object_clrParent_doc[]=
|
|
"(mode = 0, fast = 0) - clears parent object.\n\
|
|
If specified:\n\
|
|
mode 2: keep object transform\n\
|
|
fast > 0: don't update scene hierarchy (faster)\n\
|
|
";
|
|
|
|
static PyObject *Object_clrParent(PyObject *self, PyObject *args)
|
|
{
|
|
int mode = 0, ret;
|
|
int fast = 0;
|
|
Object *ob= PYBLOCK_AS_OBJECT(self);
|
|
|
|
BPY_TRY(PyArg_ParseTuple(args, "|ii", &mode, &fast));
|
|
ret = object_clrParent(ob, mode, fast);
|
|
return Py_BuildValue("i", ret);
|
|
}
|
|
|
|
DATABLOCK_ASSIGN_IPO(Object, object) // defines Object_assignIpo
|
|
|
|
static char Object_makeParent_doc[]=
|
|
"([obj1, obj2, ...], mode = 0, fast = 0) - makes 'self' a parent of the\n\
|
|
objects in the list.\n\
|
|
If specified:\n\
|
|
mode <> 0: do not clear parent inverse\n\
|
|
fast <> 0 : do not update scene hierarchy (faster)\n\
|
|
\n\
|
|
If fast is set, you will have to call Scene.getCurrent.update() before\n\
|
|
redraw.";
|
|
|
|
static PyObject *Object_makeParent(PyObject *self, PyObject *args)
|
|
{
|
|
int i, ret;
|
|
PyObject *list;
|
|
int noninverse = 0;
|
|
int fast = 0;
|
|
|
|
DataBlock *parblk = (DataBlock*) self;
|
|
|
|
BPY_TRY(PyArg_ParseTuple(args, "O|ii", &list, &noninverse, &fast));
|
|
if (!PySequence_Check(list)){
|
|
PyErr_SetString(PyExc_TypeError, "expects a list of objects");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < PySequence_Length(list); i ++) {
|
|
DataBlock *childblk = (DataBlock *) PySequence_GetItem(list, i);
|
|
|
|
if (!DataBlock_Check(childblk)) {
|
|
PyErr_SetString(PyExc_TypeError, "Object Type expected");
|
|
return 0;
|
|
}
|
|
ret = object_makeParent((Object *) parblk->data, (Object *) childblk->data, noninverse, fast);
|
|
|
|
Py_DECREF((PyObject *) childblk); // don't need it anymore
|
|
if (ret == 0) { // could not parent
|
|
PyErr_SetString(PyExc_RuntimeError, "parenting failed!");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (PyErr_Occurred()) {
|
|
PyErr_Print();
|
|
}
|
|
return Py_BuildValue("i", 1);
|
|
}
|
|
|
|
static char Object_getMaterials_doc[] = "() - returns a list of object materials";
|
|
|
|
static PyObject *Object_getMaterials(PyObject *self, PyObject *args)
|
|
{
|
|
DataBlock *objectblk = (DataBlock*) self;
|
|
Object *object = PYBLOCK_AS_OBJECT(objectblk);
|
|
return PyList_fromMaterialList(object->mat, object->totcol);
|
|
}
|
|
|
|
static char Object_setMaterials_doc[] = "(materialList) - sets object materials";
|
|
|
|
static PyObject *Object_setMaterials(PyObject *self, PyObject *args)
|
|
{
|
|
int len;
|
|
int ret;
|
|
DataBlock *objectblk = (DataBlock*) self;
|
|
Object *object = PYBLOCK_AS_OBJECT(objectblk);
|
|
PyObject *list;
|
|
Material **matlist;
|
|
|
|
BPY_TRY(PyArg_ParseTuple(args, "O!", &PyList_Type, &list));
|
|
len = PySequence_Length(list);
|
|
if (len) {
|
|
matlist = newMaterialList_fromPyList(list);
|
|
if (!matlist) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"materialList must be a list of valid materials!");
|
|
return 0;
|
|
}
|
|
ret = object_setMaterials(object, matlist, len);
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
return Py_BuildValue("i", ret);
|
|
}
|
|
|
|
static char Object_copy_doc[] = "() - returns a copy of the object, sharing the same data";
|
|
|
|
static PyObject *Object_copy(PyObject *self, PyObject *args)
|
|
{
|
|
Object *new;
|
|
|
|
DataBlock *objectblk = (DataBlock*) self;
|
|
Object *object = PYBLOCK_AS_OBJECT(objectblk);
|
|
|
|
new = object_copy(object);
|
|
return DataBlock_fromData(new);
|
|
}
|
|
|
|
static char Object_shareFrom_doc[] = "(obj) - link data of 'self' with data of 'obj' -- \n\
|
|
only if of same type!";
|
|
|
|
static PyObject *Object_shareFrom(PyObject *self, PyObject *args)
|
|
{
|
|
DataBlock *blockA = (DataBlock*) self;
|
|
DataBlock *blockB;
|
|
Object *object, *other;
|
|
int t;
|
|
|
|
BPY_TRY(PyArg_ParseTuple(args, "O!", &DataBlock_Type, &blockB));
|
|
|
|
if (!DataBlock_isType(blockB, ID_OB)) {
|
|
PyErr_SetString(PyExc_TypeError, "Argument 1 is not of type 'Object'");
|
|
return NULL;
|
|
}
|
|
|
|
object = PYBLOCK_AS_OBJECT(blockA);
|
|
other = PYBLOCK_AS_OBJECT(blockB);
|
|
|
|
if (other->type != object->type) {
|
|
PyErr_SetString(PyExc_TypeError, "Objects are not of same data type");
|
|
return NULL;
|
|
}
|
|
t = object->type;
|
|
switch (t) {
|
|
case OB_MESH:
|
|
return Py_BuildValue("i", object_linkdata(object, other->data));
|
|
default:
|
|
PyErr_SetString(PyExc_TypeError, "Type not supported");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/******************/
|
|
/* get & set attr */
|
|
|
|
static float g_zero_float= 0.0;
|
|
|
|
/* Object attributes functions which require getter/setter C functions
|
|
different from the access provided by DataBlock support */
|
|
|
|
/* get special attributes through datablock property structure */
|
|
|
|
void *Object_special_getattr(void *vdata, char *name)
|
|
{
|
|
Object *ob= (Object *) vdata;
|
|
int scriptflag;
|
|
|
|
if (STREQ(name, "layer")) {
|
|
return &ob->lay;
|
|
|
|
} else if (strncmp(name, "eff", 3)==0) {
|
|
Ika *ika= ob->data;
|
|
|
|
if (ob->type==OB_IKA && ika) {
|
|
if (name[3]=='x') return &ika->effg[0];
|
|
else if (name[3]=='y') return &ika->effg[1];
|
|
else if (name[3]=='z') return &ika->effg[2];
|
|
}
|
|
|
|
return &g_zero_float;
|
|
/* these only for compatibiliy... XXX */
|
|
} else if (STREQ(name, "matrix")) {
|
|
scriptflag = during_script();
|
|
disable_where_script(1);
|
|
where_is_object(ob);
|
|
disable_where_script(scriptflag);
|
|
|
|
return &ob->obmat;
|
|
} else if (STREQ(name, "inverse") || STREQ(name, "inverseMatrix")) {
|
|
return Object_getInverseMatrix(vdata, 0);
|
|
}
|
|
/* end compatibility */
|
|
|
|
PyErr_SetString(PyExc_AttributeError, name);
|
|
return NULL;
|
|
}
|
|
|
|
int Object_special_setattr(void *vdata, char *name, PyObject *py_ob)
|
|
{
|
|
Object *ob= (Object *) vdata;
|
|
|
|
if (STREQ(name, "layer")) {
|
|
Base *base;
|
|
int ival;
|
|
|
|
if (!PyArg_Parse(py_ob, "i", &ival)) return -1;
|
|
|
|
ob->lay= ival;
|
|
// TODO this is old stuff, maybe move to update routine at end of
|
|
// script execution ?
|
|
base= (G.scene->base.first);
|
|
while (base) {
|
|
if (base->object == ob) base->lay= ob->lay;
|
|
base= base->next;
|
|
}
|
|
// end TODO
|
|
|
|
return 0;
|
|
} else if (strncmp(name, "eff", 3)==0) {
|
|
Ika *ika= ob->data;
|
|
float fval;
|
|
|
|
if (!PyArg_Parse(py_ob, "f", &fval)) return -1;
|
|
|
|
if (ob->type==OB_IKA && ika) {
|
|
if (name[3]=='x') ika->effg[0]= fval;
|
|
else if (name[3]=='y') ika->effg[1]= fval;
|
|
else if (name[3]=='z') ika->effg[2]= fval;
|
|
|
|
itterate_ika(ob);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
PyErr_SetString(PyExc_AttributeError, name);
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
#undef MethodDef
|
|
#define MethodDef(func) _MethodDef(func, Object)
|
|
|
|
struct PyMethodDef Object_methods[] = {
|
|
MethodDef(makeParent),
|
|
MethodDef(copy),
|
|
MethodDef(shareFrom),
|
|
MethodDef(getMatrix),
|
|
MethodDef(getType),
|
|
MethodDef(getInverseMatrix),
|
|
MethodDef(clrParent),
|
|
MethodDef(assignIpo),
|
|
MethodDef(clrIpo),
|
|
MethodDef(getMaterials),
|
|
MethodDef(setMaterials),
|
|
{NULL, NULL}
|
|
};
|
|
|
|
#undef BPY_ADDCONST
|
|
#define BPY_ADDCONST(dict, name) insertConst(dict, #name, PyInt_FromLong(OB_##name))
|
|
|
|
PyObject *initObject(void)
|
|
{
|
|
PyObject *mod, *dict, *d;
|
|
|
|
mod= Py_InitModule(MODNAME(BLENDERMODULE) ".Object", Objectmodule_methods);
|
|
dict= PyModule_GetDict(mod);
|
|
d = ConstObject_New();
|
|
PyDict_SetItemString(dict, "Types", d);
|
|
BPY_ADDCONST(d, EMPTY);
|
|
BPY_ADDCONST(d, MESH);
|
|
BPY_ADDCONST(d, LAMP);
|
|
BPY_ADDCONST(d, CAMERA);
|
|
|
|
d = ConstObject_New();
|
|
PyDict_SetItemString(dict, "DrawTypes", d);
|
|
/* dt flags */
|
|
BPY_ADDCONST(d, BOUNDBOX);
|
|
BPY_ADDCONST(d, WIRE);
|
|
BPY_ADDCONST(d, SOLID);
|
|
BPY_ADDCONST(d, SHADED);
|
|
BPY_ADDCONST(d, TEXTURE);
|
|
d = ConstObject_New();
|
|
PyDict_SetItemString(dict, "DrawModes", d);
|
|
/* dtx flags */
|
|
BPY_ADDCONST(d, BOUNDBOX);
|
|
BPY_ADDCONST(d, AXIS);
|
|
BPY_ADDCONST(d, TEXSPACE);
|
|
insertConst(d, "NAME", PyInt_FromLong(OB_DRAWNAME));
|
|
return mod;
|
|
}
|
|
|