385 lines
10 KiB
C
385 lines
10 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 "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 */
|
|
|
|
/**
|
|
* 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 );
|
|
|
|
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.";
|
|
|
|
/**
|
|
* 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},
|
|
{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];
|
|
|
|
int len = 0;
|
|
|
|
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 */
|
|
}
|
|
|
|
/* 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( fname );
|
|
BLI_strncpy(G.sce, filename, sizeof(filename));
|
|
|
|
if( !bpy_openlib )
|
|
return Py_BuildValue( "i", 0 );
|
|
|
|
len = strlen( fname ) + 1; /* +1 for terminating '\0' */
|
|
|
|
bpy_openlibname = MEM_mallocN( len, "bpy_openlibname" );
|
|
|
|
if( bpy_openlibname )
|
|
PyOS_snprintf( bpy_openlibname, len, "%s", fname );
|
|
|
|
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_INCREF( Py_None );
|
|
return Py_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 );
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
if( !bpy_openlib ) {
|
|
return EXPP_ReturnPyObjError( PyExc_IOError,
|
|
"no library file: you need to open one, first." );
|
|
}
|
|
|
|
if( !PyArg_ParseTuple( args, "ss|i", &name, &base, &update ) ) {
|
|
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" );
|
|
}
|
|
|
|
BLO_script_library_append( bpy_openlib, bpy_openlibname, name,
|
|
blocktype );
|
|
|
|
if( update ) {
|
|
M_Library_Update( self );
|
|
Py_DECREF( Py_None ); /* incref'ed by above function */
|
|
}
|
|
|
|
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;
|
|
}
|