Python API

----------
Support for new bpy.libraries module, which is being proposed to replace
the Blender.Library module.
This commit is contained in:
Ken Hughes
2007-03-21 02:23:28 +00:00
parent a6db9c5949
commit 3a834803ef
13 changed files with 1020 additions and 35 deletions

View File

@@ -159,6 +159,7 @@ void BPY_start_python( int argc, char **argv )
static int argc_copy = 0;
static char **argv_copy = NULL;
int first_time = argc;
char *str, version[16];
/* we keep a copy of the values of argc and argv so that the game engine
* can call BPY_start_python(0, NULL) whenever a game ends, without having
@@ -178,8 +179,8 @@ void BPY_start_python( int argc, char **argv )
* print an error if not found. See init_syspath() for the
* rest of our init msgs.
*/
// Py_GetVersion() returns a ptr to astatic string
printf( "Compiled with Python version %.5s.\n", Py_GetVersion() );
printf( "Compiled with Python version %s.\n", PY_VERSION );
//Initialize the TOP-LEVEL modules
PyImport_ExtendInittab(BPy_Inittab_Modules);

View File

@@ -964,7 +964,7 @@ void M_Blender_Init(void)
PyDict_SetItemString(dict, "Key", Key_Init());
PyDict_SetItemString(dict, "Lamp", Lamp_Init());
PyDict_SetItemString(dict, "Lattice", Lattice_Init());
PyDict_SetItemString(dict, "Library", Library_Init());
PyDict_SetItemString(dict, "Library", oldLibrary_Init());
PyDict_SetItemString(dict, "Material", Material_Init());
PyDict_SetItemString(dict, "Mesh", Mesh_Init());
PyDict_SetItemString(dict, "Metaball", Metaball_Init());

View File

@@ -28,11 +28,15 @@
*
* This is a new part of Blender.
*
* Contributor(s): Willian P. Germano
* Contributor(s): Willian P. Germano, Campbell Barton, Ken Hughes
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
/************************************************************/
/* Original library module code */
/************************************************************/
#include <Python.h>
#include "DNA_curve_types.h"
@@ -64,14 +68,13 @@ static PyObject *M_Library_Close( PyObject * self );
static PyObject *M_Library_GetName( PyObject * self );
static PyObject *M_Library_Update( PyObject * self );
static PyObject *M_Library_Datablocks( PyObject * self, PyObject * args );
static PyObject *M_Library_Load( PyObject * self, PyObject * args );
static PyObject *oldM_Library_Load( PyObject * self, PyObject * args );
static PyObject *M_Library_LinkableGroups( PyObject * self );
static PyObject *M_Library_LinkedLibs( PyObject * self );
PyObject *Library_Init( void );
void EXPP_Library_Close( void );
/**
* Module doc strings.
*/
@@ -119,7 +122,7 @@ static char Library_LinkedLibs_doc[] =
/**
* Python method structure definition for Blender.Library submodule.
*/
struct PyMethodDef M_Library_methods[] = {
struct PyMethodDef oldM_Library_methods[] = {
{"Open", M_Library_Open, METH_VARARGS, Library_Open_doc},
{"Close", ( PyCFunction ) M_Library_Close, METH_NOARGS,
Library_Close_doc},
@@ -129,7 +132,7 @@ struct PyMethodDef M_Library_methods[] = {
Library_Update_doc},
{"Datablocks", M_Library_Datablocks, METH_VARARGS,
Library_Datablocks_doc},
{"Load", M_Library_Load, METH_VARARGS, Library_Load_doc},
{"Load", oldM_Library_Load, METH_VARARGS, Library_Load_doc},
{"LinkableGroups", ( PyCFunction ) M_Library_LinkableGroups,
METH_NOARGS, Library_LinkableGroups_doc},
{"LinkedLibs", ( PyCFunction ) M_Library_LinkedLibs,
@@ -144,7 +147,7 @@ struct PyMethodDef M_Library_methods[] = {
* Only one can be open at a time, so this function also closes
* the previously opened file, if any.
*/
PyObject *M_Library_Open( PyObject * self, PyObject * args )
static PyObject *M_Library_Open( PyObject * self, PyObject * args )
{
char *fname = NULL;
char filename[FILE_MAXDIR+FILE_MAXFILE];
@@ -193,7 +196,7 @@ PyObject *M_Library_Open( PyObject * self, PyObject * args )
/**
* Close the current .blend file, if any.
*/
PyObject *M_Library_Close( PyObject * self )
static PyObject *M_Library_Close( PyObject * self )
{
if( bpy_openlib ) {
BLO_blendhandle_close( bpy_openlib );
@@ -228,7 +231,7 @@ void EXPP_Library_Close( void )
/**
* Get the filename of the currently open library file, if any.
*/
PyObject *M_Library_GetName( PyObject * self )
static PyObject *M_Library_GetName( PyObject * self )
{
if( bpy_openlib && bpy_openlibname )
return Py_BuildValue( "s", bpy_openlibname );
@@ -241,7 +244,7 @@ PyObject *M_Library_GetName( PyObject * self )
* Return a list with all items of a given datablock type
* (like 'Object', 'Mesh', etc.) in the open library file.
*/
PyObject *M_Library_Datablocks( PyObject * self, PyObject * args )
static PyObject *M_Library_Datablocks( PyObject * self, PyObject * args )
{
char *name = NULL;
int blocktype = 0;
@@ -288,7 +291,7 @@ PyObject *M_Library_Datablocks( PyObject * self, PyObject * args )
* Return a list with the names of all linkable groups in the
* open library file.
*/
PyObject *M_Library_LinkableGroups( PyObject * self )
static PyObject *M_Library_LinkableGroups( PyObject * self )
{
LinkNode *l = NULL, *names = NULL;
PyObject *list = NULL;
@@ -317,7 +320,7 @@ PyObject *M_Library_LinkableGroups( PyObject * self )
/**
* Return a list with the names of all externally linked libs used in the current Blend file
*/
PyObject *M_Library_LinkedLibs( PyObject * self )
static PyObject *M_Library_LinkedLibs( PyObject * self )
{
int counter = 0;
Library *li;
@@ -335,7 +338,7 @@ PyObject *M_Library_LinkedLibs( PyObject * self )
* Load (append) a given datablock of a given datablock type
* to the current scene.
*/
PyObject *M_Library_Load( PyObject * self, PyObject * args )
static PyObject *oldM_Library_Load( PyObject * self, PyObject * args )
{
char *name = NULL;
char *base = NULL;
@@ -360,9 +363,9 @@ PyObject *M_Library_Load( PyObject * self, PyObject * args )
"no such Blender datablock type" );
if (linked)
BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK);
BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK, G.scene);
else
BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0);
BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0, G.scene);
if( update ) {
M_Library_Update( self );
@@ -394,7 +397,7 @@ PyObject *M_Library_Load( PyObject * self, PyObject * args )
/**
* Update all links and remake displists.
*/
PyObject *M_Library_Update( PyObject * self )
static PyObject *M_Library_Update( PyObject * self )
{ /* code adapted from do_library_append in src/filesel.c: */
Library *lib = NULL;
@@ -425,12 +428,751 @@ PyObject *M_Library_Update( PyObject * self )
* Called by Blender_Init in Blender.c .
* @return the registered submodule.
*/
PyObject *Library_Init( void )
PyObject *oldLibrary_Init( void )
{
PyObject *submod;
submod = Py_InitModule3( "Blender.Library", M_Library_methods,
submod = Py_InitModule3( "Blender.Library", oldM_Library_methods,
M_Library_doc );
return submod;
}
/************************************************************/
/* New library (LibData) module code */
/************************************************************/
#include "Library.h"
/* if this module supercedes the old library module, include these instead */
#if 0
#include "BLI_blenlib.h"
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h" /* for line linked */
#include "BKE_library.h" /* for all_local */
#include "BKE_utildefines.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BLO_readfile.h"
#include "BLI_linklist.h"
#include "Object.h"
#include "gen_utils.h"
#endif
#include "gen_library.h"
/* Helper function */
/*
* Try to open a library, set Python exceptions as necessary if not
* successful. On success, return a valid handle; othewise return NULL.
*/
static BlendHandle *open_library( char *filename, char *longFilename )
{
char globalFilename[FILE_MAX];
BlendHandle *openlib = NULL;
/* get complete file name if necessary */
BLI_strncpy( longFilename, filename, FILE_MAX );
BLI_convertstringcode( longFilename, G.sce, 0 );
/* throw exceptions for wrong file type, cyclic reference */
if( !BLO_has_bfile_extension(longFilename) ) {
PyErr_SetString( PyExc_ValueError, "file not a library" );
return NULL;
}
if( BLI_streq(G.main->name, longFilename) ) {
PyErr_SetString( PyExc_ValueError,
"cannot use current file as library" );
return NULL;
}
/* G.sce = last file loaded, save for UI and restore after opening file */
BLI_strncpy(globalFilename, G.sce, sizeof(globalFilename));
openlib = BLO_blendhandle_from_file( longFilename );
BLI_strncpy(G.sce, globalFilename, sizeof(globalFilename));
/* if failed, set that exception code too */
if( !openlib )
PyErr_SetString( PyExc_IOError, "library not found" );
return openlib;
}
/*
* Create a specific type of LibraryData object. These are used for
* .append() and .link() access, for iterators, and (for Blender Objects)
* for defining "pseudo objects" for scene linking.
*/
static PyObject *CreatePyObject_LibData( int idtype, int kind,
void *name, void *iter, char *filename )
{
BPy_LibraryData *seq = PyObject_NEW( BPy_LibraryData, &LibraryData_Type);
seq->iter = iter; /* the name list (for iterators) */
seq->type = idtype; /* the Blender ID type */
seq->kind = kind; /* used by Blender Objects */
seq->name = name; /* object name, iterator name list, or NULL */
/* save the library name */
BLI_strncpy( seq->filename, filename, strlen(filename)+1 );
return (PyObject *)seq;
}
/*
* Link/append data to the current .blend file, or create a pseudo object
* which can be linked/appended to a scene.
*/
static PyObject *lib_link_or_append( BPy_LibraryData *self, PyObject * args,
int mode )
{
char *name;
/* get the name of the data used wants to append */
if( !PyArg_ParseTuple( args, "s", &name ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected a string" );
/*
* For everything except objects, just add to Blender's DB. For objects,
* create an APPEND or LINK "pseudo object" for the Scene module.
*/
if( self->type != ID_OB )
return LibraryData_importLibData( self, name, 0, NULL );
else {
/*
* If this is already a pseudo object, throw an exception: re-linking
* or re-appending is not allowed
*/
if( self->kind != OTHER )
return EXPP_ReturnPyObjError( PyExc_ValueError,
"object has already been marked for append or link" );
/* otherwise, create a pseudo object ready for appending or linking */
return CreatePyObject_LibData( ID_OB, mode,
BLI_strdupn( name, strlen( name ) ), NULL, self->filename );
}
}
/*
* Perform the actual link or append operation. This procedure is also
* called externally from the Scene module using a "pseudo Object" so we
* can be sure objects get linked to a scene.
*/
PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
int mode, Scene *scene )
{
char longFilename[FILE_MAX];
char *finalName;
BlendHandle *openlib;
Library *lib;
LinkNode *names, *ptr;
ID idtest, *id;
ListBase *lb;
/* try to open the library */
openlib = open_library( self->filename, longFilename );
if( !openlib )
return NULL;
/* find all datablocks for the specified type */
names = BLO_blendhandle_get_datablock_names ( openlib, self->type );
/* now check for a match to the user-specified name */
for( ptr = names; ptr; ptr = ptr->next )
if( strcmp( ptr->link, name ) == 0 ) break;
BLI_linklist_free( names, free );
/* if no match, throw exception */
if( !ptr ) {
BLO_blendhandle_close( openlib );
return EXPP_ReturnPyObjError( PyExc_ValueError,
"library does not contain specified item" );
}
/*
* Figure out what the datablock will be named after it's imported. If
* it's a link, nothing to do. If it's an append, find what it might
* be renamed to.
*/
if( mode == FILE_LINK )
finalName = name;
else { /* for appends, build a fake ID block, then try to dup it */
strncpy( idtest.name+2, name, strlen(name)+1 );
*((short *)&idtest.name) = self->type;
idtest.newid = NULL;
idtest.lib = NULL;
dup_id( NULL, &idtest, self->name );
finalName = idtest.name+2;
}
/* import from the libary */
BLO_script_library_append( openlib, longFilename, name, self->type, mode,
scene );
/*
* locate the library. If this is an append, make the data local. If it
* is link, we need the library for later
*/
for( lib = G.main->library.first; lib; lib = lib->id.next )
if( strcmp( longFilename, lib->name ) == 0 ) {
if( mode != FILE_LINK ) {
all_local( lib );
lib = NULL;
}
break;
}
/* done with library; close it */
BLO_blendhandle_close( openlib );
/* find the base for this type */
lb = wich_libbase( G.main, self->type );
/*
* Search the base for the datablock. For link, lib points to library,
* otherwise it's NULL.
*/
for( id = lb->first; id; id = id->next ) {
if( id->lib == lib && id->name[2]==finalName[0] &&
strcmp(id->name+2, finalName)==0 )
return GetPyObjectFromID( id );
}
/* if we get here, something's really wrong */
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"could not find data after reading from library" );
}
/************************************************************
* Python LibraryData_Type getseters
************************************************************/
/* .append(): make a local copy of the library's data (except for objects) */
static PyObject *LibraryData_getAppend( BPy_LibraryData *self, PyObject * args)
{
return lib_link_or_append( self, args, OBJECT_IS_APPEND );
}
/* .link(): make a link to the library's data (except for objects) */
static PyObject *LibraryData_getLink( BPy_LibraryData *self, PyObject * args)
{
return lib_link_or_append( self, args, OBJECT_IS_LINK );
}
/************************************************************************
* Python LibraryData_Type iterator
************************************************************************/
/* Create and initialize the interator indices */
static PyObject *LibraryData_getIter( BPy_LibraryData * self )
{
char longFilename[FILE_MAX];
BlendHandle *openlib;
LinkNode *names;
/* try to open library */
openlib = open_library( self->filename, longFilename );
/* if failed, return exception */
if( !openlib )
return NULL;
/* find all datablocks for the specified type */
names = BLO_blendhandle_get_datablock_names ( openlib, self->type );
/* close library*/
BLO_blendhandle_close( openlib );
/* build an iterator object for the name list */
return CreatePyObject_LibData( self->type, OTHER, names,
names, self->filename );
}
/* Return next name. */
static PyObject *LibraryData_nextIter( BPy_LibraryData * self )
{
LinkNode *ptr = (LinkNode *)self->iter;
PyObject *ob;
/* if at the end of list, clean up */
if( !ptr ) {
/* If name list is still allocated, free storage. This check is
* necessary since iter.next() can technically be called repeatedly */
if( self->name ) {
BLI_linklist_free( (LinkNode *)self->name, free );
self->name = NULL;
}
return EXPP_ReturnPyObjError( PyExc_StopIteration,
"iterator at end" );
}
/* otherwise, return the next name in the list */
ob = PyString_FromString( ptr->link );
ptr = ptr->next;
self->iter = ptr;
return ob;
}
/************************************************************************
* Python LibraryData_type methods structure
************************************************************************/
static struct PyMethodDef BPy_LibraryData_methods[] = {
{"append", (PyCFunction)LibraryData_getAppend, METH_VARARGS,
"(str) - create new data from library"},
{"link", (PyCFunction)LibraryData_getLink, METH_VARARGS,
"(str) - link data from library"},
{NULL, NULL, 0, NULL}
};
/* Deallocate object and its data */
static void LibraryData_dealloc( BPy_LibraryData * self )
{
if( self->name )
MEM_freeN( self->name );
PyObject_DEL( self );
}
/* Display representation of what Library Data is wrapping */
static PyObject *LibraryData_repr( BPy_LibraryData * self )
{
char *linkstate = "";
char *str;
switch (self->type) {
case ID_OB:
/* objects can be lib data or pseudo objects */
switch( self->kind ) {
case OBJECT_IS_APPEND :
linkstate = ", appended";
break;
case OBJECT_IS_LINK :
linkstate = ", linked";
break;
default:
break;
}
str = "Object";
break;
case ID_SCE:
str = "Scene";
break;
case ID_ME:
str = "Mesh";
break;
case ID_CU:
str = "Curve";
break;
case ID_MB:
str = "Metaball";
break;
case ID_MA:
str = "Material";
break;
case ID_TE:
str = "Texture";
break;
case ID_IM:
str = "Image";
break;
case ID_LT:
str = "Lattice";
break;
case ID_LA:
str = "Lamp";
break;
case ID_CA:
str = "Camera";
break;
case ID_IP:
str = "Ipo";
break;
case ID_WO:
str = "World";
break;
case ID_VF:
str = "Font";
break;
case ID_TXT:
str = "Text";
break;
case ID_SO:
str = "Sound";
break;
case ID_GR:
str = "Group";
break;
case ID_AR:
str = "Armature";
break;
case ID_AC:
str = "Action";
break;
default:
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
"unsupported ID type" );
}
return PyString_FromFormat( "[Library Data (%s%s)]", str, linkstate );
}
PyTypeObject LibraryData_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
0, /* ob_size */
/* For printing, in format "<module>.<name>" */
"Blender LibData", /* char *tp_name; */
sizeof( BPy_LibraryData ), /* int tp_basicsize; */
0, /* tp_itemsize; For allocation */
/* Methods to implement standard operations */
( destructor ) LibraryData_dealloc,/* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
( cmpfunc ) NULL, /* cmpfunc tp_compare; */
( reprfunc ) LibraryData_repr, /* reprfunc tp_repr; */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
NULL, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
NULL, /* richcmpfunc tp_richcompare; */
/*** weak reference enabler ***/
0, /* long tp_weaklistoffset; */
/*** Added in release 2.2 ***/
/* Iterators */
(getiterfunc)LibraryData_getIter, /* getiterfunc tp_iter; */
(iternextfunc)LibraryData_nextIter, /* iternextfunc tp_iternext; */
/*** Attribute descriptor and subclassing stuff ***/
BPy_LibraryData_methods, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
NULL, /* struct PyGetSetDef *tp_getset; */
NULL, /* struct _typeobject *tp_base; */
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
NULL, /* descrsetfunc tp_descr_set; */
0, /* long tp_dictoffset; */
NULL, /* initproc tp_init; */
NULL, /* allocfunc tp_alloc; */
NULL, /* newfunc tp_new; */
/* Low-level free-memory routine */
NULL, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
/* method resolution order */
NULL, /* PyObject *tp_mro; */
NULL, /* PyObject *tp_cache; */
NULL, /* PyObject *tp_subclasses; */
NULL, /* PyObject *tp_weaklist; */
NULL
};
/*
* Create a LibraryData object for a specific type of Blender Group (ID_OB,
* ID_MA, etc). These can then be used to link or append the data.
*/
static PyObject *LibraryData_CreatePyObject( BPy_Library *self, void *mode )
{
return CreatePyObject_LibData( (int)mode, OTHER, NULL, NULL,
self->filename );
}
/************************************************************
* Python Library_Type getseters
************************************************************/
/*
* Return the library's filename.
*/
static PyObject *Library_getFilename( BPy_Library * self )
{
return PyString_FromString( self->filename );
}
/*
* Set/change the library's filename.
*/
static int Library_setFilename( BPy_Library * self, PyObject * args )
{
char *filename = PyString_AsString( args );
if( !filename )
return EXPP_ReturnIntError( PyExc_TypeError, "expected a string" );
BLI_strncpy( self->filename, filename, sizeof(self->filename) );
return 0;
}
/************************************************************************
* Python Library_type attributes get/set structure
************************************************************************/
static PyGetSetDef Library_getseters[] = {
{"filename",
(getter)Library_getFilename, (setter)Library_setFilename,
"library filename",
NULL},
{"objects",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"objects from the library",
(void *)ID_OB},
{"scenes",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"scenes from the library",
(void *)ID_SCE},
{"meshes",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"meshes from the library",
(void *)ID_ME},
{"curves",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"curves from the library",
(void *)ID_CU},
{"metaballs",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"metaballs from the library",
(void *)ID_MB},
{"lattices",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"lattices from the library",
(void *)ID_LT},
{"lamps",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"lamps from the library",
(void *)ID_LA},
{"cameras",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"cameras from the library",
(void *)ID_CA},
{"materials",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"objects from the library",
(void *)ID_MA},
{"textures",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"textures from the library",
(void *)ID_TE},
{"images",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"images from the library",
(void *)ID_IM},
{"ipos",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"ipos from the library",
(void *)ID_IP},
{"worlds",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"worlds from the library",
(void *)ID_WO},
{"fonts",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"fonts from the library",
(void *)ID_VF},
{"texts",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"texts from the library",
(void *)ID_TXT},
{"groups",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"groups from the library",
(void *)ID_GR},
{"sounds",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"sounds from the library",
(void *)ID_SO},
{"actions",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"actions from the library",
(void *)ID_AC},
{"armatures",
(getter)LibraryData_CreatePyObject, (setter)NULL,
"armatures from the library",
(void *)ID_AR},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
/*
* Define a new library and create a library object. We don't actually test
* if the library is valid here since we have to do it when the file is
* actually accessed later.
*/
static PyObject *M_Library_Load(PyObject *self, PyObject * args)
{
char *filename;
BPy_Library *lib;
if( !PyArg_ParseTuple( args, "s", &filename ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected a string" );
/* try to create a new object */
lib = (BPy_Library *)PyObject_NEW( BPy_Library, &Library_Type );
if( !lib )
return NULL;
/* assign the library filename for future use, then return */
BLI_strncpy( lib->filename, filename, sizeof(lib->filename) );
return (PyObject *)lib;
}
static struct PyMethodDef M_Library_methods[] = {
{"load", (PyCFunction)M_Library_Load, METH_VARARGS,
"(string) - declare a .blend file for use as a library"},
{NULL, NULL, 0, NULL}
};
/*****************************************************************************/
/* Python Library_Type structure definition: */
/*****************************************************************************/
PyTypeObject Library_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
0, /* ob_size */
/* For printing, in format "<module>.<name>" */
"Blender Library", /* char *tp_name; */
sizeof( BPy_Library ), /* int tp_basicsize; */
0, /* tp_itemsize; For allocation */
/* Methods to implement standard operations */
NULL, /* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
( cmpfunc ) NULL, /* cmpfunc tp_compare; */
( reprfunc ) NULL, /* reprfunc tp_repr; */
/* Method suites for standard classes */
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
NULL, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
NULL, /* hashfunc tp_hash; */
NULL, /* ternaryfunc tp_call; */
NULL, /* reprfunc tp_str; */
NULL, /* getattrofunc tp_getattro; */
NULL, /* setattrofunc tp_setattro; */
/* Functions to access object as input/output buffer */
NULL, /* PyBufferProcs *tp_as_buffer; */
/*** Flags to define presence of optional/expanded features ***/
Py_TPFLAGS_DEFAULT, /* long tp_flags; */
NULL, /* char *tp_doc; Documentation string */
/*** Assigned meaning in release 2.0 ***/
/* call function for all accessible objects */
NULL, /* traverseproc tp_traverse; */
/* delete references to contained objects */
NULL, /* inquiry tp_clear; */
/*** Assigned meaning in release 2.1 ***/
/*** rich comparisons ***/
NULL, /* richcmpfunc tp_richcompare; */
/*** weak reference enabler ***/
0, /* long tp_weaklistoffset; */
/*** Added in release 2.2 ***/
/* Iterators */
NULL, /* getiterfunc tp_iter; */
NULL, /* iternextfunc tp_iternext; */
/*** Attribute descriptor and subclassing stuff ***/
NULL, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
Library_getseters, /* struct PyGetSetDef *tp_getset; */
NULL, /* struct _typeobject *tp_base; */
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
NULL, /* descrsetfunc tp_descr_set; */
0, /* long tp_dictoffset; */
NULL, /* initproc tp_init; */
NULL, /* allocfunc tp_alloc; */
NULL, /* newfunc tp_new; */
/* Low-level free-memory routine */
NULL, /* freefunc tp_free; */
/* For PyObject_IS_GC */
NULL, /* inquiry tp_is_gc; */
NULL, /* PyObject *tp_bases; */
/* method resolution order */
NULL, /* PyObject *tp_mro; */
NULL, /* PyObject *tp_cache; */
NULL, /* PyObject *tp_subclasses; */
NULL, /* PyObject *tp_weaklist; */
NULL
};
/*
* Library module initialization
*/
static char M_newLibrary_doc[] = "The Blender.lib submodule";
PyObject *Library_Init( void )
{
PyObject *submodule;
if( PyType_Ready( &Library_Type ) < 0 )
return NULL;
if( PyType_Ready( &LibraryData_Type ) < 0 )
return NULL;
submodule = Py_InitModule3( "Blender.lib", M_Library_methods,
M_newLibrary_doc );
return submodule;
}

View File

@@ -0,0 +1,76 @@
/*
* $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.
*
* This is a new part of Blender.
*
* Contributor(s): Ken Hughes
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#ifndef EXPP_LIBRARY_H
#define EXPP_LIBRARY_H
#include <Python.h>
#include "DNA_scene_types.h"
#include "BLI_linklist.h"
#include "blendef.h"
/*****************************************************************************/
/* Python BPy_Library structure definition: */
/*****************************************************************************/
typedef struct {
PyObject_HEAD
char filename[FILE_MAXDIR + FILE_MAXFILE];
} BPy_Library;
typedef struct {
PyObject_HEAD
LinkNode *iter;
int type;
char filename[FILE_MAXDIR + FILE_MAXFILE];
char *name;
enum {
OBJECT_IS_LINK,
OBJECT_IS_APPEND,
OTHER
} kind;
} BPy_LibraryData;
extern PyTypeObject Library_Type;
extern PyTypeObject LibraryData_Type;
#define BPy_LibraryData_Check(v) ((v)->ob_type == &LibraryData_Type)
#define BPy_Library_Check(v) ((v)->ob_type == &Library_Type)
/*****************************************************************************/
/* Module Blender.Library - public functions */
/*****************************************************************************/
PyObject *Library_Init( void );
PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
int mode, Scene *scene );
#endif /* EXPP_LIBRARY_H */

View File

@@ -105,7 +105,7 @@
#include "NLA.h"
#include "Main.h"
#include "Scene.h"
#include "Library.h"
#include "Config.h" /* config pydata */
@@ -746,6 +746,8 @@ static char M_Main_doc[] = "The Blender.Main submodule";
PyObject *Main_Init( void )
{
PyObject *submodule;
PyObject *dict;
if( PyType_Ready( &MainSeq_Type ) < 0 )
return NULL;
@@ -753,6 +755,10 @@ PyObject *Main_Init( void )
return NULL;
submodule = Py_InitModule3( "Blender.Main", NULL, M_Main_doc );
dict = PyModule_GetDict( submodule );
PyDict_SetItemString( dict, "libraries", Library_Init( ) );
/* Python Data Types */
PyModule_AddObject( submodule, "scenes", MainSeq_CreatePyObject(NULL, ID_SCE) );

View File

@@ -72,6 +72,7 @@ struct View3D;
#include "Metaball.h"
#include "IDProp.h"
#include "Text3d.h"
#include "Library.h"
#include "gen_utils.h"
#include "gen_library.h"
@@ -1419,6 +1420,13 @@ static PyObject *SceneObSeq_link( BPy_SceneObSeq * self, PyObject *pyobj )
"Cannot modify scene objects while iterating" );
*/
if( PyTuple_Size(pyobj) == 1 ) {
BPy_LibraryData *seq = ( BPy_LibraryData * )PyTuple_GET_ITEM( pyobj, 0 );
if( BPy_LibraryData_Check( seq ) )
return LibraryData_importLibData( seq, seq->name,
( seq->kind == OBJECT_IS_LINK ? FILE_LINK : 0 ),
self->bpyscene->scene );
}
return Scene_link(self->bpyscene, pyobj);
}

View File

@@ -130,6 +130,8 @@ Example::
@type armatures: L{dataIterator}
@var actions: iterator for L{action<NLA.Action>} data
@type actions: L{dataIterator}
@var libraries: L{New library<LibData>} submodule
@type libraries: L{New library<LibData>}
"""

View File

@@ -0,0 +1,137 @@
# bpy.lib submodule
"""
The bpy.libraries submodule.
Libraries
=========
This module provides access to objects stored in .blend files. With it scripts
can append from Blender files to the current scene, like the File->Append
menu entry in Blender does. It allows programmers to use .blend files as
data files for their scripts.
@warn: This module is new and being considered as a replacement for the
L{original Library<Library>} module. Users should stay tuned to see
which module is supported in the end.
Example::
import bpy
scn= bpy.scenes.active # get current scene
lib = bpy.libraries.load('//file.blend') # open file.blend
ob = scn.objects.link(lib.objects.append('Cube')) # append Cube object from library to current scene
mat = lib.objects.link('Material') # get a link to a material
me = ob.getData(mesh=1) # get mesh data
me.materials[0] = mat # assign linked material to mesh
"""
def load(filename):
"""
Select an existing .blend file for use as a library. Unlike the
Library module, multiple libraries can be defined at the same time.
@type filename: string
@param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location.
@rtype: Library
@return: return a L{Library} object.
"""
class Libraries:
"""
The Library object
==================
This class provides a unified way to access and manipulate library types
in Blender.
It provides access to scenes, objects, meshes, curves, metaballs,
materials, textures, images, lattices, lamps, cameras, ipos, worlds,
fonts, texts, sounds, groups, armatures, and actions.
@ivar filename: The path to the library
@type filename: string
@ivar scenes: library L{scene<Scene.Scene>} data
@type scenes: L{LibData}
@ivar objects: library L{object<Object.Object>} data
@type objects: L{LibData}
@ivar meshes: library L{mesh<Mesh.Mesh>} data
@type meshes: L{LibData}
@ivar curves: library L{curve<Curve.Curve>} data
@type curves: L{LibData}
@ivar metaballs: library L{metaball<Metaball.Metaball>} data
@type metaballs: L{LibData}
@ivar materials: library L{material<Material.Material>} data
@type materials: L{LibData}
@ivar textures: library L{texture<Texture.Texture>} data
@type textures: L{LibData}
@ivar images: library L{image<Image.Image>} data
@type images: L{LibData}
@ivar lattices: library L{lattice<Lattice.Lattice>} data
@type lattices: L{LibData}
@ivar lamps: library L{lamp<Lamp.Lamp>} data
@type lamps: L{LibData}
@ivar cameras: library L{camera<Camera.Camera>} data
@type cameras: L{LibData}
@ivar ipos: library L{ipo<Ipo.Ipo>} data
@type ipos: L{LibData}
@ivar worlds: library L{world<World.World>} data
@type worlds: L{LibData}
@ivar fonts: library L{font<Font.Font>} data
@type fonts: L{LibData}
@ivar texts: library L{text<Text.Text>} data
@type texts: L{LibData}
@ivar sounds: library L{sound<Sound.Sound>} data
@type sounds: L{LibData}
@ivar groups: library L{group<Group.Group>} data
@type groups: L{LibData}
@ivar armatures: library L{armature<Armature.Armature>} data
@type armatures: L{LibData}
@ivar actions: library L{action<NLA.Action>} data
@type actions: L{LibData}
"""
class LibData:
"""
Generic Library Data Access
===========================
This class provides access to a specific type of library data.
"""
def append(name):
"""
Append a new datablock from a library. The new copy
is added to the current .blend file.
B{Note}: Blender Objects cannot be appended or linked without linking
them to a scene. For this reason, lib.objects.append() returns a
special "wrapper object" which must be passed to Scene.objects.link()
or bpy.scenes.active.link() in order to actually create the object.
So the following code will not create a new object::
import bpy
scn= bpy.scenes.active # get current scene
lib = bpy.libraries.load('//file.blend') # open file.blend
pseudoOb = lib.objects.append('Cube')) # get an object wrapper
But this code will::
import bpy
scn= bpy.scenes.active # get current scene
lib = bpy.libraries.load('//file.blend') # open file.blend
pseudoOb = lib.objects.append('Cube')) # get an object wrapper
ob = scn.objects.link(pseudoOb) # link to scene
@rtype: Blender data
@return: return a Blender datablock or object
@raise IOError: library cannot be read
@raise ValueError: library does not contain B{name}
"""
def link(name):
"""
Link a new datablock from a library. The linked data is not copied
into the local .blend file.
See L{append} for notes on special handling of Blender Objects.
@rtype: Blender data
@return: return a Blender datablock or object
@raise IOError: library cannot be read
@raise ValueError: library does not contain B{name}
"""

View File

@@ -11,7 +11,9 @@ can append from Blender files to the current scene, like the File->Append
menu entry in Blender does. It allows programmers to use .blend files as
data files for their scripts.
@warn: This is a new, still experimental module.
@warn: This module is being considered for deprecation. Users should
consider using the L{new Library<LibData>} module and stay tuned to see
which module is supported in the end.
Example::
import Blender