-- Fix for the "LIB ERROR: base removed" problem; BPy Object was decrementing

us.id when objects were destroyed but not always incrementing when
   created.  The intent of modifying us.id is to make Python a "user" of the
   data so it persists even when it is deleted from Blenders UI.  The original
   commit was unintentional but Ton thought the idea was OK.
This commit is contained in:
Ken Hughes 2005-11-17 18:35:11 +00:00
parent f3c9dce8e3
commit 32c91c897b
2 changed files with 67 additions and 83 deletions

@ -113,7 +113,7 @@ struct rctf;
/*****************************************************************************/ /*****************************************************************************/
static PyObject *M_Object_New( PyObject * self, PyObject * args ); static PyObject *M_Object_New( PyObject * self, PyObject * args );
PyObject *M_Object_Get( PyObject * self, PyObject * args ); PyObject *M_Object_Get( PyObject * self, PyObject * args );
static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args ); static PyObject *M_Object_GetSelected( PyObject * self );
/* HELPER FUNCTION FOR PARENTING */ /* HELPER FUNCTION FOR PARENTING */
static PyObject *internal_makeParent(Object *parent, PyObject *py_child, int partype, int noninverse, int fast, int v1, int v2, int v3); static PyObject *internal_makeParent(Object *parent, PyObject *py_child, int partype, int noninverse, int fast, int v1, int v2, int v3);
@ -147,7 +147,7 @@ struct PyMethodDef M_Object_methods[] = {
M_Object_New_doc}, M_Object_New_doc},
{"Get", ( PyCFunction ) M_Object_Get, METH_VARARGS, {"Get", ( PyCFunction ) M_Object_Get, METH_VARARGS,
M_Object_Get_doc}, M_Object_Get_doc},
{"GetSelected", ( PyCFunction ) M_Object_GetSelected, METH_VARARGS, {"GetSelected", ( PyCFunction ) M_Object_GetSelected, METH_NOARGS,
M_Object_GetSelected_doc}, M_Object_GetSelected_doc},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
@ -169,13 +169,13 @@ static PyObject *Object_getDrawType( BPy_Object * self );
static PyObject *Object_getEuler( BPy_Object * self ); static PyObject *Object_getEuler( BPy_Object * self );
static PyObject *Object_getInverseMatrix( BPy_Object * self ); static PyObject *Object_getInverseMatrix( BPy_Object * self );
static PyObject *Object_getIpo( BPy_Object * self ); static PyObject *Object_getIpo( BPy_Object * self );
static PyObject *Object_getLocation( BPy_Object * self, PyObject * args ); static PyObject *Object_getLocation( BPy_Object * self );
static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args ); static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args );
static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args ); static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args );
static PyObject *Object_getName( BPy_Object * self ); static PyObject *Object_getName( BPy_Object * self );
static PyObject *Object_getParent( BPy_Object * self ); static PyObject *Object_getParent( BPy_Object * self );
static PyObject *Object_getParentBoneName( BPy_Object * self ); static PyObject *Object_getParentBoneName( BPy_Object * self );
static PyObject *Object_getSize( BPy_Object * self, PyObject * args ); static PyObject *Object_getSize( BPy_Object * self );
static PyObject *Object_getTimeOffset( BPy_Object * self ); static PyObject *Object_getTimeOffset( BPy_Object * self );
static PyObject *Object_getTracked( BPy_Object * self ); static PyObject *Object_getTracked( BPy_Object * self );
static PyObject *Object_getType( BPy_Object * self ); static PyObject *Object_getType( BPy_Object * self );
@ -187,7 +187,7 @@ static PyObject *Object_link( BPy_Object * self, PyObject * args );
static PyObject *Object_makeParent( BPy_Object * self, PyObject * args ); static PyObject *Object_makeParent( BPy_Object * self, PyObject * args );
static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args ); static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args );
static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args ); static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args );
static PyObject *Object_materialUsage( BPy_Object * self, PyObject * args ); static PyObject *Object_materialUsage( void );
static PyObject *Object_getDupliVerts ( BPy_Object * self ); static PyObject *Object_getDupliVerts ( BPy_Object * self );
static PyObject *Object_getEffects( BPy_Object * self ); static PyObject *Object_getEffects( BPy_Object * self );
static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args ); static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args );
@ -302,7 +302,7 @@ If 'name_only' is nonzero or True, only the name of the datablock is returned"},
{"getInverseMatrix", ( PyCFunction ) Object_getInverseMatrix, {"getInverseMatrix", ( PyCFunction ) Object_getInverseMatrix,
METH_NOARGS, METH_NOARGS,
"Returns the object's inverse matrix"}, "Returns the object's inverse matrix"},
{"getLocation", ( PyCFunction ) Object_getLocation, METH_VARARGS, {"getLocation", ( PyCFunction ) Object_getLocation, METH_NOARGS,
"Returns the object's location (x, y, z)"}, "Returns the object's location (x, y, z)"},
{"getMaterials", ( PyCFunction ) Object_getMaterials, METH_VARARGS, {"getMaterials", ( PyCFunction ) Object_getMaterials, METH_VARARGS,
"(i = 0) - Returns list of materials assigned to the object.\n\ "(i = 0) - Returns list of materials assigned to the object.\n\
@ -467,7 +467,7 @@ mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
fast:\n\t0: update scene hierarchy automatically\n\t\ fast:\n\t0: update scene hierarchy automatically\n\t\
don't update scene hierarchy (faster). In this case, you must\n\t\ don't update scene hierarchy (faster). In this case, you must\n\t\
explicitely update the Scene hierarchy."}, explicitely update the Scene hierarchy."},
{"materialUsage", ( PyCFunction ) Object_materialUsage, METH_VARARGS, {"materialUsage", ( PyCFunction ) Object_materialUsage, METH_NOARGS,
"Determines the way the material is used and returns status.\n\ "Determines the way the material is used and returns status.\n\
Possible arguments (provide as strings):\n\ Possible arguments (provide as strings):\n\
\tData: Materials assigned to the object's data are shown. (default)\n\ \tData: Materials assigned to the object's data are shown. (default)\n\
@ -594,16 +594,13 @@ PyTypeObject Object_Type = {
PyObject *M_Object_New( PyObject * self, PyObject * args ) PyObject *M_Object_New( PyObject * self, PyObject * args )
{ {
struct Object *object; struct Object *object;
BPy_Object *blen_object;
int type; int type;
char *str_type; char *str_type;
char *name = NULL; char *name = NULL;
if( !PyArg_ParseTuple( args, "s|s", &str_type, &name ) ) { if( !PyArg_ParseTuple( args, "s|s", &str_type, &name ) )
EXPP_ReturnPyObjError( PyExc_TypeError, return EXPP_ReturnPyObjError( PyExc_TypeError,
"string expected as argument" ); "string expected as argument" );
return ( NULL );
}
if( strcmp( str_type, "Armature" ) == 0 ) if( strcmp( str_type, "Armature" ) == 0 )
type = OB_ARMATURE; type = OB_ARMATURE;
@ -691,12 +688,11 @@ PyObject *M_Object_New( PyObject * self, PyObject * args )
object->data = NULL; object->data = NULL;
/* Create a Python object from it. */ /* user count be incremented in Object_CreatePyObject */
blen_object = object->id.us = 0;
( BPy_Object * ) PyObject_NEW( BPy_Object, &Object_Type );
blen_object->object = object;
return ( ( PyObject * ) blen_object ); /* Create a Python object from it. */
return Object_CreatePyObject( object );
} }
/*****************************************************************************/ /*****************************************************************************/
@ -706,7 +702,7 @@ PyObject *M_Object_New( PyObject * self, PyObject * args )
PyObject *M_Object_Get( PyObject * self, PyObject * args ) PyObject *M_Object_Get( PyObject * self, PyObject * args )
{ {
struct Object *object; struct Object *object;
BPy_Object *blen_object; PyObject *blen_object;
char *name = NULL; char *name = NULL;
PyArg_ParseTuple( args, "|s", &name ); PyArg_ParseTuple( args, "|s", &name );
@ -714,18 +710,12 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
if( name != NULL ) { if( name != NULL ) {
object = GetObjectByName( name ); object = GetObjectByName( name );
if( object == NULL ) {
/* No object exists with the name specified in the argument name. */ /* No object exists with the name specified in the argument name. */
return ( EXPP_ReturnPyObjError( PyExc_AttributeError, if( !object )
"Unknown object specified." ) ); return EXPP_ReturnPyObjError( PyExc_AttributeError,
} "Unknown object specified." );
blen_object =
( BPy_Object * ) PyObject_NEW( BPy_Object,
&Object_Type );
blen_object->object = object;
object->id.us++;
return ( ( PyObject * ) blen_object ); return Object_CreatePyObject( object );
} else { } else {
/* No argument has been given. Return a list of all objects. */ /* No argument has been given. Return a list of all objects. */
PyObject *obj_list; PyObject *obj_list;
@ -734,27 +724,24 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
obj_list = PyList_New( BLI_countlist( &( G.main->object ) ) ); obj_list = PyList_New( BLI_countlist( &( G.main->object ) ) );
if( obj_list == NULL ) { if( !obj_list )
return ( EXPP_ReturnPyObjError( PyExc_SystemError, return EXPP_ReturnPyObjError( PyExc_SystemError,
"List creation failed." ) ); "List creation failed." );
}
link = G.main->object.first; link = G.main->object.first;
index = 0; index = 0;
while( link ) { while( link ) {
object = ( Object * ) link; object = ( Object * ) link;
blen_object = blen_object = Object_CreatePyObject( object );
( BPy_Object * ) PyObject_NEW( BPy_Object, if( !blen_object ) {
&Object_Type ); Py_DECREF( obj_list );
blen_object->object = object; Py_RETURN_NONE;
object->id.us++; }
PyList_SetItem( obj_list, index, blen_object );
PyList_SetItem( obj_list, index,
( PyObject * ) blen_object );
index++; index++;
link = link->next; link = link->next;
} }
return ( obj_list ); return obj_list;
} }
} }
@ -762,9 +749,9 @@ PyObject *M_Object_Get( PyObject * self, PyObject * args )
/* Function: M_Object_GetSelected */ /* Function: M_Object_GetSelected */
/* Python equivalent: Blender.Object.GetSelected */ /* Python equivalent: Blender.Object.GetSelected */
/*****************************************************************************/ /*****************************************************************************/
static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args ) static PyObject *M_Object_GetSelected( PyObject * self )
{ {
BPy_Object *blen_object; PyObject *blen_object;
PyObject *list; PyObject *list;
Base *base_iter; Base *base_iter;
@ -777,40 +764,34 @@ static PyObject *M_Object_GetSelected( PyObject * self, PyObject * args )
if( ( G.scene->basact ) && if( ( G.scene->basact ) &&
( ( G.scene->basact->flag & SELECT ) && ( ( G.scene->basact->flag & SELECT ) &&
( G.scene->basact->lay & G.vd->lay ) ) ) { ( G.scene->basact->lay & G.vd->lay ) ) ) {
/* Active object is first in the list. */ /* Active object is first in the list. */
blen_object = blen_object = Object_CreatePyObject( G.scene->basact->object );
( BPy_Object * ) PyObject_NEW( BPy_Object, if( !blen_object ) {
&Object_Type );
if( blen_object == NULL ) {
Py_DECREF( list ); Py_DECREF( list );
Py_INCREF( Py_None ); Py_RETURN_NONE;
return ( Py_None );
} }
blen_object->object = G.scene->basact->object; PyList_Append( list, blen_object );
PyList_Append( list, ( PyObject * ) blen_object );
Py_DECREF( blen_object ); Py_DECREF( blen_object );
} }
base_iter = G.scene->base.first; base_iter = G.scene->base.first;
while( base_iter ) { while( base_iter ) {
if( ( ( base_iter->flag & SELECT ) && if( ( ( base_iter->flag & SELECT ) &&
( base_iter->lay & G.vd->lay ) ) && ( base_iter->lay & G.vd->lay ) ) &&
( base_iter != G.scene->basact ) ) { ( base_iter != G.scene->basact ) ) {
blen_object =
( BPy_Object * ) PyObject_NEW( BPy_Object, blen_object = Object_CreatePyObject( base_iter->object );
&Object_Type ); if( !blen_object ) {
if( blen_object == NULL ) {
Py_DECREF( list ); Py_DECREF( list );
Py_INCREF( Py_None ); Py_RETURN_NONE;
return ( Py_None );
} }
blen_object->object = base_iter->object; PyList_Append( list, blen_object );
PyList_Append( list, ( PyObject * ) blen_object );
Py_DECREF( blen_object ); Py_DECREF( blen_object );
} }
base_iter = base_iter->next; base_iter = base_iter->next;
} }
return ( list ); return list;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -1177,7 +1158,7 @@ static PyObject *Object_getIpo( BPy_Object * self )
return Ipo_CreatePyObject( ipo ); return Ipo_CreatePyObject( ipo );
} }
static PyObject *Object_getLocation( BPy_Object * self, PyObject * args ) static PyObject *Object_getLocation( BPy_Object * self )
{ {
PyObject *attr = Py_BuildValue( "fff", PyObject *attr = Py_BuildValue( "fff",
self->object->loc[0], self->object->loc[0],
@ -1277,7 +1258,7 @@ static PyObject *Object_getParentBoneName( BPy_Object * self )
"Failed to get parent bone name" ) ); "Failed to get parent bone name" ) );
} }
static PyObject *Object_getSize( BPy_Object * self, PyObject * args ) static PyObject *Object_getSize( BPy_Object * self )
{ {
PyObject *attr = Py_BuildValue( "fff", PyObject *attr = Py_BuildValue( "fff",
self->object->size[0], self->object->size[0],
@ -1350,7 +1331,6 @@ static PyObject *Object_getType( BPy_Object * self )
} }
} }
static PyObject *Object_getBoundBox( BPy_Object * self ) static PyObject *Object_getBoundBox( BPy_Object * self )
{ {
int i; int i;
@ -1482,7 +1462,7 @@ static PyObject *Object_link( BPy_Object * self, PyObject * args )
} }
if( ArmatureObject_Check( py_data ) ) if( ArmatureObject_Check( py_data ) )
data = ( void * ) PyArmature_AsArmature((BPy_Armature*)py_data); data = ( void * ) PyArmature_AsArmature((BPy_Armature*)py_data);
if( Camera_CheckPyObject( py_data ) ) else if( Camera_CheckPyObject( py_data ) )
data = ( void * ) Camera_FromPyObject( py_data ); data = ( void * ) Camera_FromPyObject( py_data );
else if( Lamp_CheckPyObject( py_data ) ) else if( Lamp_CheckPyObject( py_data ) )
data = ( void * ) Lamp_FromPyObject( py_data ); data = ( void * ) Lamp_FromPyObject( py_data );
@ -1823,10 +1803,10 @@ static PyObject *internal_makeParent(Object *parent, PyObject *py_child,
return EXPP_incr_ret( Py_None ); return EXPP_incr_ret( Py_None );
} }
static PyObject *Object_materialUsage( BPy_Object * self, PyObject * args ) static PyObject *Object_materialUsage( void )
{ {
return ( EXPP_ReturnPyObjError( PyExc_NotImplementedError, return EXPP_ReturnPyObjError( PyExc_NotImplementedError,
"materialUsage: not yet implemented" ) ); "materialUsage: not yet implemented" );
} }
static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args ) static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args )
@ -2594,7 +2574,7 @@ static PyObject *Object_getEffects( BPy_Object * self )
eff = self->object->effect.first; eff = self->object->effect.first;
while( eff ) { while( eff ) {
PyList_Append( effect_list, EffectCreatePyObject( eff ) ); PyList_Append( effect_list, EffectCreatePyObject( eff, self->object ) );
eff = eff->next; eff = eff->next;
} }
return effect_list; return effect_list;
@ -2610,16 +2590,15 @@ PyObject *Object_CreatePyObject( struct Object * obj )
BPy_Object *blen_object; BPy_Object *blen_object;
if( !obj ) if( !obj )
return EXPP_incr_ret( Py_None ); Py_RETURN_NONE;
blen_object = blen_object =
( BPy_Object * ) PyObject_NEW( BPy_Object, &Object_Type ); ( BPy_Object * ) PyObject_NEW( BPy_Object, &Object_Type );
if( blen_object == NULL ) { if( blen_object ) {
return ( NULL ); blen_object->object = obj;
obj->id.us++;
} }
blen_object->object = obj;
obj->id.us++;
return ( ( PyObject * ) blen_object ); return ( ( PyObject * ) blen_object );
} }
@ -2778,11 +2757,9 @@ static PyObject *Object_getAttr( BPy_Object * obj, char *name )
} }
if( StringEqual( name, "parent" ) ) { if( StringEqual( name, "parent" ) ) {
if( object->parent ) if( object->parent )
return ( Object_CreatePyObject( object->parent ) ); return Object_CreatePyObject( object->parent );
else { else
Py_INCREF( Py_None ); Py_RETURN_NONE;
return ( Py_None );
}
} }
if( StringEqual( name, "parentbonename" ) ) { if( StringEqual( name, "parentbonename" ) ) {
if( object->parent && object->parsubstr[0] ) if( object->parent && object->parsubstr[0] )
@ -2794,7 +2771,7 @@ static PyObject *Object_getAttr( BPy_Object * obj, char *name )
} }
if( StringEqual( name, "track" ) ) if( StringEqual( name, "track" ) )
return ( Object_CreatePyObject( object->track ) ); return Object_CreatePyObject( object->track );
if( StringEqual( name, "data" ) ) { if( StringEqual( name, "data" ) ) {
PyObject *getdata, *tuple = PyTuple_New(0); PyObject *getdata, *tuple = PyTuple_New(0);
@ -2864,6 +2841,8 @@ static PyObject *Object_getAttr( BPy_Object * obj, char *name )
} }
if( StringEqual( name, "effects" ) ) if( StringEqual( name, "effects" ) )
return Object_getEffects( obj ); return Object_getEffects( obj );
if( StringEqual( name, "users" ) )
return PyInt_FromLong( obj->object->id.us );
/* not an attribute, search the methods table */ /* not an attribute, search the methods table */
return Py_FindMethod( BPy_Object_methods, ( PyObject * ) obj, name ); return Py_FindMethod( BPy_Object_methods, ( PyObject * ) obj, name );

@ -4,6 +4,9 @@
The Blender.Object submodule The Blender.Object submodule
B{New}: B{New}:
- Objects now increment the Blender user count when they are created and
decremented it when they are destroyed. This means Python scripts can
keep the object "alive" if it is deleted in the Blender GUI.
- L{Object.getData} now accepts two optional bool keyword argument to - L{Object.getData} now accepts two optional bool keyword argument to
define (1) if the user wants the data object or just its name define (1) if the user wants the data object or just its name
and (2) if a mesh object should use NMesh or Mesh. and (2) if a mesh object should use NMesh or Mesh.
@ -187,6 +190,8 @@ class Object:
@ivar sel: The selection state of the object in the current scene, 1 is selected, 0 is unselected. @ivar sel: The selection state of the object in the current scene, 1 is selected, 0 is unselected.
@ivar effects: The list of particle effects associated with the object. (Read-only) @ivar effects: The list of particle effects associated with the object. (Read-only)
@ivar parentbonename: The string name of the parent bone. @ivar parentbonename: The string name of the parent bone.
@ivar users: The number of users of the object. Read-only.
@type users: int
""" """
def buildParts(): def buildParts():
@ -1233,4 +1238,4 @@ class Property:
""" """
Get the type for this property. Get the type for this property.
@rtype: string @rtype: string
""" """