** Note: two new files added, projectfiles will need an update.

Scripts:
  Campbell Barton (Ideasman, thanks) updated his Wavefront OBJ importer.
BPython:
- Finally committed pending contributions:
    Chris Keith wrote the Blender.Sound module -- still some testing to do this week;
    Joseph (joeedh) added the OnLoad scene script event;
    Satish Goda added 6 GLU functions to Blender.BGL.  Great additions, thanks all!
- Small changes to Blender.Load (leave editmode as Blender wants) and Window.EditMode (allow definition of "undo string");
- Fixed bug #1539: Window.RedrawAll() crashed Blender if an empty spacescript was available while using it in a gui-less script.
- doc updates.
This commit is contained in:
Willian Padovani Germano 2004-08-17 04:26:00 +00:00
parent 5a39312392
commit 446e1fae7c
19 changed files with 874 additions and 161 deletions

@ -114,8 +114,8 @@ def load_mat_image(mat, img_fileName, type, mesh):
# adds textures to faces (Textured/Alt-Z mode)
# Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
if type == 'Kd':
for f in mesh.faces:
if mesh.materials[f.mat].name == mat.name:
for f in meshList[objectName][0].faces:
if meshList[objectName][0].materials[f.mat].name == mat.name:
# the inline usemat command overides the material Image
if not f.image:
@ -184,22 +184,24 @@ def load_mtl(dir, mtl_file, mesh):
def load_obj(file):
def applyMat(mesh, f, mat):
# Check weather the 16 mat limit has been met.
if len( mesh.materials ) >= MATLIMIT:
if len( meshList[objectName][0].materials ) >= MATLIMIT:
print 'Warning, max material limit reached, using an existing material'
return mesh, f
return meshList[objectName][0]
mIdx = 0
for m in mesh.materials:
for m in meshList[objectName][0].materials:
if m.getName() == mat.getName():
break
mIdx+=1
if mIdx == len(mesh.materials):
mesh.addMaterial(mat)
meshList[objectName][0].addMaterial(mat)
f.mat = mIdx
return mesh, f
return f
# Get the file name with no path or .obj
fileName = stripName( stripPath(file) )
@ -208,23 +210,26 @@ def load_obj(file):
DIR = pathName(file, stripPath(file))
fileLines = open(file, 'r').readlines()
mesh = NMesh.GetRaw() # new empty mesh
objectName = 'mesh' # If we cant get one, use this
uvMapList = [(0,0)] # store tuple uv pairs here
# This dummy vert makes life a whole lot easier-
# pythons index system then aligns with objs, remove later
vertList = [NMesh.Vert(0, 0, 0)] # store tuple uv pairs here
# Here we store a boolean list of which verts are used or not
# no we know weather to add them to the current mesh
# This is an issue with global vertex indicies being translated to per mesh indicies
# like blenders, we start with a dummy just like the vert.
# -1 means unused, any other value refers to the local mesh index of the vert.
usedList = [-1]
# objectName has a char in front of it that determins weather its a group or object.
# We ignore it when naming the object.
objectName = 'omesh' # If we cant get one, use this
meshList = {}
meshList[objectName] = (NMesh.GetRaw(), [-1]) # Mesh/meshList[objectName][1]
uvMapList = [(0,0)] # store tuple uv pairs here
# This dummy vert makes life a whole lot easier-
# pythons index system then aligns with objs, remove later
vertList = [NMesh.Vert(0, 0, 0)] # store tuple uv pairs here
nullMat = getMat(NULL_MAT)
@ -245,7 +250,7 @@ def load_obj(file):
elif l[0] == 'v':
# This is a new vert, make a new mesh
vertList.append( NMesh.Vert(eval(l[1]), eval(l[2]), eval(l[3]) ) )
usedList.append(-1) # Ad the moment this vert is not used by any mesh.
meshList[objectName][1].append(-1) # Ad the moment this vert is not used by any meshList[objectName][0].
elif l[0] == 'vn':
pass
@ -258,8 +263,12 @@ def load_obj(file):
# Make a face with the correct material.
f = NMesh.Face()
mesh, f = applyMat(mesh, f, currentMat)
f = applyMat(meshList[objectName][0], f, currentMat)
# Apply the current image to the face
if currentImg != NULL_IMG:
f.image = currentImg
# Set up vIdxLs : Verts
# Set up vtIdxLs : UV
# Start with a dummy objects so python accepts OBJs 1 is the first index.
@ -293,89 +302,63 @@ def load_obj(file):
# Quads only, we could import quads using the method below but it polite to import a quad as a quad.
if len(vIdxLs) == 4:
for i in [0,1,2,3]:
if usedList[vIdxLs[i]] == -1:
mesh.verts.append(vertList[vIdxLs[i]])
f.v.append(mesh.verts[-1])
usedList[vIdxLs[i]] = len(mesh.verts)-1
if meshList[objectName][1][vIdxLs[i]] == -1:
meshList[objectName][0].verts.append(vertList[vIdxLs[i]])
f.v.append(meshList[objectName][0].verts[-1])
meshList[objectName][1][vIdxLs[i]] = len(meshList[objectName][0].verts)-1
else:
f.v.append(mesh.verts[usedList[vIdxLs[i]]])
f.v.append(meshList[objectName][0].verts[meshList[objectName][1][vIdxLs[i]]])
# UV MAPPING
if fHasUV:
for i in [0,1,2,3]:
f.uv.append( uvMapList[ vtIdxLs[i] ] )
mesh.faces.append(f) # move the face onto the mesh
# Apply the current image to the face
if currentImg != NULL_IMG:
mesh.faces[-1].image = currentImg
meshList[objectName][0].faces.append(f) # move the face onto the mesh
elif len(vIdxLs) >= 3: # This handles tri's and fans
for i in range(len(vIdxLs)-2):
f = NMesh.Face()
mesh, f = applyMat(mesh, f, currentMat)
if usedList[vIdxLs[0]] == -1:
mesh.verts.append(vertList[vIdxLs[0]])
f.v.append(mesh.verts[-1])
usedList[vIdxLs[0]] = len(mesh.verts)-1
else:
f.v.append(mesh.verts[usedList[vIdxLs[0]]])
if usedList[vIdxLs[i+1]] == -1:
mesh.verts.append(vertList[vIdxLs[i+1]])
f.v.append(mesh.verts[-1])
usedList[vIdxLs[i+1]] = len(mesh.verts)-1
else:
f.v.append(mesh.verts[usedList[vIdxLs[i+1]]])
if usedList[vIdxLs[i+2]] == -1:
mesh.verts.append(vertList[vIdxLs[i+2]])
f.v.append(mesh.verts[-1])
usedList[vIdxLs[i+2]] = len(mesh.verts)-1
else:
f.v.append(mesh.verts[usedList[vIdxLs[i+2]]])
f = applyMat(meshList[objectName][0], f, currentMat)
for ii in [0, i+1, i+2]:
if meshList[objectName][1][vIdxLs[ii]] == -1:
meshList[objectName][0].verts.append(vertList[vIdxLs[ii]])
f.v.append(meshList[objectName][0].verts[-1])
meshList[objectName][1][vIdxLs[ii]] = len(meshList[objectName][0].verts)-1
else:
f.v.append(meshList[objectName][0].verts[meshList[objectName][1][vIdxLs[ii]]])
# UV MAPPING
if fHasUV:
f.uv.append( uvMapList[ vtIdxLs[0] ] )
f.uv.append( uvMapList[ vtIdxLs[i+1] ] )
f.uv.append( uvMapList[ vtIdxLs[i+2] ] )
mesh.faces.append(f) # move the face onto the mesh
# Apply the current image to the face
if currentImg != NULL_IMG:
mesh.faces[-1].image = currentImg
meshList[objectName][0].faces.append(f) # move the face onto the mesh
# Object / Group
elif l[0] == 'o' or l[0] == 'g':
# Reset the used list
ulIdx = 0
while ulIdx < len(usedList):
usedList[ulIdx] = -1
ulIdx +=1
# This makes sure that if an object and a group have the same name then
# they are not put into the same object.
if l[0] == 'o':
newObjectName = 'o' + '_'.join(l[1:])
elif l[0] == 'g':
newObjectName = 'g' + '_'.join(l[1:])
# Some material stuff
if mtl_fileName != '':
load_mtl(DIR, mtl_fileName, mesh)
if newObjectName == '':
objectName = 'omesh'
else:
objectName = newObjectName
# Make sure the objects is worth putting
if len(mesh.verts) > 1:
mesh.verts.remove(mesh.verts[0])
ob = NMesh.PutRaw(mesh, fileName + '_' + objectName)
if ob != None: # Name the object too.
ob.name = fileName + '_' + objectName
# Make new mesh
mesh = NMesh.GetRaw()
# This dummy vert makes life a whole lot easier-
# pythons index system then aligns with objs, remove later
mesh.verts.append( NMesh.Vert(0, 0, 0) )
# If we havnt written to this mesh before then do so.
if objectName not in meshList.keys():
meshList[objectName] = (NMesh.GetRaw(), [-1])
meshList[objectName][0].verts.append( NMesh.Vert(0, 0, 0) )
# New mesh name
objectName = '_'.join(l[1:]) # Use join in case of spaces
while len(meshList[objectName][1]) != len(vertList):
meshList[objectName][1].append(-1)
# Material
elif l[0] == 'usemtl':
if l[1] == '(null)':
currentMat = getMat(NULL_MAT)
@ -393,17 +376,20 @@ def load_obj(file):
mtl_fileName = l[1]
lIdx+=1
#==============================================#
# Write all meshs in the dictionary #
#==============================================#
for mk in meshList.keys():
# Applies material properties to materials alredy on the mesh as well as Textures.
if mtl_fileName != '':
load_mtl(DIR, mtl_fileName, meshList[mk][0])
meshList[mk][0].verts.remove(meshList[mk][0].verts[0])
ob = NMesh.PutRaw(meshList[mk][0], mk[1:])
if ob.name != None:
ob.name = mk[1:]
# Some material stuff
if mtl_fileName != '':
load_mtl(DIR, mtl_fileName, mesh)
# We need to do this to put the last object.
# All other objects will be put alredy
if len(mesh.verts) > 1:
mesh.verts.remove(mesh.verts[0])
ob = NMesh.PutRaw(mesh, fileName + '_' + objectName)
if ob != None: # Name the object too.
ob.name = fileName + '_' + objectName
Window.FileSelector(load_obj, 'Import Wavefront OBJ')

@ -53,8 +53,9 @@ typedef struct ScriptLink {
/* **************** SCRIPTLINKS ********************* */
#define SCRIPT_FRAMECHANGED 1
#define SCRIPT_ONLOAD 2
#define SCRIPT_REDRAW 4
#define SCRIPT_ONLOAD 2
#define SCRIPT_REDRAW 4
#define SCRIPT_ONSAVE 8
#ifdef __cplusplus
}

@ -53,7 +53,8 @@ source_files = ['BPY_interface.c',
'api2_2x/sceneRender.c',
'api2_2x/sceneRadio.c',
'api2_2x/EXPP_interface.c',
'api2_2x/Noise.c']
'api2_2x/Noise.c',
'api2_2x/Sound.c']
python_env.Append (CPPPATH = ['api2_2x',
'../blenkernel',

@ -665,12 +665,18 @@ BGL_Wrap(1, Vertex4iv, void, (GLintP))
BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort))
BGL_Wrap(1, Vertex4sv, void, (GLshortP))
BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei))
BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble))
BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble))
BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP))
BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
/* #endif */
#undef MethodDef
#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"}
#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"}
/* So that MethodDef(Accum) becomes:
* {"glAccum", Method_Accumfunc, METH_VARARGS} */
@ -992,7 +998,12 @@ static struct PyMethodDef BGL_methods[] = {
MethodDef(Vertex4s),
MethodDef(Vertex4sv),
MethodDef(Viewport),
MethodDefu(Perspective),
MethodDefu(LookAt),
MethodDefu(Ortho2D),
MethodDefu(PickMatrix),
MethodDefu(Project),
MethodDefu(UnProject),
/* #endif */
{NULL, NULL, 0, NULL}

@ -420,6 +420,15 @@ static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
ret_ret_##ret; \
}
#define BGLU_Wrap(nargs, funcname, ret, arg_list) \
static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
arg_def##nargs arg_list; \
ret_def_##ret; \
if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
ret_set_##ret glu##funcname (arg_var##nargs arg_list);\
ret_ret_##ret; \
}
/* #endif */
PyObject *BGL_Init(void);

@ -41,6 +41,7 @@
#include <io.h>
#endif
#include <BDR_editobject.h> /* exit_editmode() */
#include <BIF_usiblender.h>
#include <BLI_blenlib.h>
#include <BLO_writefile.h>
@ -391,6 +392,8 @@ static PyObject *Blender_Load(PyObject *self, PyObject *args)
BIF_write_autosave(); /* for safety let's preserve the current data */
}
if (G.obedit) exit_editmode(1);
/* for safety, any filename with .B.blend is considered the default one.
* It doesn't seem necessary to compare file attributes (like st_ino and
* st_dev, according to the glibc info pages) to find out if the given
@ -524,6 +527,7 @@ void M_Blender_Init (void)
PyDict_SetItemString (dict, "Noise", Noise_Init());
PyDict_SetItemString (dict, "Mathutils",Mathutils_Init());
PyDict_SetItemString (dict, "Library", Library_Init());
PyDict_SetItemString (dict, "Sound", Sound_Init());
PyDict_SetItemString (dict, "CurNurb", CurNurb_Init());

@ -0,0 +1,522 @@
/*
* $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): Chris Keith
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#include <BKE_main.h>
#include <BKE_global.h>
#include <BKE_library.h>
#include <BKE_sound.h>
#include <BLI_blenlib.h>
#include <BIF_editsound.h>
#include <BIF_space.h> /* allqueue() */
#include "mydevice.h" /* redraw defines */
#include "gen_utils.h"
#include "Sound.h"
/*****************************************************************************/
/* Python BPy_Sound defaults: */
/*****************************************************************************/
/*****************************************************************************/
/* Python API function prototypes for the Sound module. */
/*****************************************************************************/
static PyObject *M_Sound_New (PyObject *self, PyObject *args,
PyObject *keywords);
static PyObject *M_Sound_Get (PyObject *self, PyObject *args);
static PyObject *M_Sound_Load (PyObject *self, PyObject *args);
/************************************************************************/
/* The following string definitions are used for documentation strings. */
/* In Python these will be written to the console when doing a */
/* Blender.Sound.__doc__ */
/************************************************************************/
static char M_Sound_doc[] =
"The Blender Sound module\n\n";
static char M_Sound_New_doc[] =
"() - return a new Sound object -- unimplemented";
static char M_Sound_Get_doc[] =
"(name) - return the sound with the name 'name', \
returns None if not found.\n If 'name' is not specified, \
it returns a list of all sounds in the\ncurrent scene.";
static char M_Sound_Load_doc[] =
"(filename, redraw = 0) - return sound from file filename as Sound Object,\n\
returns None if not found.";
/*****************************************************************************/
/* Python method structure definition for Blender.Sound module: */
/*****************************************************************************/
struct PyMethodDef M_Sound_methods[] = {
{"New",(PyCFunction)M_Sound_New, METH_VARARGS|METH_KEYWORDS,
M_Sound_New_doc},
{"Get", M_Sound_Get, METH_VARARGS, M_Sound_Get_doc},
{"get", M_Sound_Get, METH_VARARGS, M_Sound_Get_doc},
{"Load", M_Sound_Load, METH_VARARGS, M_Sound_Load_doc},
{NULL, NULL, 0, NULL}
};
/*****************************************************************************/
/* Python Sound_Type callback function prototypes: */
/*****************************************************************************/
static void Sound_dealloc (BPy_Sound *self);
static int Sound_setAttr (BPy_Sound *self, char *name, PyObject *v);
static int Sound_compare (BPy_Sound *a, BPy_Sound *b);
static PyObject *Sound_getAttr (BPy_Sound *self, char *name);
static PyObject *Sound_repr (BPy_Sound *self);
#define SOUND_FLOAT_METHODS(funcname, varname) \
static PyObject *Sound_get ## funcname(BPy_Sound *self) { \
char e[256]; \
PyObject *attr = PyFloat_FromDouble(self->sound->varname); \
if (attr) return attr; \
sprintf(e, "couldn't get Sound.%s attribute", #varname); \
return EXPP_ReturnPyObjError (PyExc_RuntimeError, e); \
} \
static PyObject *Sound_set ## funcname(BPy_Sound *self, PyObject *args) { \
float f = 0; \
if (!PyArg_ParseTuple(args, "f", &f)) \
return (EXPP_ReturnPyObjError (PyExc_TypeError, \
"expected float argument")); \
self->sound->varname = f; \
Py_INCREF(Py_None); \
return Py_None; \
}
#define SOUND_FLOAT_METHOD_FUNCS(varname) \
{"get"#varname, (PyCFunction)Sound_get ## varname, METH_NOARGS, \
"() - Return Sound object "#varname}, \
{"set"#varname, (PyCFunction)Sound_set ## varname, METH_VARARGS, \
"(float) - Change Sound object "#varname},
/*****************************************************************************/
/* Python BPy_Sound methods declarations: */
/*****************************************************************************/
static PyObject *Sound_getName(BPy_Sound *self);
static PyObject *Sound_getFilename(BPy_Sound *self);
static PyObject *Sound_play(BPy_Sound *self);
static PyObject *Sound_makeActive(BPy_Sound *self);
SOUND_FLOAT_METHODS(Volume, volume)
SOUND_FLOAT_METHODS(Panning, panning)
SOUND_FLOAT_METHODS(Attenuation, attenuation)
SOUND_FLOAT_METHODS(Pitch, pitch)
SOUND_FLOAT_METHODS(MinGain, min_gain)
SOUND_FLOAT_METHODS(MaxGain, max_gain)
SOUND_FLOAT_METHODS(Distance, distance)
/*****************************************************************************/
/* Python BPy_Sound methods table: */
/*****************************************************************************/
static PyMethodDef BPy_Sound_methods[] = {
/* name, method, flags, doc */
{"getName", (PyCFunction)Sound_getName, METH_NOARGS,
"() - Return Sound object name"},
{"getFilename", (PyCFunction)Sound_getFilename, METH_NOARGS,
"() - Return Sound object filename"},
{"play", (PyCFunction)Sound_play, METH_NOARGS,
"() - play this sound"},
{"makeActive", (PyCFunction)Sound_makeActive, METH_NOARGS,
"() - make this the active sound in the sound buttons win (also redraws)"},
SOUND_FLOAT_METHOD_FUNCS(Volume)
SOUND_FLOAT_METHOD_FUNCS(Panning)
SOUND_FLOAT_METHOD_FUNCS(Attenuation)
SOUND_FLOAT_METHOD_FUNCS(Pitch)
SOUND_FLOAT_METHOD_FUNCS(MinGain)
SOUND_FLOAT_METHOD_FUNCS(MaxGain)
SOUND_FLOAT_METHOD_FUNCS(Distance)
{NULL, NULL, 0, NULL}
};
/*****************************************************************************/
/* Python Sound_Type structure definition: */
/*****************************************************************************/
PyTypeObject Sound_Type =
{
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"Blender Sound", /* tp_name */
sizeof (BPy_Sound), /* tp_basicsize */
0, /* tp_itemsize */
/* methods */
(destructor)Sound_dealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc)Sound_getAttr, /* tp_getattr */
(setattrfunc)Sound_setAttr, /* tp_setattr */
(cmpfunc)Sound_compare, /* tp_compare */
(reprfunc)Sound_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_as_hash */
0,0,0,0,0,0,
0, /* tp_doc */
0,0,0,0,0,0,
BPy_Sound_methods, /* tp_methods */
0, /* tp_members */
};
/*****************************************************************************/
/* Function: M_Sound_New */
/* Python equivalent: Blender.Sound.New */
/*****************************************************************************/
static PyObject *M_Sound_New(PyObject *self, PyObject *args, PyObject *keywords)
{
printf ("In Sound_New() - unimplemented in 2.34\n");
Py_INCREF(Py_None);
return Py_None;
}
/* NOTE: these were copied and modified from image.h. To Be Done TBD:
* macro-ize them, or C++ templates eventually?
*/
/********************************************************************************/
/* Function: M_Sound_Get */
/* Python equivalent: Blender.Sound.Get */
/* Description: Receives a string and returns the Sound object */
/* whose name matches the string. If no argument is */
/* passed in, a list of all Sound names in the */
/* current scene is returned. */
/*********************************************************************************/
static PyObject *M_Sound_Get(PyObject *self, PyObject *args)
{
char *name = NULL;
bSound *snd_iter;
if (!PyArg_ParseTuple(args, "|s", &name))
return (EXPP_ReturnPyObjError (PyExc_TypeError,
"expected string argument (or nothing)"));
snd_iter = G.main->sound.first;
if (name) { /* (name) - Search Sound by name */
BPy_Sound *wanted_Sound = NULL;
while ((snd_iter) && (wanted_Sound == NULL)) {
if (strcmp (name, snd_iter->id.name+2) == 0) {
wanted_Sound = (BPy_Sound *)PyObject_NEW(BPy_Sound, &Sound_Type);
if (wanted_Sound) {
wanted_Sound->sound = snd_iter;
break;
}
}
snd_iter = snd_iter->id.next;
}
if (wanted_Sound == NULL) { /* Requested Sound doesn't exist */
char error_msg[64];
PyOS_snprintf(error_msg, sizeof(error_msg),
"Sound \"%s\" not found", name);
return (EXPP_ReturnPyObjError (PyExc_NameError, error_msg));
}
return (PyObject *)wanted_Sound;
}
else { /* () - return a list of all Sounds in the scene */
int index = 0;
PyObject *snd_list, *pyobj;
snd_list = PyList_New (BLI_countlist (&(G.main->sound)));
if (snd_list == NULL)
return (EXPP_ReturnPyObjError (PyExc_MemoryError,
"couldn't create PyList"));
while (snd_iter) {
pyobj = Sound_CreatePyObject (snd_iter);
if (!pyobj)
return (EXPP_ReturnPyObjError (PyExc_MemoryError,
"couldn't create PyObject"));
PyList_SET_ITEM (snd_list, index, pyobj);
snd_iter = snd_iter->id.next;
index++;
}
return (snd_list);
}
}
/*****************************************************************************/
/* Function: M_Sound_Load */
/* Python equivalent: Blender.Sound.Load */
/* Description: Receives a string and returns the Sound object */
/* whose filename matches the string. */
/*****************************************************************************/
static PyObject *M_Sound_Load(PyObject *self, PyObject *args)
{
char *fname;
bSound *snd_ptr;
BPy_Sound *snd;
if (!PyArg_ParseTuple(args, "s", &fname))
return (EXPP_ReturnPyObjError (PyExc_TypeError,
"expected string argument"));
snd = (BPy_Sound *)PyObject_NEW(BPy_Sound, &Sound_Type);
if (!snd)
return (EXPP_ReturnPyObjError (PyExc_MemoryError,
"couldn't create PyObject Sound_Type"));
snd_ptr = sound_new_sound(fname);
if (snd_ptr) {
if (G.ssound) {
G.ssound->sound= snd_ptr;
}
}
if (!snd_ptr)
return (EXPP_ReturnPyObjError (PyExc_IOError,
"not a valid sound sample"));
snd->sound = snd_ptr;
return (PyObject *)snd;
}
/*****************************************************************************/
/* Function: Sound_Init */
/*****************************************************************************/
PyObject *Sound_Init (void)
{
PyObject *submodule;
Sound_Type.ob_type = &PyType_Type;
submodule = Py_InitModule3("Blender.Sound", M_Sound_methods, M_Sound_doc);
return (submodule);
}
/************************/
/*** The Sound PyType ***/
/************************/
/*****************************************************************************/
/* Function: Sound_dealloc */
/* Description: This is a callback function for the BPy_Sound type. It is */
/* the destructor function. */
/*****************************************************************************/
static void Sound_dealloc (BPy_Sound *self)
{
PyObject_DEL (self);
}
/*****************************************************************************/
/* Function: Sound_CreatePyObject */
/* Description: This function will create a new BPy_Sound from an existing */
/* Blender Sound structure. */
/*****************************************************************************/
PyObject *Sound_CreatePyObject (bSound *snd)
{
BPy_Sound *py_snd;
py_snd = (BPy_Sound *)PyObject_NEW (BPy_Sound, &Sound_Type);
if (!py_snd)
return EXPP_ReturnPyObjError (PyExc_MemoryError,
"couldn't create BPy_Sound object");
py_snd->sound = snd;
return (PyObject *)py_snd;
}
/*****************************************************************************/
/* Function: Sound_CheckPyObject */
/* Description: This function returns true when the given PyObject is of the */
/* type Sound. Otherwise it will return false. */
/*****************************************************************************/
int Sound_CheckPyObject (PyObject *pyobj)
{
return (pyobj->ob_type == &Sound_Type);
}
/*****************************************************************************/
/* Function: Sound_FromPyObject */
/* Description: Returns the Blender Sound associated with this object */
/*****************************************************************************/
bSound *Sound_FromPyObject (PyObject *pyobj)
{
return ((BPy_Sound *)pyobj)->sound;
}
/*****************************************************************************/
/* Python BPy_Sound methods: */
/*****************************************************************************/
static PyObject *Sound_getName(BPy_Sound *self)
{
PyObject *attr = PyString_FromString(self->sound->id.name+2);
if (attr) return attr;
return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
"couldn't get Sound.name attribute"));
}
static PyObject *Sound_getFilename(BPy_Sound *self)
{
PyObject *attr = PyString_FromString(self->sound->name);
if (attr) return attr;
return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
"couldn't get Sound.filename attribute"));
}
static PyObject *Sound_play(BPy_Sound *self)
{
sound_play_sound(self->sound);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *Sound_makeActive(BPy_Sound *self)
{
bSound *snd_ptr = self->sound;
if (snd_ptr) {
if (G.ssound) {
G.ssound->sound = snd_ptr;
}
}
allqueue(REDRAWSOUND, 0);
allqueue(REDRAWBUTSLOGIC, 0);
Py_INCREF (Py_None);
return Py_None;
}
/*****************************************************************************/
/* Function: Sound_getAttr */
/* Description: This is a callback function for the BPy_Sound type. It is */
/* the function that accesses BPy_Sound member variables and */
/* methods. */
/*****************************************************************************/
static PyObject *Sound_getAttr (BPy_Sound *self, char *name)
{
PyObject *attr = Py_None;
if (strcmp(name, "name") == 0)
attr = PyString_FromString(self->sound->id.name+2);
else if (strcmp(name, "filename") == 0)
attr = PyString_FromString(self->sound->name);
else if (strcmp(name, "__members__") == 0)
attr = Py_BuildValue("[s,s]",
"name", "filename");
if (!attr)
return (EXPP_ReturnPyObjError (PyExc_MemoryError,
"couldn't create PyObject"));
if (attr != Py_None) return attr; /* attribute found, return its value */
/* not an attribute, search the methods table */
return Py_FindMethod(BPy_Sound_methods, (PyObject *)self, name);
}
/*****************************************************************************/
/* Function: Sound_setAttr */
/* Description: This is a callback function for the BPy_Sound type. It is the*/
/* function that changes Sound object members values. If this */
/* data is linked to a Blender Sound, it also gets updated. */
/*****************************************************************************/
static int Sound_setAttr (BPy_Sound *self, char *name, PyObject *value)
{
PyObject *valtuple;
PyObject *error = NULL;
/* We're playing a trick on the Python API users here. Even if they use
* Sound.member = val instead of Sound.setMember(value), we end up using the
* function anyway, since it already has error checking, clamps to the right
* interval and updates the Blender Sound structure when necessary. */
valtuple = Py_BuildValue("(O)", value); /*the set* functions expect a tuple*/
if (!valtuple)
return EXPP_ReturnIntError(PyExc_MemoryError,
"SoundSetAttr: couldn't create PyTuple");
/* if (strcmp (name, "name") == 0)
error = Sound_setName (self, valtuple);
else */ {
/* Error: no such member in the Sound object structure */
Py_DECREF(value);
Py_DECREF(valtuple);
return (EXPP_ReturnIntError (PyExc_KeyError,
"attribute not found or immutable"));
}
Py_DECREF(valtuple);
if (error != Py_None) return -1;
Py_DECREF(Py_None); /* incref'ed by the called set* function */
return 0; /* normal exit */
}
/*****************************************************************************/
/* Function: Sound_compare */
/* Description: This is a callback function for the BPy_Sound type. It */
/* compares two Sound_Type objects. Only the "==" and "!=" */
/* comparisons are meaninful. Returns 0 for equality and -1 if */
/* they don't point to the same Blender Sound struct. */
/* In Python it becomes 1 if they are equal, 0 otherwise. */
/*****************************************************************************/
static int Sound_compare (BPy_Sound *a, BPy_Sound *b)
{
bSound *pa = a->sound, *pb = b->sound;
return (pa == pb) ? 0:-1;
}
/*****************************************************************************/
/* Function: Sound_repr */
/* Description: This is a callback function for the BPy_Sound type. It */
/* builds a meaninful string to represent Sound objects. */
/*****************************************************************************/
static PyObject *Sound_repr (BPy_Sound *self)
{
return PyString_FromFormat("[Sound \"%s\"]", self->sound->id.name+2);
}

@ -0,0 +1,57 @@
/*
* $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): Chris Keith
*
* ***** END GPL/BL DUAL LICENSE BLOCK *****
*/
#ifndef EXPP_SOUND_H
#define EXPP_SOUND_H
#include <Python.h>
#include <DNA_sound_types.h>
/*****************************************************************************/
/* Python BPy_Sound structure definition */
/*****************************************************************************/
typedef struct {
PyObject_HEAD
bSound *sound;
} BPy_Sound;
/*****************************************************************************/
/* Module Blender.Sound - public functions */
/*****************************************************************************/
PyObject *Sound_Init (void);
PyObject *Sound_CreatePyObject (bSound *sound);
bSound *Sound_FromPyObject (PyObject *pyobj);
int Sound_CheckPyObject (PyObject *pyobj);
#endif /* EXPP_SOUND_H */

@ -765,17 +765,20 @@ static PyObject *M_Window_GetViewMatrix(PyObject *self)
static PyObject *M_Window_EditMode(PyObject *self, PyObject *args)
{
short status = -1;
char *undo_str = "From script";
int undo_str_len = 11;
if (!PyArg_ParseTuple(args, "|h", &status))
if (!PyArg_ParseTuple(args, "|hs#", &status, &undo_str, &undo_str_len))
return EXPP_ReturnPyObjError (PyExc_TypeError,
"expected nothing or an int (bool) as argument");
"expected nothing or an int (bool) and a string as arguments");
if (status >= 0) {
if (status) {
if (!G.obedit) enter_editmode();
}
else if (G.obedit) {
undo_push_mesh("From script"); /* use better solution after 2.34 */
if (undo_str_len > 63) undo_str[63] = '\0'; /* 64 is max */
undo_push_mesh(undo_str); /* use better solution after 2.34 */
exit_editmode(1);
}
}

@ -7,39 +7,39 @@ The Blender Python API Reference
Top Module:
-----------
- L{Blender} (*)
- L{Blender}
Submodules:
-----------
- L{Armature}
- L{Bone}
- L{NLA}
- L{BGL}
- L{Camera} (*)
- L{Curve} (*)
- L{Draw} (*)
- L{BGL} (*)
- L{Camera}
- L{Curve}
- L{Draw}
- L{Effect}
- L{Image} (*)
- L{Ipo} (*)
- L{Lamp} (*)
- L{Image}
- L{Ipo}
- L{Lamp}
- L{Lattice}
- L{Library}
- L{Material} (*)
- L{Material}
- L{Mathutils}
- L{Metaball} (*)
- L{Metaball}
- L{NMesh}
- L{Noise}
- L{Object} (*)
- L{Object}
- L{Registry}
- L{Scene} (*)
- L{Radio} (new)
- L{Scene}
- L{Radio}
- L{Render}
- L{Text}
- L{Texture} (*)
- L{Texture}
- L{Types}
- L{Window} (* important: L{Window.EditMode})
- L{World} (*)
- L{sys<Sys>} (*)
- L{Window}
- L{World}
- L{sys<Sys>}
(*) - marks updated.
@ -177,24 +177,30 @@ The Game Engine API:
Blender Data Structures:
------------------------
Programs manipulate data structures. Blender python scripts are no exception.
Blender uses an Object Oriented architecture. The bpython interface tries to
present Blender objects and their attributes in the same way you see them through
the User Interface ( the GUI ). One key to bpython programming is understanding
the information presented in Blender's OOPS window where Blender objects and their
relationships are displayed.
Programs manipulate data structures. Blender python scripts are no exception.
Blender uses an Object Oriented architecture. The bpython interface tries to
present Blender objects and their attributes in the same way you see them
through the User Interface ( the GUI ). One key to bpython programming is
understanding the information presented in Blender's OOPS window where Blender
objects and their relationships are displayed.
Each Blender graphic element ( Mesh, Lamp, Curve, etc.) is composed from two parts:
An Object and ObData. The Object holds information about the position, rotation and size
of the element. This is information that all elements have in common. The ObData holds
information specific to that particular type of element.
Each Blender graphic element (Mesh, Lamp, Curve, etc.) is composed from two
parts: an Object and ObData. The Object holds information about the position,
rotation and size of the element. This is information that all elements have
in common. The ObData holds information specific to that particular type of
element.
Each Object has a link to its associated ObData. A single ObData may be shared by many Objects. A graphic element also has a link to a list of Materials. By default, this list is associated with the ObData.
Each Object has a link to its associated ObData. A single ObData may be
shared by many Objects. A graphic element also has a link to a list of
Materials. By default, this list is associated with the ObData.
All Blender objects have a unique name. However, the name is qualified by the type of the object. This means you can have a Lamp Object called Lamp.001 ( OB:Lamp.001 ) and a Lamp ObData called Lamp.001 ( LA:Lamp.001 )
All Blender objects have a unique name. However, the name is qualified by the
type of the object. This means you can have a Lamp Object called Lamp.001
(OB:Lamp.001) and a Lamp ObData called Lamp.001 (LA:Lamp.001).
For a more in-depth look at Blender internals, and some understanding of why
Blender works the way it does, see the U{Blender Architecture document<http://www.blender3d.org/cms/Blender_Architecture.336.0.html>}.
For a more in-depth look at Blender internals, and some understanding of why
Blender works the way it does, see the U{Blender Architecture document
<http://www.blender3d.org/cms/Blender_Architecture.336.0.html>}.
A note to newbie script writers:
--------------------------------
@ -207,7 +213,7 @@ A note to newbie script writers:
@author: The Blender Python Team
@requires: Blender 2.34 or newer.
@version: 2.34
@version: 2.34cvs
@see: U{www.blender3d.org<http://www.blender3d.org>}: main site
@see: U{www.blender.org<http://www.blender.org>}: documentation and forum
@see: U{www.elysiun.com<http://www.elysiun.com>}: user forum
@ -217,4 +223,13 @@ A note to newbie script writers:
@see: U{www.python.org/doc<http://www.python.org/doc>}
@note: this documentation was generated by epydoc, which can output html and
pdf. For pdf it requires a working LaTeX environment.
@note: the official version of this reference guide is only updated for each
new Blender release. But it is simple to build yourself current cvs
versions of this text: install epydoc, grab all files in the
source/blender/python/api2_2x/doc/ folder of Blender's cvs and use the
epy_docgen.sh script also found there to generate the html docs.
Naturally you will also need a recent Blender binary to try the new
features. If you prefer not to compile it yourself, there is a testing
builds forum at U{blender.org<http://www.blender.org>}.
"""

@ -3,6 +3,8 @@
"""
The Blender.BGL submodule (the OpenGL wrapper).
B{New}: some GLU functions: L{gluLookAt}, etc.
The Blender.BGL submodule
=========================
@ -1603,9 +1605,97 @@ def glViewport(x,y,width,height):
is first attached to a window, width and height are set to the dimensions of that window.
"""
def gluPerspective(fovY, aspect, zNear, zFar):
"""
Set up a perspective projection matrix.
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5557116}
@type fovY: double
@param fovY: Specifies the field of view angle, in degrees, in the y direction.
@type aspect: double
@param aspect: Specifies the aspect ratio that determines the field of view in the x direction.
The aspect ratio is the ratio of x (width) to y (height).
@type zNear: double
@param zNear: Specifies the distance from the viewer to the near clipping plane (always positive).
@type zFar: double
@param zFar: Specifies the distance from the viewer to the far clipping plane (always positive).
"""
def gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz):
"""
Define a viewing transformation
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5552781}
@type eyex, eyey, eyez: double
@param eyex, eyey, eyez: Specifies the position of the eye point.
@type centerx, centery, centerz: double
@param centerx, centery, centerz: Specifies the position of the reference point.
@type upx, upy, upz: double
@param upx, upy, upz: Specifies the direction of the up vector.
"""
def gluOrtho2D(left, right, bottom, top):
"""
Define a 2-D orthographic projection matrix
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5556407}
@type left, right: double
@param left, right: Specify the coordinates for the left and right vertical clipping planes.
@type bottom, top: double
@param bottom, top: Specify the coordinates for the bottom and top horizontal clipping planes.
"""
def gluPickMatrix(x, y, width, height, viewport):
"""
Define a picking region
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5557442}
@type x, y: double
@param x, y: Specify the center of a picking region in window coordinates.
@type width, height: double
@param width, height: Specify the width and height, respectively, of the picking region in window coordinates.
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport.
"""
def gluProject(objx, objy, objz, modelMatrix, projMatrix, viewport, winx, winy, winz):
"""
Map object coordinates to window coordinates.
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5557853}
@type objx, objy, objz: double
@param objx, objy, objz: Specify the object coordinates.
@type modelMatrix: Buffer object. [double]
@param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
@type projMatrix: Buffer object. [double]
@param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport (as from a glGetIntegerv call).
@type winx, winy, winz: Buffer object. [double]
@param winx, winy, winz: Return the computed window coordinates.
"""
def gluUnProject(winx, winy, winz, modelMatrix, projMatrix, viewport, objx, objy, objz):
"""
Map object coordinates to window
coordinates.
@see: U{http://www.parallab.uib.no/SGI_bookshelves/SGI_Developer/books/OpenGL_RM/sgi_html/ch06.html#id5557853}
@type winx, winy, winz: double
@param winx, winy, winz: Specify the window coordinates to be mapped.
@type modelMatrix: Buffer object. [double]
@param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
@type projMatrix: Buffer object. [double]
@param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
@type viewport: Buffer object. [int]
@param viewport: Specifies the current viewport (as from a glGetIntegerv call).
@type objx, objy, objz: Buffer object. [double]
@param objx, objy, objz: Return the computed object coordinates.
"""
class Buffer:
"""
The Buffer object is simply a block of memory that is delineated and initalized by the
The Buffer object is simply a block of memory that is delineated and initialized by the
user. Many OpenGL funtions return data to a C-style pointer, however, because this
is not possible in python the Buffer object can be used to this end. Wherever pointer
notation is used in the OpenGL functions the Buffer object can be used in it's BGL
@ -1651,16 +1741,3 @@ class Buffer:
@rtype: Buffer object
@return: The newly created buffer as a PyObject.
"""

@ -75,6 +75,8 @@ def Load (filename = None):
script to previously defined data will generate a NameError. So it's
better to put Blender.Load as the last executed command in the script,
when this function is used to open .blend files.
@warn: if in edit mode, this function leaves it, since Blender itself
requires that.
"""
def Save (filename, overwrite = 0):

@ -3,8 +3,7 @@
"""
The Blender.Scene submodule.
B{New}: L{Scene.play}; scriptLink methods: L{Scene.getScriptLinks}, etc;
L{Scene.getRadiosityContext}
B{New}: OnSave script link event: L{Scene.getScriptLinks}.
Scene
=====
@ -174,7 +173,7 @@ class Scene:
"""
Get a list with this Scene's script links of type 'event'.
@type event: string
@param event: "FrameChanged", "OnLoad" or "Redraw".
@param event: "FrameChanged", "OnLoad", "OnSave" or "Redraw".
@rtype: list
@return: a list with Blender L{Text} names (the script links of the given
'event' type) or None if there are no script links at all.
@ -193,7 +192,7 @@ class Scene:
@type text: string
@param text: the name of an existing Blender L{Text}.
@type event: string
@param event: "FrameChanged", "OnLoad" or "Redraw".
@param event: "FrameChanged", "OnLoad", "OnSave" or "Redraw".
"""
def play (mode = 0, win = '<VIEW3D>'):

@ -201,7 +201,7 @@ def GetViewMatrix ():
@return: the current matrix.
"""
def EditMode(enable = -1):
def EditMode(enable = -1, undo_msg = 'From script'):
"""
Get and optionally set the current edit mode status: in or out.
@ -221,7 +221,12 @@ def EditMode(enable = -1):
- 1: enter edit mode.
It's not an error to try to change to a state that is already the
current one, the function simply ignores the request.
current one, the function simply ignores the request.
@type undo_msg: string
@param undo_msg: only needed when exiting edit mode (EditMode(0)). This
string is used as the undo message in the Mesh->Undo History submenu in
the 3d view header. Max length is 63, strings longer than that get
clamped.
@rtype: int (bool)
@return: 0 if Blender is not in edit mode right now, 1 otherwise.
@warn: this is an important function. NMesh operates on normal Blender

@ -130,6 +130,8 @@ char * event_to_name(short event)
return "FrameChanged";
case SCRIPT_ONLOAD:
return "OnLoad";
case SCRIPT_ONSAVE:
return "OnSave";
case SCRIPT_REDRAW:
return "Redraw";
default:
@ -272,9 +274,11 @@ PyObject *EXPP_getScriptLinks (ScriptLink *slink, PyObject *args, int is_scene)
event = SCRIPT_REDRAW;
else if (is_scene && !strcmp(eventname, "OnLoad"))
event = SCRIPT_ONLOAD;
else if (is_scene && !strcmp(eventname, "OnSave"))
event = SCRIPT_ONSAVE;
else
return EXPP_ReturnPyObjError (PyExc_AttributeError,
"invalid event name.");
"invalid event name");
for (i = 0; i < slink->totscript; i++) {
if ((slink->flag[i] == event) && slink->scripts[i])
@ -335,6 +339,8 @@ int EXPP_addScriptLink (ScriptLink *slink, PyObject *args, int is_scene)
event = SCRIPT_REDRAW;
else if (is_scene && !strcmp(eventname, "OnLoad"))
event = SCRIPT_ONLOAD;
else if (is_scene && !strcmp(eventname, "OnSave"))
event = SCRIPT_ONSAVE;
else
return EXPP_ReturnIntError (PyExc_AttributeError,
"invalid event name.");

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

@ -231,10 +231,11 @@ void draw_scriptlink(uiBlock *block, ScriptLink *script, int sx, int sy, int sce
strcpy(str, "FrameChanged%x 1|");
strcat(str, "Redraw%x 4|");
if (scene) {
strcat(str, "OnLoad%x 2");
strcat(str, "OnLoad%x 2|");
strcat(str, "OnSave%x 8");
}
uiDefButS(block, MENU, 1, str, (short)sx, (short)sy, 140, 19, &script->flag[script->actscript-1], 0, 0, 0, 0, "Script links for the Frame changed event");
uiDefButS(block, MENU, 1, str, (short)sx, (short)sy, 140, 19, &script->flag[script->actscript-1], 0, 0, 0, 0, "Script links for this event");
uiDefIDPoinBut(block, test_scriptpoin_but, 1, "", (short)(sx+140),(short)sy, 140, 19, &script->scripts[script->actscript-1], "Name of Script to link");
}

@ -91,13 +91,21 @@ void drawscriptspace(ScrArea *sa, void *spacedata)
glClear(GL_COLOR_BUFFER_BIT);
myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5);
if(!sc->script) {
if (G.main->script.first)
sc->script = G.main->script.first;
else
return;
if (!sc->script) {
Script *script = G.main->script.first;
while (script) {
if (script->py_draw || script->py_event || script->py_button) {
sc->script = script;
break;
}
else script = script->id.next;
}
}
if (!sc->script) return;
BPY_spacescript_do_pywin_draw(sc);
}

@ -371,7 +371,12 @@ void BIF_write_file(char *target)
char *err;
if (BLI_streq(target, "")) return;
/*Send the OnSave event*/
if (G.f & G_SCENESCRIPT) {
BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE);
}
for (li= G.main->library.first; li; li= li->id.next) {
if (BLI_streq(li->name, target)) {
error("Cannot overwrite used library");