diff --git a/source/blender/python/api2_2x/Group.c b/source/blender/python/api2_2x/Group.c index fae3c11db5a..080520e3a9d 100755 --- a/source/blender/python/api2_2x/Group.c +++ b/source/blender/python/api2_2x/Group.c @@ -48,6 +48,9 @@ #include "Object.h" #include "gen_utils.h" +/* checks for the group being removed */ +#define GROUP_DEL_CHECK_PY(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Group has been removed" ) ) +#define GROUP_DEL_CHECK_INT(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Group has been removed" ) ) /*****************************************************************************/ /* Python API function prototypes for the Blender module. */ @@ -56,6 +59,8 @@ static PyObject *M_Group_New( PyObject * self, PyObject * args ); PyObject *M_Group_Get( PyObject * self, PyObject * args ); PyObject *M_Group_Unlink( PyObject * self, PyObject * args ); +/* internal */ +static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter ); /*****************************************************************************/ /* Python method structure definition for Blender.Object module: */ @@ -86,41 +91,38 @@ static PyMethodDef BPy_Group_methods[] = { static PyObject *BPy_Group_copy( BPy_Group * self ) { + BPy_Group *py_group; /* for Group Data object wrapper in Python */ + struct Group *bl_group; + GroupObject *group_ob, *group_ob_new; /* Group object, copied and added to the groups */ - if( !(self->group) ) { - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Group was deleted!" ); - } else { - BPy_Group *py_group; /* for Group Data object wrapper in Python */ - struct Group *bl_group; - GroupObject *group_ob, *group_ob_new; /* Group object, copied and added to the groups */ - - bl_group= add_group(); - - if( bl_group ) /* now create the wrapper grp in Python */ - py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group ); - else - return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, - "couldn't create Group Data in Blender" ) ); - - rename_id( &bl_group->id, self->group->id.name + 2 ); - - - /* user count be incremented in Group_CreatePyObject */ - bl_group->id.us = 0; - - /* Now add the objects to the group */ - group_ob= self->group->gobject.first; - while(group_ob) { - /* save time by not using */ - group_ob_new= MEM_callocN(sizeof(GroupObject), "groupobject"); - group_ob_new->ob= group_ob->ob; - BLI_addtail( &bl_group->gobject, group_ob_new); - group_ob= group_ob->next; - } - - return ( PyObject * ) py_group; + GROUP_DEL_CHECK_PY(self); + + bl_group= add_group(); + + if( bl_group ) /* now create the wrapper grp in Python */ + py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group ); + else + return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, + "couldn't create Group Data in Blender" ) ); + + rename_id( &bl_group->id, self->group->id.name + 2 ); + + + /* user count be incremented in Group_CreatePyObject */ + bl_group->id.us = 0; + + /* Now add the objects to the group */ + group_ob= self->group->gobject.first; + while(group_ob) { + /* save time by not using */ + group_ob_new= MEM_callocN(sizeof(GroupObject), "groupobject"); + group_ob_new->ob= group_ob->ob; + BLI_addtail( &bl_group->gobject, group_ob_new); + group_ob= group_ob->next; } + + return ( PyObject * ) py_group; + } @@ -131,9 +133,7 @@ static PyObject *BPy_Group_copy( BPy_Group * self ) ************************************************************************/ static PyObject *Group_getObjects( BPy_Group * self ) { - BPy_GroupObSeq *seq = PyObject_NEW( BPy_GroupObSeq, &GroupObSeq_Type); - seq->bpygroup = self; Py_INCREF(self); - return (PyObject *)seq; + return GroupObSeq_CreatePyObject(self, NULL); } @@ -158,6 +158,8 @@ static int Group_setObjects( BPy_Group * self, PyObject * args ) Object *blen_ob; group= self->group; + GROUP_DEL_CHECK_INT(self); + if( PyList_Check( args ) ) { if( EXPP_check_sequence_consistency( args, &Object_Type ) != 1) return ( EXPP_ReturnIntError( PyExc_TypeError, @@ -170,11 +172,6 @@ static int Group_setObjects( BPy_Group * self, PyObject * args ) blen_ob= ((BPy_Object *)PyList_GET_ITEM( args, i ))->object; add_to_group_wraper(group, blen_ob); } - /* - } else if( args->ob_type == &GroupObSeq_Type ) { - */ - /* todo, handle sequences here */ - } else if (PyIter_Check(args)) { PyObject *iterator = PyObject_GetIter(args); PyObject *item; @@ -224,9 +221,7 @@ static int Group_setName( BPy_Group * self, PyObject * value ) char *name = NULL; char buf[21]; - if( !(self->group) ) - return EXPP_ReturnIntError( PyExc_RuntimeError, - "Blender Group was deleted!" ); + GROUP_DEL_CHECK_INT(self); name = PyString_AsString ( value ); if( !name ) @@ -244,9 +239,7 @@ static int Group_setName( BPy_Group * self, PyObject * value ) static PyObject *Group_getName( BPy_Group * self, PyObject * args ) { PyObject *attr; - if( !(self->group) ) - return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Group was deleted!" ) ); + GROUP_DEL_CHECK_PY(self); attr = PyString_FromString( self->group->id.name + 2 ); @@ -488,11 +481,10 @@ PyObject *M_Group_Unlink( PyObject * self, PyObject * args ) "expected a group" ) ); pygrp= (BPy_Group *)pyob; - group= pygrp->group; - if( !group ) - return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Group was deleted!" ) ); + GROUP_DEL_CHECK_PY(pygrp); + + group= pygrp->group; pygrp->group= NULL; free_group(group); @@ -625,6 +617,9 @@ static int Group_compare( BPy_Group * a, BPy_Group * b ) /*****************************************************************************/ static PyObject *Group_repr( BPy_Group * self ) { + if (!self->group) + return PyString_FromString( "[Group - Removed]" ); + return PyString_FromFormat( "[Group \"%s\"]", self->group->id.name + 2 ); } @@ -639,12 +634,34 @@ static PyObject *Group_repr( BPy_Group * self ) * create a thin GroupOb object */ -static PyObject *GroupObSeq_CreatePyObject( Group *group, int i ) +static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter ) { + BPy_GroupObSeq *seq = PyObject_NEW( BPy_GroupObSeq, &GroupObSeq_Type); + seq->bpygroup = self; Py_INCREF(self); + seq->iter= iter; + return (PyObject *)seq; +} + + +static int GroupObSeq_len( BPy_GroupObSeq * self ) +{ + GROUP_DEL_CHECK_INT(self->bpygroup); + return BLI_countlist( &( self->bpygroup->group->gobject ) ); +} + +/* + * retrive a single GroupOb from somewhere in the GroupObex list + */ + +static PyObject *GroupObSeq_item( BPy_GroupObSeq * self, int i ) +{ + Group *group= self->bpygroup->group; int index=0; PyObject *bpy_obj; GroupObject *gob; + GROUP_DEL_CHECK_PY(self->bpygroup); + for (gob= group->gobject.first; gob && i!=index; gob= gob->next, index++) {} if (!(gob)) @@ -658,21 +675,7 @@ static PyObject *GroupObSeq_CreatePyObject( Group *group, int i ) "PyObject_New() failed" ); return (PyObject *)bpy_obj; -} - - -static int GroupObSeq_len( BPy_GroupObSeq * self ) -{ - return BLI_countlist( &( self->bpygroup->group->gobject ) ); -} - -/* - * retrive a single GroupOb from somewhere in the GroupObex list - */ - -static PyObject *GroupObSeq_item( BPy_GroupObSeq * self, int i ) -{ - return GroupObSeq_CreatePyObject( self->bpygroup->group, i ); + } static PySequenceMethods GroupObSeq_as_sequence = { @@ -698,8 +701,14 @@ static PySequenceMethods GroupObSeq_as_sequence = { static PyObject *GroupObSeq_getIter( BPy_GroupObSeq * self ) { - self->iter = self->bpygroup->group->gobject.first; - return EXPP_incr_ret ( (PyObject *) self ); + GROUP_DEL_CHECK_PY(self->bpygroup); + + if (!self->iter) { + self->iter = self->bpygroup->group->gobject.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return GroupObSeq_CreatePyObject(self->bpygroup->group, self->bpygroup->group->gobject.first); + } } /* @@ -724,6 +733,9 @@ static PyObject *GroupObSeq_add( BPy_GroupObSeq * self, PyObject *args ) PyObject *pyobj; Object *blen_ob; Base *base= NULL; + + GROUP_DEL_CHECK_PY(self->bpygroup); + if( !PyArg_ParseTuple( args, "O!", &Object_Type, &pyobj ) ) return ( EXPP_ReturnPyObjError( PyExc_TypeError, "expected a python object as an argument" ) ); @@ -745,9 +757,7 @@ static PyObject *GroupObSeq_remove( BPy_GroupObSeq * self, PyObject *args ) Object *blen_ob; Base *base= NULL; - if( !(self->bpygroup->group) ) - return (EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Group was deleted!" )); + GROUP_DEL_CHECK_PY(self->bpygroup); if( !PyArg_ParseTuple( args, "O!", &Object_Type, &pyobj ) ) return ( EXPP_ReturnPyObjError( PyExc_TypeError, diff --git a/source/blender/python/api2_2x/Metaball.c b/source/blender/python/api2_2x/Metaball.c index ea8a3ecac31..0b107766da3 100644 --- a/source/blender/python/api2_2x/Metaball.c +++ b/source/blender/python/api2_2x/Metaball.c @@ -726,14 +726,21 @@ static PyObject *Metaball_copy( BPy_Metaball * self ) return ( PyObject * ) pymball; } + +static PyObject *MetaElemSeq_CreatePyObject(PyObject *self, MetaElem *iter) +{ + BPy_MetaElemSeq *seq = PyObject_NEW( BPy_MetaElemSeq, &MetaElemSeq_Type); + seq->bpymetaball = self; Py_INCREF(self); + seq->iter= iter; + return (PyObject *)seq; +} + /* * Element, get an instance of the iterator. */ static PyObject *Metaball_getElements( BPy_Metaball * self ) { - BPy_MetaElemSeq *seq = PyObject_NEW( BPy_MetaElemSeq, &MetaElemSeq_Type); - seq->bpymetaball = self; Py_INCREF(self); - return (PyObject *)seq; + return MetaElemSeq_CreatePyObject(self, NULL); } /* @@ -1016,8 +1023,11 @@ static PySequenceMethods MetaElemSeq_as_sequence = { static PyObject *MetaElemSeq_getIter( BPy_MetaElemSeq * self ) { - self->iter = self->bpymetaball->metaball->elems.first; - return EXPP_incr_ret ( (PyObject *) self ); + if (!self->iter) { /* not alredy looping on this data, */ + self->iter = self->bpymetaball->metaball->elems.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else + return MetaElemSeq_CreatePyObject(self->bpymetaball, self->bpymetaball->metaball->elems.first); } /* @@ -1027,9 +1037,11 @@ static PyObject *MetaElemSeq_getIter( BPy_MetaElemSeq * self ) static PyObject *MetaElemSeq_nextIter( BPy_MetaElemSeq * self ) { PyObject *object; - if( !(self->iter) || !(self->bpymetaball->metaball) ) + if( !(self->iter) || !(self->bpymetaball->metaball) ) { + self->iter= NULL; return EXPP_ReturnPyObjError( PyExc_StopIteration, "iterator at end" ); + } object= MetaElem_CreatePyObject( self->iter ); self->iter= self->iter->next; diff --git a/source/blender/python/api2_2x/Modifier.c b/source/blender/python/api2_2x/Modifier.c index 89faa8c86d9..9c597f2618c 100644 --- a/source/blender/python/api2_2x/Modifier.c +++ b/source/blender/python/api2_2x/Modifier.c @@ -27,6 +27,9 @@ * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ +/* TODO, accessing a modifier sequence of a deleted object will crash blender at the moment, not sure how to fix this. */ + + #include "Modifier.h" /*This must come first*/ #include "DNA_object_types.h" @@ -48,6 +51,10 @@ #include "Mathutils.h" #include "gen_utils.h" +/* checks for the scene being removed */ +#define MODIFIER_DEL_CHECK_PY(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Modifier has been removed" ) ) +#define MODIFIER_DEL_CHECK_INT(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Modifier has been removed" ) ) + enum mod_constants { /*Apply to all modifiers*/ EXPP_MOD_RENDER = 0, @@ -252,10 +259,7 @@ PyTypeObject Modifier_Type = { static PyObject *Modifier_getName( BPy_Modifier * self ) { - if (self->md==NULL) - return (EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This modifier has been removed!" )); - + MODIFIER_DEL_CHECK_PY(self); return PyString_FromString( self->md->name ); } @@ -269,9 +273,7 @@ static int Modifier_setName( BPy_Modifier * self, PyObject * attr ) if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" ); - if (self->md==NULL) - return (EXPP_ReturnIntError( PyExc_RuntimeError, - "This modifier has been removed!" )); + MODIFIER_DEL_CHECK_INT(self); BLI_strncpy( self->md->name, name, sizeof( self->md->name ) ); @@ -284,9 +286,7 @@ static int Modifier_setName( BPy_Modifier * self, PyObject * attr ) static PyObject *Modifier_getType( BPy_Modifier * self ) { - if (self->md==NULL ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This modifier has been removed!" ); + MODIFIER_DEL_CHECK_PY(self); return PyInt_FromLong( self->md->type ); } @@ -729,9 +729,7 @@ static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected an int arg as stored in Blender.Modifier.Settings" ); - if (self->md==NULL ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "This modifier has been removed!" ); + MODIFIER_DEL_CHECK_PY(self); setting = PyInt_AsLong( key ); switch( setting ) { @@ -784,9 +782,7 @@ static int Modifier_setData( BPy_Modifier * self, PyObject * key, return EXPP_ReturnIntError( PyExc_TypeError, "expected an int arg as stored in Blender.Modifier.Settings" ); - if (self->md==NULL ) - return EXPP_ReturnIntError( PyExc_RuntimeError, - "This modifier has been removed!" ); + MODIFIER_DEL_CHECK_INT(self); key_int = PyInt_AsLong( key ); @@ -910,8 +906,12 @@ ModifierData *Modifier_FromPyObject( PyObject * pyobj ) static PyObject *Modifiers_getIter( BPy_Modifiers * self ) { - self->iter = (ModifierData *)self->obj->modifiers.first; - return EXPP_incr_ret ( (PyObject *) self ); + if (!self->iter) { + self->iter = (ModifierData *)self->obj->modifiers.first; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return ModSeq_CreatePyObject(self->obj, (ModifierData *)self->obj->modifiers.first); + } } /* @@ -920,12 +920,13 @@ static PyObject *Modifiers_getIter( BPy_Modifiers * self ) static PyObject *Modifiers_nextIter( BPy_Modifiers * self ) { - ModifierData *this = self->iter; - if( this ) { - self->iter = this->next; - return Modifier_CreatePyObject( self->obj, this ); + ModifierData *iter = self->iter; + if( iter ) { + self->iter = iter->next; + return Modifier_CreatePyObject( self->obj, iter ); } - + + self->iter= NULL; /* mark as not iterating */ return EXPP_ReturnPyObjError( PyExc_StopIteration, "iterator at end" ); } @@ -1195,7 +1196,7 @@ PyTypeObject Modifiers_Type = { /* Description: This function will create a new BPy_Modifiers from an */ /* existing ListBase structure. */ /*****************************************************************************/ -PyObject *ModSeq_CreatePyObject( Object *obj ) +PyObject *ModSeq_CreatePyObject( Object *obj, ModifierData *iter ) { BPy_Modifiers *pymod; pymod = ( BPy_Modifiers * ) PyObject_NEW( BPy_Modifiers, &Modifiers_Type ); @@ -1203,6 +1204,7 @@ PyObject *ModSeq_CreatePyObject( Object *obj ) return EXPP_ReturnPyObjError( PyExc_MemoryError, "couldn't create BPy_Modifiers object" ); pymod->obj = obj; + pymod->iter = iter; return ( PyObject * ) pymod; } diff --git a/source/blender/python/api2_2x/Modifier.h b/source/blender/python/api2_2x/Modifier.h index f2b064141d0..a0de656c7d7 100644 --- a/source/blender/python/api2_2x/Modifier.h +++ b/source/blender/python/api2_2x/Modifier.h @@ -68,6 +68,6 @@ typedef struct { ModifierData *iter; } BPy_Modifiers; -PyObject *ModSeq_CreatePyObject( Object *obj ); +PyObject *ModSeq_CreatePyObject( Object *obj, ModifierData *iter ); #endif /* EXPP_MODIFIER_H */ diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c index b3dad13fa1c..2859352210d 100644 --- a/source/blender/python/api2_2x/Object.c +++ b/source/blender/python/api2_2x/Object.c @@ -2945,7 +2945,7 @@ static PyObject *Object_getConstraints( BPy_Object * self ) static PyObject *Object_getModifiers( BPy_Object * self ) { - return ModSeq_CreatePyObject( self->object ); + return ModSeq_CreatePyObject( self->object, NULL ); } static PyObject *Object_insertShapeKey(BPy_Object * self) diff --git a/source/blender/python/api2_2x/Scene.c b/source/blender/python/api2_2x/Scene.c index 097a93155e1..e62fd12abc6 100644 --- a/source/blender/python/api2_2x/Scene.c +++ b/source/blender/python/api2_2x/Scene.c @@ -80,6 +80,11 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args ); /* from Object.c */ #define EXPP_SCENE_FRAME_MAX 30000 #define EXPP_SCENE_RENDER_WINRESOLUTION_MIN 4 #define EXPP_SCENE_RENDER_WINRESOLUTION_MAX 10000 + +/* checks for the scene being removed */ +#define SCENE_DEL_CHECK_PY(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Scene has been removed" ) ) +#define SCENE_DEL_CHECK_INT(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Scene has been removed" ) ) + /*-----------------------Python API function prototypes for the Scene module--*/ static PyObject *M_Scene_New( PyObject * self, PyObject * args, PyObject * keywords ); @@ -141,6 +146,10 @@ static int Scene_setAttr( BPy_Scene * self, char *name, PyObject * v ); static int Scene_compare( BPy_Scene * a, BPy_Scene * b ); static PyObject *Scene_getAttr( BPy_Scene * self, char *name ); static PyObject *Scene_repr( BPy_Scene * self ); + +/*object seq*/ +static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode); + /*-----------------------BPy_Scene method def------------------------------*/ static PyMethodDef BPy_Scene_methods[] = { /* name, method, flags, doc */ @@ -270,10 +279,7 @@ static void Scene_dealloc( BPy_Scene * self ) static PyObject *Scene_getAttr( BPy_Scene * self, char *name ) { PyObject *attr = Py_None; - - if( !(self->scene) ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( strcmp( name, "name" ) == 0 ) attr = PyString_FromString( self->scene->id.name + 2 ); @@ -306,10 +312,7 @@ static int Scene_setAttr( BPy_Scene * self, char *name, PyObject * value ) PyObject *valtuple; PyObject *error = NULL; - if( !(self->scene) ) - return EXPP_ReturnIntError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); - + SCENE_DEL_CHECK_INT(self); /* We're playing a trick on the Python API users here. Even if they use * Scene.member = val instead of Scene.setMember(val), we end up using the @@ -361,7 +364,7 @@ static int Scene_compare( BPy_Scene * a, BPy_Scene * b ) static PyObject *Scene_repr( BPy_Scene * self ) { if( !(self->scene) ) - return PyString_FromString( "[Scene Unlinked]"); + return PyString_FromString( "[Scene - Removed]"); else return PyString_FromFormat( "[Scene \"%s\"]", self->scene->id.name + 2 ); @@ -537,9 +540,7 @@ static PyObject *M_Scene_Unlink( PyObject * self, PyObject * args ) pyscn = (BPy_Scene *)pyobj; scene = pyscn->scene; - if (!(scene)) - return EXPP_ReturnPyObjError( PyExc_SystemError, - "scene has alredy been removed!" ); + SCENE_DEL_CHECK_PY(pyscn); if( scene == G.scene ) return EXPP_ReturnPyObjError( PyExc_SystemError, @@ -547,16 +548,19 @@ static PyObject *M_Scene_Unlink( PyObject * self, PyObject * args ) free_libblock( &G.main->scene, scene ); - pyscn->scene=NULL; - Py_INCREF( Py_None ); - return Py_None; + pyscn->scene= NULL; + Py_RETURN_NONE; } /*-----------------------BPy_Scene function defintions-------------------*/ /*-----------------------Scene.getName()---------------------------------*/ static PyObject *Scene_getName( BPy_Scene * self ) { - PyObject *attr = PyString_FromString( self->scene->id.name + 2 ); + PyObject *attr; + + SCENE_DEL_CHECK_PY(self); + + attr= PyString_FromString( self->scene->id.name + 2 ); if( attr ) return attr; @@ -570,17 +574,18 @@ static PyObject *Scene_setName( BPy_Scene * self, PyObject * args ) { char *name; char buf[21]; - + + SCENE_DEL_CHECK_PY(self); + if( !PyArg_ParseTuple( args, "s", &name ) ) return ( EXPP_ReturnPyObjError( PyExc_TypeError, "expected string argument" ) ); - + PyOS_snprintf( buf, sizeof( buf ), "%s", name ); rename_id( &self->scene->id, buf ); - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /*-----------------------Scene.getLayers()---------------------------------*/ @@ -588,7 +593,9 @@ static PyObject *Scene_getLayers( BPy_Scene * self ) { PyObject *laylist = PyList_New( 0 ), *item; int layers, bit = 0, val = 0; - + + SCENE_DEL_CHECK_PY(self); + if( !laylist ) return ( EXPP_ReturnPyObjError( PyExc_MemoryError, "couldn't create pylist!" ) ); @@ -612,7 +619,9 @@ static PyObject *Scene_setLayers( BPy_Scene * self, PyObject * args ) { PyObject *list = NULL, *item = NULL; int layers = 0, val, i, len_list; - + + SCENE_DEL_CHECK_PY(self); + if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &list ) ) return ( EXPP_ReturnPyObjError( PyExc_TypeError, "expected a list of integers in the range [1, 20]" ) ); @@ -654,14 +663,16 @@ static PyObject *Scene_setLayers( BPy_Scene * self, PyObject * args ) } } - return EXPP_incr_ret(Py_None); + Py_RETURN_NONE; } /* only used by setAttr */ static PyObject *Scene_setLayersMask(BPy_Scene *self, PyObject *args) { int laymask = 0; - + + SCENE_DEL_CHECK_PY(self); + if (!PyArg_ParseTuple(args , "i", &laymask)) { return EXPP_ReturnPyObjError( PyExc_AttributeError, "expected an integer (bitmask) as argument" ); @@ -688,7 +699,7 @@ static PyObject *Scene_setLayersMask(BPy_Scene *self, PyObject *args) } } - return EXPP_incr_ret(Py_None); + Py_RETURN_NONE; } /*-----------------------Scene.copy()------------------------------------*/ @@ -697,9 +708,7 @@ static PyObject *Scene_copy( BPy_Scene * self, PyObject * args ) short dup_objs = 1; Scene *scene = self->scene; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "|h", &dup_objs ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -712,14 +721,15 @@ static PyObject *Scene_copy( BPy_Scene * self, PyObject * args ) static PyObject *Scene_makeCurrent( BPy_Scene * self ) { Scene *scene = self->scene; - - if( scene ) { + + SCENE_DEL_CHECK_PY(self); + + if( scene && scene != G.scene) { set_scene( scene ); scene_update_for_newframe(scene, scene->lay); } - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /*-----------------------Scene.update()----------------------------------*/ @@ -727,10 +737,8 @@ static PyObject *Scene_update( BPy_Scene * self, PyObject * args ) { Scene *scene = self->scene; int full = 0; - - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "|i", &full ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -752,8 +760,7 @@ static PyObject *Scene_update( BPy_Scene * self, PyObject * args ) "0: to only sort scene elements (old behavior); or\n" "1: for a full update (regroups, does ipos, keys, etc.)" ); - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /*-----------------------Scene.link()------------------------------------*/ @@ -763,9 +770,7 @@ static PyObject *Scene_link( BPy_Scene * self, PyObject * args ) BPy_Object *bpy_obj; Object *object = NULL; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -817,8 +822,7 @@ static PyObject *Scene_link( BPy_Scene * self, PyObject * args ) BLI_addhead( &scene->base, base ); /* finally, link new base to scene */ } - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /*-----------------------Scene.unlink()----------------------------------*/ @@ -828,9 +832,7 @@ static PyObject *Scene_unlink( BPy_Scene * self, PyObject * args ) Scene *scene = self->scene; Base *base; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -857,9 +859,7 @@ static PyObject *Scene_getChildren( BPy_Scene * self ) Object *object; Base *base; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); base = scene->base.first; @@ -888,9 +888,7 @@ static PyObject *Scene_getActiveObject(BPy_Scene *self) PyObject *pyob; Object *ob; - if (!scene) - return EXPP_ReturnPyObjError(PyExc_RuntimeError, - "Blender Scene was deleted!"); + SCENE_DEL_CHECK_PY(self); ob = ((scene->basact) ? (scene->basact->object) : 0); @@ -904,7 +902,7 @@ static PyObject *Scene_getActiveObject(BPy_Scene *self) return pyob; } - return EXPP_incr_ret(Py_None); /* no active object */ + Py_RETURN_NONE; /* no active object */ } /*-----------------------Scene.getCurrentCamera()------------------------*/ @@ -914,9 +912,7 @@ static PyObject *Scene_getCurrentCamera( BPy_Scene * self ) PyObject *pyob; Scene *scene = self->scene; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); cam_obj = scene->camera; @@ -928,8 +924,7 @@ static PyObject *Scene_getCurrentCamera( BPy_Scene * self ) return pyob; } - Py_INCREF( Py_None ); /* none found */ - return Py_None; + Py_RETURN_NONE; /* none found */ } /*-----------------------Scene.setCurrentCamera()------------------------*/ @@ -939,9 +934,7 @@ static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args ) BPy_Object *cam_obj; Scene *scene = self->scene; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "O!", &Object_Type, &cam_obj ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -961,26 +954,19 @@ static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args ) /* XXX copy_view3d_lock(REDRAW) prints "bad call to addqueue: 0 (18, 1)". * The same happens in bpython. */ - Py_INCREF( Py_None ); - return Py_None; + Py_RETURN_NONE; } /*-----------------------Scene.getRenderingContext()---------------------*/ static PyObject *Scene_getRenderingContext( BPy_Scene * self ) { - if( !self->scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); - + SCENE_DEL_CHECK_PY(self); return RenderData_CreatePyObject( self->scene ); } static PyObject *Scene_getRadiosityContext( BPy_Scene * self ) { - if( !self->scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); - + SCENE_DEL_CHECK_PY(self); return Radio_CreatePyObject( self->scene ); } @@ -990,9 +976,7 @@ static PyObject *Scene_addScriptLink( BPy_Scene * self, PyObject * args ) Scene *scene = self->scene; ScriptLink *slink = NULL; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); slink = &( scene )->scriptlink; @@ -1005,9 +989,7 @@ static PyObject *Scene_clearScriptLinks( BPy_Scene * self, PyObject * args ) Scene *scene = self->scene; ScriptLink *slink = NULL; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); slink = &( scene )->scriptlink; @@ -1021,9 +1003,7 @@ static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * args ) ScriptLink *slink = NULL; PyObject *ret = NULL; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); slink = &( scene )->scriptlink; @@ -1037,14 +1017,11 @@ static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * args ) static PyObject *Scene_play( BPy_Scene * self, PyObject * args ) { - Scene *scene = self->scene; int mode = 0, win = SPACE_VIEW3D; PyObject *ret = NULL; ScrArea *sa = NULL, *oldsa = curarea; - if( !scene ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" ); + SCENE_DEL_CHECK_PY(self); if( !PyArg_ParseTuple( args, "|ii", &mode, &win ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -1098,10 +1075,7 @@ static PyObject *Scene_getTimeLine( BPy_Scene *self ) { BPy_TimeLine *tm; - if( !(self->scene) ) - return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender scene was deleted!" ); - + SCENE_DEL_CHECK_PY(self); tm= (BPy_TimeLine *) PyObject_NEW (BPy_TimeLine, &TimeLine_Type); if (!tm) @@ -1113,13 +1087,11 @@ static PyObject *Scene_getTimeLine( BPy_Scene *self ) return (PyObject *)tm; } - - -static PyObject *Scene_getObjects( BPy_Scene *self ) +/* accessed from scn.objects */ +static PyObject *Scene_getObjects( BPy_Scene *self) { - BPy_SceneObSeq *seq = PyObject_NEW( BPy_SceneObSeq, &SceneObSeq_Type); - seq->bpyscene = self; Py_INCREF(self); - return (PyObject *)seq; + SCENE_DEL_CHECK_PY(self); + return SceneObSeq_CreatePyObject(self, NULL, 0); } /************************************************************************ @@ -1131,13 +1103,83 @@ static PyObject *Scene_getObjects( BPy_Scene *self ) * create a thin wrapper for the scenes objects */ -static PyObject *SceneObSeq_CreatePyObject( Scene *scene, int i ) +/* accessed from scn.objects.selected or scn.objects.context */ +static PyObject *SceneObSeq_getObjects( BPy_SceneObSeq *self, void *mode) +{ + SCENE_DEL_CHECK_PY(self->bpyscene); + return SceneObSeq_CreatePyObject(self->bpyscene, NULL, (int)((long)mode)); +} + + +static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode ) +{ + BPy_SceneObSeq *seq = PyObject_NEW( BPy_SceneObSeq, &SceneObSeq_Type); + seq->bpyscene = self; Py_INCREF(self); + seq->iter = iter; + seq->mode = mode; + return (PyObject *)seq; +} + +static int SceneObSeq_len( BPy_SceneObSeq * self ) +{ + Scene *scene= self->bpyscene->scene; + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode == 0) /* all obejcts */ + return BLI_countlist( &( scene->base ) ); + else if (self->mode == 1) { /* selected obejcts */ + int len=0; + Base *base; + for (base= scene->base.first; base; base= base->next) { + if (base->flag & SELECT) { + len++; + } + } + return len; + } else if (self->mode == 2) { /* user context */ + int len=0; + Base *base; + + if( G.vd == NULL ) /* No 3d view has been initialized yet, simply return an empty list */ + return 0; + + for (base= scene->base.first; base; base= base->next) { + if ((base->flag & SELECT) && (base->lay & G.vd->lay)) { + len++; + } + } + } + /*should never run this */ + return 0; +} + +/* + * retrive a single Object from somewhere in the Object list + */ + +static PyObject *SceneObSeq_item( BPy_SceneObSeq * self, int i ) { int index=0; PyObject *bpy_obj; - Base *base; + Base *base= NULL; + Scene *scene= self->bpyscene->scene; - for (base= scene->base.first; base&& i!=index; base= base->next, index++) {} + SCENE_DEL_CHECK_PY(self->bpyscene); + + /* objects */ + if (self->mode==0) + for (base= scene->base.first; base && i!=index; base= base->next, index++) {} + /* selected */ + else if (self->mode==1) + for (base= scene->base.first; base && i!=index; base= base->next) + if (base->flag & SELECT) + index++; + /* context */ + else if (self->mode==2) + if (G.vd) + for (base= scene->base.first; base && i!=index; base= base->next) + if ((base->flag & SELECT) && (base->lay & G.vd->lay)) + index++; if (!(base)) return EXPP_ReturnPyObjError( PyExc_IndexError, @@ -1152,20 +1194,6 @@ static PyObject *SceneObSeq_CreatePyObject( Scene *scene, int i ) return (PyObject *)bpy_obj; } -static int SceneObSeq_len( BPy_SceneObSeq * self ) -{ - return BLI_countlist( &( self->bpyscene->scene->base ) ); -} - -/* - * retrive a single MGroupOb from somewhere in the GroupObex list - */ - -static PyObject *SceneObSeq_item( BPy_SceneObSeq * self, int i ) -{ - return SceneObSeq_CreatePyObject( self->bpyscene->scene, i ); -} - static PySequenceMethods SceneObSeq_as_sequence = { ( inquiry ) SceneObSeq_len, /* sq_length */ ( binaryfunc ) 0, /* sq_concat */ @@ -1190,8 +1218,29 @@ static PySequenceMethods SceneObSeq_as_sequence = { static PyObject *SceneObSeq_getIter( BPy_SceneObSeq * self ) { - self->iter = self->bpyscene->scene->base.first; - return EXPP_incr_ret ( (PyObject *) self ); + /* we need to get the first base, but for selected context we may need to advance + to the first selected or first conext base */ + Base *base= self->bpyscene->scene->base.first; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode==1) /* selected */ + while (base && !(base->flag & SELECT)) + base= base->next; + else if (self->mode==2) { /* context */ + if (!G.vd) + base= NULL; /* will never iterate if we have no */ + else + while (base && !((base->flag & SELECT) && (base->lay & G.vd->lay))) + base= base->next; + } + /* create a new iterator if were alredy using this one */ + if (self->iter==NULL) { + self->iter = base; + return EXPP_incr_ret ( (PyObject *) self ); + } else { + return SceneObSeq_CreatePyObject(self->bpyscene, base, self->mode); + } } /* @@ -1201,23 +1250,41 @@ static PyObject *SceneObSeq_getIter( BPy_SceneObSeq * self ) static PyObject *SceneObSeq_nextIter( BPy_SceneObSeq * self ) { PyObject *object; - if( !(self->iter) || !(self->bpyscene->scene) ) + Base *base; + if( !(self->iter) || !(self->bpyscene->scene) ) { + self->iter= NULL; return EXPP_ReturnPyObjError( PyExc_StopIteration, "iterator at end" ); + } object= Object_CreatePyObject( self->iter->object ); - self->iter= self->iter->next; + base= self->iter->next; + + if (self->mode==1) /* selected */ + while (base && !(base->flag & SELECT)) + base= base->next; + else if (self->mode==2) { /* context */ + if (!G.vd) + base= NULL; /* will never iterate if we have no */ + else + while (base && !((base->flag & SELECT) && (base->lay & G.vd->lay))) + base= base->next; + } + self->iter= base; + return object; } static PyObject *SceneObSeq_add( BPy_SceneObSeq * self, PyObject *pyobj ) -{ - if( !(self->bpyscene->scene) ) - return (EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" )); +{ + SCENE_DEL_CHECK_PY(self->bpyscene); /* this shold eventually replace Scene_link */ + if (self->mode != 0) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot add to objects.selection or objects.context!" )); + return Scene_link(self->bpyscene, pyobj); } @@ -1232,9 +1299,11 @@ static PyObject *SceneObSeq_new( BPy_SceneObSeq * self, PyObject *args ) PyObject *py_data; Scene *scene= self->bpyscene->scene; - if( !(scene) ) - return (EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" )); + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode != 0) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot add new to objects.selection or objects.context!" )); if( !PyArg_ParseTuple( args, "O", &py_data ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, @@ -1368,9 +1437,11 @@ static PyObject *SceneObSeq_remove( BPy_SceneObSeq * self, PyObject *args ) Object *blen_ob; Base *base= NULL; - if( !(self->bpyscene->scene) ) - return (EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Blender Scene was deleted!" )); + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode != 0) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "Cannot add new to objects.selection or objects.context!" )); if( !PyArg_ParseTuple( args, "O!", &Object_Type, &pyobj ) ) return ( EXPP_ReturnPyObjError( PyExc_TypeError, @@ -1394,10 +1465,65 @@ static PyObject *SceneObSeq_remove( BPy_SceneObSeq * self, PyObject *args ) MEM_freeN( base ); self->bpyscene->scene->basact = 0; /* in case the object was selected */ } - return EXPP_incr_ret( Py_None ); + Py_RETURN_NONE; } +PyObject *SceneObSeq_getActive(BPy_SceneObSeq *self) +{ + PyObject *pyob; + Base *base; + + SCENE_DEL_CHECK_PY(self->bpyscene); + + if (self->mode!=0) + return (EXPP_ReturnPyObjError( PyExc_TypeError, + "cannot get active from objects.selected or objects.context" )); + + base= self->bpyscene->scene->basact; + if (!base) + Py_RETURN_NONE; + + pyob = Object_CreatePyObject( base->object ); + + if (!pyob) + return EXPP_ReturnPyObjError(PyExc_MemoryError, + "couldn't create new object wrapper!"); + + return pyob; +} + +static int SceneObSeq_setActive(BPy_SceneObSeq *self, PyObject *value) +{ + Base *base; + + SCENE_DEL_CHECK_INT(self->bpyscene); + + if (self->mode!=0) + return (EXPP_ReturnIntError( PyExc_TypeError, + "cannot set active from objects.selected or objects.context" )); + + if (value==Py_None) { + self->bpyscene->scene->basact= NULL; + return 0; + } + + if (!BPy_Object_Check(value)) + return (EXPP_ReturnIntError( PyExc_ValueError, + "Object or None types can only be assigned to active!" )); + + base = object_in_scene( ((BPy_Object *)value)->object, self->bpyscene->scene ); + + if (!base) + return (EXPP_ReturnIntError( PyExc_ValueError, + "cannot assign an active object outside the scene." )); + + self->bpyscene->scene->basact= base; + return 0; +} + + + static struct PyMethodDef BPy_SceneObSeq_methods[] = { {"add", (PyCFunction)SceneObSeq_add, METH_VARARGS, "add object to the scene"}, @@ -1420,6 +1546,48 @@ static void SceneObSeq_dealloc( BPy_SceneObSeq * self ) PyObject_DEL( self ); } +static int SceneObSeq_compare( BPy_SceneObSeq * a, BPy_SceneObSeq * b ) +{ + Scene *pa = a->bpyscene->scene, *pb = b->bpyscene->scene; + return ( pa == pb && a->mode == b->mode) ? 0 : -1; +} + +/* + * repr function + * callback functions building meaninful string to representations + */ +static PyObject *SceneObSeq_repr( BPy_SceneObSeq * self ) +{ + if( !(self->bpyscene->scene) ) + return PyString_FromFormat( "[Scene ObjectSeq Removed]" ); + else if (self->mode==1) + return PyString_FromFormat( "[Scene ObjectSeq Selected \"%s\"]", + self->bpyscene->scene->id.name + 2 ); + else if (self->mode==2) + return PyString_FromFormat( "[Scene ObjectSeq Context \"%s\"]", + self->bpyscene->scene->id.name + 2 ); + + /*self->mode==0*/ + return PyString_FromFormat( "[Scene ObjectSeq \"%s\"]", + self->bpyscene->scene->id.name + 2 ); +} + +static PyGetSetDef SceneObSeq_getseters[] = { + {"selected", + (getter)SceneObSeq_getObjects, (setter)NULL, + "sequence of selected objects", + (void *)1}, + {"context", + (getter)SceneObSeq_getObjects, (setter)NULL, + "sequence of user context objects", + (void *)2}, + {"active", + (getter)SceneObSeq_getActive, (setter)SceneObSeq_setActive, + "active object", + NULL}, + {NULL,NULL,NULL,NULL,NULL} /* Sentinel */ +}; + /*****************************************************************************/ /* Python SceneObSeq_Type structure definition: */ /*****************************************************************************/ @@ -1437,8 +1605,8 @@ PyTypeObject SceneObSeq_Type = { NULL, /* printfunc tp_print; */ NULL, /* getattrfunc tp_getattr; */ NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - NULL, /* reprfunc tp_repr; */ + ( cmpfunc ) SceneObSeq_compare, /* cmpfunc tp_compare; */ + ( reprfunc ) SceneObSeq_repr, /* reprfunc tp_repr; */ /* Method suites for standard classes */ @@ -1483,7 +1651,7 @@ PyTypeObject SceneObSeq_Type = { /*** Attribute descriptor and subclassing stuff ***/ BPy_SceneObSeq_methods, /* struct PyMethodDef *tp_methods; */ NULL, /* struct PyMemberDef *tp_members; */ - NULL, /* struct PyGetSetDef *tp_getset; */ + SceneObSeq_getseters, /* struct PyGetSetDef *tp_getset; */ NULL, /* struct _typeobject *tp_base; */ NULL, /* PyObject *tp_dict; */ NULL, /* descrgetfunc tp_descr_get; */ diff --git a/source/blender/python/api2_2x/Scene.h b/source/blender/python/api2_2x/Scene.h index 6967a569859..bdf0977b075 100644 --- a/source/blender/python/api2_2x/Scene.h +++ b/source/blender/python/api2_2x/Scene.h @@ -57,6 +57,7 @@ typedef struct { PyObject_VAR_HEAD /* required python macro */ BPy_Scene *bpyscene; /* link to the python scene so we can know if its been removed */ Base *iter; /* so we can iterate over the objects */ + int mode; /*0:all objects, 1:selected objects, 2:user context*/ } BPy_SceneObSeq;