- New module + doc: Blender.Library:
  It's like File->Append, loads datablocks from .blend files.
- small updates to fix warnings and accomodate for the new module, in readfile.[ch]
- New Blender.sys module function: time, a wrapper of the PIL get time function.
- Updated original makefile and scons builds.
This commit is contained in:
Willian Padovani Germano 2004-04-24 20:04:37 +00:00
parent e5e4c0fc4f
commit 382297b687
13 changed files with 696 additions and 162 deletions

@ -214,6 +214,7 @@ char *BLO_gethome(void);
int BLO_has_bfile_extension(char *str);
void BLO_library_append(struct SpaceFile *sfile, char *dir, int idcode);
void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode);
BlendFileData* blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r);

@ -48,6 +48,7 @@
#include <stdlib.h> // for getenv atoi
#include <fcntl.h> // for open
#include <string.h> // for strcasecmp strrchr strncmp strstr
#include <math.h> // for fabs
#ifndef WIN32
#include <unistd.h> // for read close
@ -2698,7 +2699,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
ID *id;
ListBase *lb;
char *str;
char *str = NULL;
if(bhead->code==ID_ID) {
ID *linkedid= (ID *)(bhead + 1); /* BHEAD+DATA dependancy */
@ -4862,13 +4863,12 @@ static void give_base_to_objects(Scene *sce, ListBase *lb)
}
#endif
static void append_named_part(SpaceFile *sfile, Main *mainvar, Scene *scene, char *name, int idcode)
static void append_named_part(FileData *fd, Main *mainvar, Scene *scene, char *name, int idcode)
{
Object *ob;
Base *base;
BHead *bhead;
ID *id;
FileData *fd= (FileData*) sfile->libfiledata;
int afbreek=0;
bhead = blo_firstbhead(fd);
@ -4933,6 +4933,38 @@ static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **id_r)
}
}
/* this is a version of BLO_library_append needed by the BPython API, so
* scripts can load data from .blend files -- see Blender.Library module.*/
/* append to G.scene */
void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode)
{
ListBase mainlist;
Main *mainl;
FileData *fd = (FileData *)bh;
mainlist.first= mainlist.last= G.main;
G.main->next= NULL;
/* make mains */
blo_split_main(&mainlist);
/* which one do we need? */
mainl = blo_find_main(&mainlist, dir);
append_named_part(fd, mainl, G.scene, name, idcode);
/* make main consistant */
expand_main(fd, mainl);
/* do this when expand found other libs */
read_libraries(fd, &mainlist);
blo_join_main(&mainlist);
G.main= mainlist.first;
lib_link_all(fd, G.main);
}
/* append to G.scene */
void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
@ -4977,12 +5009,12 @@ void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
mainl = blo_find_main(&mainlist, dir);
if(totsel==0) {
append_named_part(sfile, mainl, G.scene, sfile->file, idcode);
append_named_part(fd, mainl, G.scene, sfile->file, idcode);
}
else {
for(a=0; a<sfile->totfile; a++) {
if(sfile->filelist[a].flags & ACTIVE) {
append_named_part(sfile, mainl, G.scene, sfile->filelist[a].relname, idcode);
append_named_part(fd, mainl, G.scene, sfile->filelist[a].relname, idcode);
}
}
}
@ -5029,7 +5061,7 @@ static int mainvar_count_libread_blocks(Main *mainvar)
static void read_libraries(FileData *basefd, ListBase *mainlist)
{
Main *main= mainlist->first;
Main *mainl= mainlist->first;
Main *mainptr;
ListBase *lbarray[30];
int a, doit= 1;
@ -5038,7 +5070,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
doit= 0;
/* test 1: read libdata */
mainptr= main->next;
mainptr= mainl->next;
while(mainptr) {
int tot= mainvar_count_libread_blocks(mainptr);
@ -5092,7 +5124,7 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
mainptr= mainptr->next;
}
}
mainptr= main->next;
mainptr= mainl->next;
while(mainptr) {
/* test if there are unread libblocks */
a= set_listbasepointers(mainptr, lbarray);

@ -18,6 +18,7 @@ source_files = ['BPY_interface.c',
'api2_2x/World.c',
'api2_2x/Lamp.c',
'api2_2x/Lattice.c',
'api2_2x/Library.c',
'api2_2x/Curve.c',
'api2_2x/Armature.c',
'api2_2x/Bone.c',
@ -53,6 +54,7 @@ source_files = ['BPY_interface.c',
python_env.Append (CPPPATH = ['api2_2x',
'../blenkernel',
'../blenlib',
'../blenloader',
'../render/extern/include',
'../makesdna',
'#/intern/guardedalloc',

@ -236,4 +236,5 @@ void M_Blender_Init (void)
PyDict_SetItemString (dict, "NMesh", NMesh_Init());
PyDict_SetItemString (dict, "Noise", Noise_Init());
PyDict_SetItemString (dict, "Mathutils",Mathutils_Init());
PyDict_SetItemString (dict, "Library", Library_Init());
}

@ -0,0 +1,360 @@
/**
* $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 <stdio.h>
#include "BKE_displist.h" /* for set_displist_onlyzero */
#include "BKE_font.h" /* for text_to_curve */
#include "BKE_library.h" /* for all_local */
#include "BLO_readfile.h"
#include "BLI_linklist.h"
#include "MEM_guardedalloc.h"
#include "gen_utils.h"
#include "modules.h"
/**
* Global variables.
*/
static BlendHandle *bpy_openlib; /* ptr to the open .blend file */
static char *bpy_openlibname; /* 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);
/**
* 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;
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 */
}
bpy_openlib = BLO_blendhandle_from_file(fname);
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;
}
/**
* 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: */
Object *ob = NULL;
Library *lib = NULL;
ob = G.main->object.first;
set_displist_onlyzero(1);
while (ob) {
if (ob->id.lib) {
if (ob->type==OB_FONT) {
Curve *cu= ob->data;
if (cu->nurb.first==0) text_to_curve(ob, 0);
}
makeDispList(ob);
}
else {
if (ob->type == OB_MESH && ob->parent && ob->parent->type == OB_LATTICE)
makeDispList(ob);
}
ob = ob->id.next;
}
set_displist_onlyzero(0);
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;
}

@ -50,6 +50,7 @@ CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
CPPFLAGS += -I../../makesdna
CPPFLAGS += -I../../blenkernel
CPPFLAGS += -I../../blenlib
CPPFLAGS += -I../../blenloader
CPPFLAGS += -I../../include
CPPFLAGS += -I../../render/extern/include
CPPFLAGS += -I$(NAN_BMFONT)/include

@ -30,6 +30,7 @@
*/
#include "BKE_utildefines.h"
#include "PIL_time.h"
#include "Sys.h"
@ -168,3 +169,10 @@ static PyObject *M_sys_splitext (PyObject *self, PyObject *args)
return Py_BuildValue("ss", path, ext);
}
static PyObject *M_sys_time (PyObject *self)
{
double t = PIL_check_seconds_timer();
return Py_BuildValue("d", t);
}

@ -43,6 +43,7 @@
static PyObject *M_sys_basename (PyObject *self, PyObject *args);
static PyObject *M_sys_dirname (PyObject *self, PyObject *args);
static PyObject *M_sys_splitext (PyObject *self, PyObject *args);
static PyObject *M_sys_time (PyObject *self);
/*****************************************************************************/
/* The following string definitions are used for documentation strings. */
@ -65,6 +66,11 @@ static char M_sys_splitext_doc[]="(path) - Split 'path' in root and \
extension:\n/this/that/file.ext -> ('/this/that/file','.ext').\n\
Return the pair (root, extension).";
static char M_sys_time_doc[]="() - Return a float representing time elapsed \
in seconds.\n\
Each successive call is garanteed to return values greater than or\n\
equal to the previous call.";
/*****************************************************************************/
/* Python method structure definition for Blender.sys module: */
/*****************************************************************************/
@ -72,6 +78,7 @@ struct PyMethodDef M_sys_methods[] = {
{"basename", M_sys_basename, METH_VARARGS, M_sys_basename_doc},
{"dirname", M_sys_dirname, METH_VARARGS, M_sys_dirname_doc},
{"splitext", M_sys_splitext, METH_VARARGS, M_sys_splitext_doc},
{"time", (PyCFunction)M_sys_time, METH_NOARGS, M_sys_time_doc},
{NULL, NULL, 0, NULL}
};

@ -29,6 +29,7 @@ The Blender Python API Reference
- L{Ipo}
- L{Lamp}
- L{Lattice}
- L{Library}
- L{Material}
- L{Mathutils}
- L{Metaball}

@ -0,0 +1,110 @@
# Blender.Library submodule
"""
The Blender.Library submodule.
Library
=======
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 is a new, still experimental module.
Example::
import Blender
from Blender import Library
def f(name):
open_library(name)
def open_library(name):
Library.Open(name)
groups = Library.LinkableGroups()
for db in groups:
print "\nDATABLOCK %s:" % db
for obname in Library.Datablocks(db):
print obname
if 'Object' in groups:
for obname in Library.Datablocks('Object'):
Library.Load(obname, 'Object', 0) # note the 0...
Library.Update()
Library.Close()
b.Redraw()
b.Window.FileSelector(f, "Choose Library", "*.blend")
"""
def Open (filename):
"""
Open an existing .blend file. If there was already one open file, it is
closed first.
@type filename: string
@param filename: The filename of a Blender file.
@rtype: bool
@return: 1 if succesful, 0 otherwise.
"""
def Close ():
"""
Close the currently open library file, if any.
"""
def getName ():
"""
Get the filename of the currently open library file.
@rtype: string
@return: The open library filename.
"""
def LinkableGroups ():
"""
Get all the linkable group names from the currently open library file. These
are the available groups for linking with the current scene. Ex: 'Object',
'Mesh', 'Material', 'Text', etc.
@rtype: list of strings
@return: the list of linkable groups.
"""
def Datablocks (group):
"""
Get all datablock objects of the given 'group' available in the currently
open library file.
@type group: string
@param group: datablock group, see L{LinkableGroups}.
"""
def Load (datablock, group, update = 1):
"""
Load the given datablock object from the current library file
@type datablock: string
@type group: string
@type update: bool
@param datablock: an available object name, as returned by L{Datablocks}.
@param group: an available group name, as returned by L{LinkableGroups}.
@param update: defines if Blender should be updated after loading this
object. This means linking all objects and remaking all display lists,
so it is potentially very slow.
@warn: If you plan to load more than one object in sequence, it is
B{definitely recommended} to set 'update' to 0 in all calls to this
function and after them call L{Update}.
"""
def Update ():
"""
Update all links and display lists in Blender. This function should be
called after a series of L{Load}(datablock, group, B{0}) calls to make
everything behave nicely.
@warn: to use this function, remember to set the third L{Load} parameter to
zero or each loading will automatically update Blender, which will slow
down your script and make you look like a lousy programmer.
Enough warnings :)?
"""

@ -6,6 +6,8 @@ The Blender.sys submodule.
sys
===
B{New}: L{time}
This module provides a minimal set of helper functions and data. Its purpose
is to avoid the need for the standard Python module 'os', in special 'os.path',
though it is only meant for the simplest cases.
@ -63,3 +65,11 @@ def splitext (path):
@rtype: list with two strings
@return: (root, ext)
"""
def time ():
"""
Get the current time in seconds since a fixed value. Successive calls to
this function are garanteed to return values greater than the previous call.
@rtype: float
@return: the elapsed time in seconds.
"""

@ -192,5 +192,6 @@ PyObject * Draw_Init (void);
PyObject * BGL_Init (void);
PyObject * Mathutils_Init (void);
PyObject * NLA_Init (void);
PyObject * Library_Init (void);
#endif /* EXPP_modules_h */