* Added data.lib attributes to almost all data types, (except for Text3d and NLA) This is None or the path of the library as a string. * Main was giving a warning, Include Curve.h rather then CurNurb.h * Added Library.LinkedLibs(), returns a list of externaly linked libs.
		
			
				
	
	
		
			437 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			437 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**
 | |
|  * $Id$
 | |
|  *
 | |
|  * Blender.Library BPython module implementation.
 | |
|  * This submodule has functions to append data from .blend files.
 | |
|  * 
 | |
|  * ***** 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): Willian P. Germano
 | |
|  *
 | |
|  * ***** END GPL/BL DUAL LICENSE BLOCK *****
 | |
| */
 | |
| 
 | |
| #include <Python.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_font.h"		/* for text_to_curve */
 | |
| #include "BKE_utildefines.h"
 | |
| #include "BKE_global.h"
 | |
| #include "BKE_main.h"
 | |
| #include "BLI_blenlib.h"
 | |
| #include "BLO_readfile.h"
 | |
| #include "BLI_linklist.h"
 | |
| #include "MEM_guardedalloc.h"
 | |
| #include "gen_utils.h"
 | |
| 
 | |
| /**
 | |
|  * Global variables.
 | |
|  */
 | |
| static BlendHandle *bpy_openlib = NULL;	/* ptr to the open .blend file */
 | |
| static char *bpy_openlibname = NULL;	/* its pathname */
 | |
| static int bpy_relative= 0;
 | |
| 
 | |
| /**
 | |
|  * Function prototypes for the Library submodule.
 | |
|  */
 | |
| static PyObject *M_Library_Open( PyObject * self, PyObject * args );
 | |
| 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 *M_Library_LinkableGroups( PyObject * self );
 | |
| static PyObject *M_Library_LinkedLibs( PyObject * self );
 | |
| 
 | |
| PyObject *Library_Init( void );
 | |
| void EXPP_Library_Close( void );
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Module doc strings.
 | |
|  */
 | |
| static char M_Library_doc[] = "The Blender.Library submodule:\n\n\
 | |
| This module gives access to .blend files, using them as libraries of\n\
 | |
| data that can be loaded into the current scene in Blender.";
 | |
| 
 | |
| static char Library_Open_doc[] =
 | |
| 	"(filename) - Open the given .blend file for access to its objects.\n\
 | |
| If another library file is still open, it's closed automatically.";
 | |
| 
 | |
| static char Library_Close_doc[] =
 | |
| 	"() - Close the currently open library file, if any.";
 | |
| 
 | |
| static char Library_GetName_doc[] =
 | |
| 	"() - Get the filename of the currently open library file, if any.";
 | |
| 
 | |
| static char Library_Datablocks_doc[] =
 | |
| 	"(datablock) - List all datablocks of the given type in the currently\n\
 | |
| open library file.\n\
 | |
| (datablock) - datablock name as a string: Object, Mesh, etc.";
 | |
| 
 | |
| static char Library_Load_doc[] =
 | |
| 	"(name, datablock [,update = 1]) - Append object 'name' of type 'datablock'\n\
 | |
| from the open library file to the current scene.\n\
 | |
| (name) - (str) the name of the object.\n\
 | |
| (datablock) - (str) the datablock of the object.\n\
 | |
| (update = 1) - (int) if non-zero, all display lists are recalculated and the\n\
 | |
| links are updated.  This is slow, set it to zero if you have more than one\n\
 | |
| object to load, then call Library.Update() after loading them all.";
 | |
| 
 | |
| static char Library_Update_doc[] =
 | |
| 	"() - Update the current scene, linking all loaded library objects and\n\
 | |
| remaking all display lists.  This is slow, call it only once after loading\n\
 | |
| all objects (load each of them with update = 0:\n\
 | |
| Library.Load(name, datablock, 0), or the update will be automatic, repeated\n\
 | |
| for each loaded object.";
 | |
| 
 | |
| static char Library_LinkableGroups_doc[] =
 | |
| 	"() - Get all linkable groups from the open .blend library file.";
 | |
| 
 | |
| static char Library_LinkedLibs_doc[] =
 | |
| 	"() - Get all libs used in the the open .blend file.";
 | |
| 	
 | |
| /**
 | |
|  * Python method structure definition for Blender.Library submodule.
 | |
|  */
 | |
| struct PyMethodDef M_Library_methods[] = {
 | |
| 	{"Open", M_Library_Open, METH_VARARGS, Library_Open_doc},
 | |
| 	{"Close", ( PyCFunction ) M_Library_Close, METH_NOARGS,
 | |
| 	 Library_Close_doc},
 | |
| 	{"GetName", ( PyCFunction ) M_Library_GetName, METH_NOARGS,
 | |
| 	 Library_GetName_doc},
 | |
| 	{"Update", ( PyCFunction ) M_Library_Update, METH_NOARGS,
 | |
| 	 Library_Update_doc},
 | |
| 	{"Datablocks", M_Library_Datablocks, METH_VARARGS,
 | |
| 	 Library_Datablocks_doc},
 | |
| 	{"Load", M_Library_Load, METH_VARARGS, Library_Load_doc},
 | |
| 	{"LinkableGroups", ( PyCFunction ) M_Library_LinkableGroups,
 | |
| 	 METH_NOARGS, Library_LinkableGroups_doc},
 | |
| 	{"LinkedLibs", ( PyCFunction ) M_Library_LinkedLibs,
 | |
| 	 METH_NOARGS, Library_LinkedLibs_doc},
 | |
| 	{NULL, NULL, 0, NULL}
 | |
| };
 | |
| 
 | |
| /* Submodule Python functions: */
 | |
| 
 | |
| /**
 | |
|  * Open a new .blend file.
 | |
|  * 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 )
 | |
| {
 | |
| 	char *fname = NULL;
 | |
| 	char filename[FILE_MAXDIR+FILE_MAXFILE];
 | |
| 	char fname1[FILE_MAXDIR+FILE_MAXFILE];
 | |
| 	
 | |
| 	int len = 0;
 | |
| 
 | |
| 	bpy_relative= 0; /* assume non relative each time we load */
 | |
| 	
 | |
| 	if( !PyArg_ParseTuple( args, "s", &fname ) ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_TypeError,
 | |
| 					      "expected a .blend filename" );
 | |
| 	}
 | |
| 
 | |
| 	if( bpy_openlib ) {
 | |
| 		M_Library_Close( self );
 | |
| 		Py_DECREF( Py_None );	/* incref'ed by above function */
 | |
| 	}
 | |
| 	
 | |
| 	/* copy the name to make it absolute so BLO_blendhandle_from_file doesn't complain */
 | |
| 	BLI_strncpy(fname1, fname, sizeof(fname1)); 
 | |
| 	BLI_convertstringcode(fname1, G.sce, 0); /* make absolute */
 | |
| 	
 | |
|    	/* G.sce = last file loaded, save for UI and restore after opening file */
 | |
| 	BLI_strncpy(filename, G.sce, sizeof(filename));
 | |
| 	bpy_openlib = BLO_blendhandle_from_file( fname1 );
 | |
| 	BLI_strncpy(G.sce, filename, sizeof(filename)); 
 | |
| 	
 | |
| 	if( !bpy_openlib )
 | |
| 		return EXPP_ReturnPyObjError( PyExc_IOError, "file not found" );
 | |
| 
 | |
| 	/* "//someblend.blend" enables relative paths */
 | |
| 	if (sizeof(fname) > 2 && fname[0] == '/' && fname[1] == '/')
 | |
| 		bpy_relative= 1; /* global that makes the library relative on loading */ 
 | |
| 	
 | |
| 	len = strlen( fname1 ) + 1;	/* +1 for terminating '\0' */
 | |
| 
 | |
| 	bpy_openlibname = MEM_mallocN( len, "bpy_openlibname" );
 | |
| 
 | |
| 	if( bpy_openlibname )
 | |
| 		PyOS_snprintf( bpy_openlibname, len, "%s", fname1 );
 | |
| 
 | |
| 	return Py_BuildValue( "i", 1 );
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Close the current .blend file, if any.
 | |
|  */
 | |
| PyObject *M_Library_Close( PyObject * self )
 | |
| {
 | |
| 	if( bpy_openlib ) {
 | |
| 		BLO_blendhandle_close( bpy_openlib );
 | |
| 		bpy_openlib = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if( bpy_openlibname ) {
 | |
| 		MEM_freeN( bpy_openlibname );
 | |
| 		bpy_openlibname = NULL;
 | |
| 	}
 | |
| 
 | |
| 	Py_RETURN_NONE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * helper function for 'atexit' clean-ups, used by BPY_end_python,
 | |
|  * declared in EXPP_interface.h.
 | |
|  */
 | |
| void EXPP_Library_Close( void )
 | |
| {
 | |
| 	if( bpy_openlib ) {
 | |
| 		BLO_blendhandle_close( bpy_openlib );
 | |
| 		bpy_openlib = NULL;
 | |
| 	}
 | |
| 
 | |
| 	if( bpy_openlibname ) {
 | |
| 		MEM_freeN( bpy_openlibname );
 | |
| 		bpy_openlibname = NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Get the filename of the currently open library file, if any.
 | |
|  */
 | |
| PyObject *M_Library_GetName( PyObject * self )
 | |
| {
 | |
| 	if( bpy_openlib && bpy_openlibname )
 | |
| 		return Py_BuildValue( "s", bpy_openlibname );
 | |
| 
 | |
| 	Py_INCREF( Py_None );
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * 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 )
 | |
| {
 | |
| 	char *name = NULL;
 | |
| 	int blocktype = 0;
 | |
| 	LinkNode *l = NULL, *names = NULL;
 | |
| 	PyObject *list = NULL;
 | |
| 
 | |
| 	if( !bpy_openlib ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_IOError,
 | |
| 					      "no library file: open one first with Blender.Lib_Open(filename)" );
 | |
| 	}
 | |
| 
 | |
| 	if( !PyArg_ParseTuple( args, "s", &name ) ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_TypeError,
 | |
| 					      "expected a string (datablock type) as argument." );
 | |
| 	}
 | |
| 
 | |
| 	blocktype = ( int ) BLO_idcode_from_name( name );
 | |
| 
 | |
| 	if( !blocktype ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_NameError,
 | |
| 					      "no such Blender datablock type" );
 | |
| 	}
 | |
| 
 | |
| 	names = BLO_blendhandle_get_datablock_names( bpy_openlib, blocktype );
 | |
| 
 | |
| 	if( names ) {
 | |
| 		int counter = 0;
 | |
| 		list = PyList_New( BLI_linklist_length( names ) );
 | |
| 		for( l = names; l; l = l->next ) {
 | |
| 			PyList_SET_ITEM( list, counter,
 | |
| 					 Py_BuildValue( "s",
 | |
| 							( char * ) l->link ) );
 | |
| 			counter++;
 | |
| 		}
 | |
| 		BLI_linklist_free( names, free );	/* free linklist *and* each node's data */
 | |
| 		return list;
 | |
| 	}
 | |
| 
 | |
| 	Py_INCREF( Py_None );
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return a list with the names of all linkable groups in the
 | |
|  * open library file.
 | |
|  */
 | |
| PyObject *M_Library_LinkableGroups( PyObject * self )
 | |
| {
 | |
| 	LinkNode *l = NULL, *names = NULL;
 | |
| 	PyObject *list = NULL;
 | |
| 
 | |
| 	if( !bpy_openlib ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_IOError,
 | |
| 					      "no library file: open one first with Blender.Lib_Open(filename)" );
 | |
| 	}
 | |
| 
 | |
| 	names = BLO_blendhandle_get_linkable_groups( bpy_openlib );
 | |
| 	list = PyList_New( BLI_linklist_length( names ) );
 | |
| 	
 | |
| 	if( names ) {
 | |
| 		int counter = 0;
 | |
| 		
 | |
| 		for( l = names; l; l = l->next ) {
 | |
| 			PyList_SET_ITEM( list, counter, PyString_FromString( ( char * ) l->link  ) );
 | |
| 			counter++;
 | |
| 		}
 | |
| 		BLI_linklist_free( names, free );	/* free linklist *and* each node's data */
 | |
| 		return list;
 | |
| 	}
 | |
| 	return list;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return a list with the names of all externally linked libs used in the current Blend file
 | |
|  */
 | |
| PyObject *M_Library_LinkedLibs( PyObject * self )
 | |
| {
 | |
| 	int counter = 0;
 | |
| 	Library *li;
 | |
| 	PyObject *list;
 | |
| 
 | |
| 	list = PyList_New( BLI_countlist( &( G.main->library ) ) );
 | |
| 	for (li= G.main->library.first; li; li= li->id.next) {
 | |
| 		PyList_SET_ITEM( list, counter, PyString_FromString( li->name ));
 | |
| 		counter++;
 | |
| 	}
 | |
| 	return list;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Load (append) a given datablock of a given datablock type
 | |
|  * to the current scene.
 | |
|  */
 | |
| PyObject *M_Library_Load( PyObject * self, PyObject * args )
 | |
| {
 | |
| 	char *name = NULL;
 | |
| 	char *base = NULL;
 | |
| 	int update = 1;
 | |
| 	int blocktype = 0;
 | |
| 	int linked = 0;
 | |
| 
 | |
| 	if( !bpy_openlib ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_IOError,
 | |
| 					      "no library file: you need to open one, first." );
 | |
| 	}
 | |
| 
 | |
| 	if( !PyArg_ParseTuple( args, "ss|ii", &name, &base, &update, &linked ) ) {
 | |
| 		return EXPP_ReturnPyObjError( PyExc_TypeError,
 | |
| 					      "expected two strings as arguments." );
 | |
| 	}
 | |
| 
 | |
| 	blocktype = ( int ) BLO_idcode_from_name( base );
 | |
| 
 | |
| 	if( !blocktype )
 | |
| 		return EXPP_ReturnPyObjError( PyExc_NameError,
 | |
| 					      "no such Blender datablock type" );
 | |
| 	
 | |
| 	if (linked)
 | |
| 		BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK);
 | |
| 	else
 | |
| 		BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0);
 | |
| 	
 | |
| 	if( update ) {
 | |
| 		M_Library_Update( self );
 | |
| 		Py_DECREF( Py_None );	/* incref'ed by above function */
 | |
| 	}
 | |
| 	
 | |
| 	if( bpy_relative ) {
 | |
| 		/* and now find the latest append lib file */
 | |
| 		Library *lib = G.main->library.first;
 | |
| 		while( lib ) {
 | |
| 			if( strcmp( bpy_openlibname, lib->name ) == 0 ) {
 | |
| 				
 | |
| 				/* use the full path, this could have been read by other library even */
 | |
| 				BLI_strncpy(lib->name, lib->filename, sizeof(lib->name));
 | |
| 		
 | |
| 				/* uses current .blend file as reference */
 | |
| 				BLI_makestringcode(G.sce, lib->name);
 | |
| 				break;
 | |
| 			}
 | |
| 			lib = lib->id.next;
 | |
| 		}
 | |
| 		
 | |
| 	}
 | |
| 
 | |
| 	Py_INCREF( Py_None );
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Update all links and remake displists.
 | |
|  */
 | |
| PyObject *M_Library_Update( PyObject * self )
 | |
| {				/* code adapted from do_library_append in src/filesel.c: */
 | |
| 	Library *lib = NULL;
 | |
| 
 | |
| 		/* Displist code that was here is obsolete... depending on what
 | |
| 		 * this function is supposed to do (it should technically be unnecessary)
 | |
| 		 * can be replaced with depgraph calls - zr
 | |
| 		 */
 | |
| 
 | |
| 	if( bpy_openlibname ) {
 | |
| 		strcpy( G.lib, bpy_openlibname );
 | |
| 
 | |
| 		/* and now find the latest append lib file */
 | |
| 		lib = G.main->library.first;
 | |
| 		while( lib ) {
 | |
| 			if( strcmp( bpy_openlibname, lib->name ) == 0 )
 | |
| 				break;
 | |
| 			lib = lib->id.next;
 | |
| 		}
 | |
| 		all_local( lib );
 | |
| 	}
 | |
| 
 | |
| 	Py_INCREF( Py_None );
 | |
| 	return Py_None;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Initialize the Blender.Library submodule.
 | |
|  * Called by Blender_Init in Blender.c .
 | |
|  * @return the registered submodule.
 | |
|  */
 | |
| PyObject *Library_Init( void )
 | |
| {
 | |
| 	PyObject *submod;
 | |
| 
 | |
| 	submod = Py_InitModule3( "Blender.Library", M_Library_methods,
 | |
| 				 M_Library_doc );
 | |
| 
 | |
| 	return submod;
 | |
| }
 |