Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Luc Peurière <jlp@nerim.net>2008-03-21 20:00:40 +0300
committerJean-Luc Peurière <jlp@nerim.net>2008-03-21 20:00:40 +0300
commit32b5138e6459df5298ca50865dafab4d22a4aeed (patch)
tree8ba947a61d91fe051e9c3a864f5e0ca61968bca1 /source/blender/python
parent473ba6ac718bc32b4fc6c6aee4d03673cf62936c (diff)
parentdf1ba7da75f9b82f81693d5e0adfec29b2f4a424 (diff)
update to trunk r14199ndof
Diffstat (limited to 'source/blender/python')
-rw-r--r--source/blender/python/BPY_extern.h4
-rw-r--r--source/blender/python/BPY_interface.c53
-rw-r--r--source/blender/python/api2_2x/Blender.c11
-rw-r--r--source/blender/python/api2_2x/Constraint.c193
-rw-r--r--source/blender/python/api2_2x/Draw.c7
-rw-r--r--source/blender/python/api2_2x/Library.c20
-rw-r--r--source/blender/python/api2_2x/Mesh.c178
-rw-r--r--source/blender/python/api2_2x/Node.c658
-rw-r--r--source/blender/python/api2_2x/Node.h21
-rw-r--r--source/blender/python/api2_2x/SurfNurb.c63
-rw-r--r--source/blender/python/api2_2x/Window.c20
-rw-r--r--source/blender/python/api2_2x/doc/Constraint.py22
-rw-r--r--source/blender/python/api2_2x/doc/Curve.py4
-rw-r--r--source/blender/python/api2_2x/doc/IpoCurve.py2
-rw-r--r--source/blender/python/api2_2x/doc/Mesh.py38
-rw-r--r--source/blender/python/api2_2x/doc/Render.py1
-rw-r--r--source/blender/python/api2_2x/sceneRender.c6
17 files changed, 1081 insertions, 220 deletions
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
index d7bd4f22fc6..bf7c4d7ad62 100644
--- a/source/blender/python/BPY_extern.h
+++ b/source/blender/python/BPY_extern.h
@@ -128,7 +128,9 @@ extern "C" {
void BPY_clear_script( struct Script *script );
void BPY_free_finished_script( struct Script *script );
void BPY_scripts_clear_pyobjects( void );
-
+
+ void error_pyscript( void );
+
/* void BPY_Err_Handle(struct Text *text); */
/* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */
/* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
index febf5e3ff31..1f028e49070 100644
--- a/source/blender/python/BPY_interface.c
+++ b/source/blender/python/BPY_interface.c
@@ -261,6 +261,7 @@ void BPY_start_python( int argc, char **argv )
void BPY_end_python( void )
{
Script *script = NULL;
+ Script *next_script = NULL;
PyGILState_Ensure(); /* finalizing, no need to grab the state */
@@ -281,8 +282,8 @@ void BPY_end_python( void )
/* Freeing all scripts here prevents problems with the order in which
* Python is finalized and G.main is freed in exit_usiblender() */
- for (script = G.main->script.first; script; script = script->id.next) {
- BPY_clear_script(script);
+ for (script = G.main->script.first; script; script = next_script) {
+ next_script = script->id.next;
free_libblock( &G.main->script, script );
}
@@ -691,8 +692,7 @@ int BPY_txt_do_python_Text( struct Text *text )
BPY_Err_Handle( textname );
ReleaseGlobalDictionary( py_dict );
script->py_globaldict = NULL;
- if( G.main->script.first )
- free_libblock( &G.main->script, script );
+ free_libblock( &G.main->script, script );
PyGILState_Release(gilstate);
return 0;
} else {
@@ -785,14 +785,23 @@ int BPY_run_script(Script *script)
char fname[FILE_MAX];
char fpath[FILE_MAX];
char ftmp[FILE_MAX];
+ char *bpyhome = bpy_gethome(1);
- strcpy(ftmp, script->scriptname);
- BLI_split_dirfile(ftmp, fpath, fname);
- BLI_make_file_string("/", fpath, bpy_gethome(1), fname);
+ if (bpyhome) {
+ BLI_strncpy(ftmp, script->scriptname, sizeof(ftmp));
+ BLI_split_dirfile(ftmp, fpath, fname); /* get the filename only - fname */
+ BLI_strncpy(fpath, bpy_gethome(1), sizeof(fpath));
+ BLI_add_slash(fpath);
+ strcat(fpath, fname);
- if (BLI_exists(fpath)) {
- strncpy(script->scriptname, fpath, sizeof(script->scriptname));
- } else if (U.pythondir[0]) {
+ if (BLI_exists(fpath)) {
+ strncpy(script->scriptname, fpath, sizeof(script->scriptname));
+ } else {
+ bpyhome = NULL; /* a bit dodgy, this is so the line below runs */
+ }
+ }
+
+ if (bpyhome == NULL && U.pythondir[0]) {
BLI_make_file_string("/", fpath, U.pythondir, fname);
if (BLI_exists(fpath)) {
strncpy(script->scriptname, fpath, sizeof(script->scriptname));
@@ -812,11 +821,13 @@ int BPY_run_script(Script *script)
Py_INCREF( Py_None );
pyarg = Py_None;
} else {
- fp = fopen( script->scriptname, "rb" );
+ if (BLI_exists(script->scriptname)) {
+ fp = fopen( script->scriptname, "rb" );
+ }
+
if( !fp ) {
printf( "Error loading script: couldn't open file %s\n", script->scriptname );
- if( G.main->script.first )
- free_libblock( &G.main->script, script );
+ free_libblock( &G.main->script, script );
PyGILState_Release(gilstate);
return 0;
}
@@ -842,8 +853,7 @@ int BPY_run_script(Script *script)
if( !setup_armature_weakrefs()){
printf("Oops - weakref dict\n");
- if( G.main->script.first )
- free_libblock( &G.main->script, script );
+ free_libblock( &G.main->script, script );
ReleaseGlobalDictionary( py_dict );
MEM_freeN( buffer );
PyGILState_Release(gilstate);
@@ -910,9 +920,8 @@ int BPY_run_script(Script *script)
BPY_Err_Handle( script->id.name + 2 );
ReleaseGlobalDictionary( py_dict );
script->py_globaldict = NULL;
- if( G.main->script.first )
- free_libblock( &G.main->script, script );
- error( "Python script error: check console" );
+ free_libblock( &G.main->script, script );
+ error_pyscript( );
PyGILState_Release(gilstate);
return 0;
@@ -1110,7 +1119,7 @@ void BPY_free_finished_script( Script * script )
if( PyErr_Occurred( ) ) { /* if script ended after filesel */
PyErr_Print( ); /* eventual errors are handled now */
- error( "Python script error: check console" );
+ error_pyscript( );
}
PyGILState_Release(gilstate);
@@ -1146,6 +1155,7 @@ static void unlink_script( Script * script )
}
}
+/* This is called from free_libblock( &G.main->script, script ); */
void BPY_clear_script( Script * script )
{
PyObject *dict;
@@ -2015,6 +2025,7 @@ float BPY_pydriver_eval(IpoDriver *driver)
}
result = ( float )PyFloat_AsDouble( retval );
+ Py_DECREF(retval);
if (result == -1 && PyErr_Occurred()) {
result = pydriver_error(driver);
@@ -2961,3 +2972,7 @@ void BPY_scripts_clear_pyobjects( void )
SCRIPT_SET_NULL(script)
}
}
+void error_pyscript( void )
+{
+ error("Python script error: check console");
+}
diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c
index d520dded486..dbcd21f04f3 100644
--- a/source/blender/python/api2_2x/Blender.c
+++ b/source/blender/python/api2_2x/Blender.c
@@ -865,8 +865,15 @@ static PyObject *Blender_Run(PyObject *self, PyObject *value)
if (script) script->flags |= SCRIPT_RUNNING; /* set */
- if (!is_blender_text) free_libblock(&G.main->text, text);
-
+ if (!is_blender_text) {
+
+ /* nice to remember the original filename, so the script can run on reload */
+ if (script) {
+ strncpy(script->scriptname, fname, sizeof(script->scriptname));
+ script->scriptarg[0] = '\0';
+ }
+ free_libblock(&G.main->text, text);
+ }
Py_RETURN_NONE;
}
diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c
index 9ca0d8d2545..844b9cc99ad 100644
--- a/source/blender/python/api2_2x/Constraint.c
+++ b/source/blender/python/api2_2x/Constraint.c
@@ -114,6 +114,8 @@ enum constraint_constants {
EXPP_CONSTR_LIMIT,
EXPP_CONSTR_CLAMP,
+ EXPP_CONSTR_MODE,
+
EXPP_CONSTR_LIMXMIN = LIMIT_XMIN,
EXPP_CONSTR_LIMXMAX = LIMIT_XMAX,
EXPP_CONSTR_LIMYMIN = LIMIT_YMIN,
@@ -904,6 +906,56 @@ static int stretchto_setter( BPy_Constraint *self, int type, PyObject *value )
}
}
+static PyObject *distlimit_getter( BPy_Constraint * self, int type )
+{
+ bDistLimitConstraint *con = (bDistLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_RESTLENGTH:
+ return PyFloat_FromDouble( (double)con->dist );
+ case EXPP_CONSTR_MODE:
+ return PyInt_FromLong( (long)con->mode );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int distlimit_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bDistLimitConstraint *con = (bDistLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_RESTLENGTH:
+ return EXPP_setFloatClamped( value, &con->dist, 0.0, 100.0 );
+ case EXPP_CONSTR_MODE:
+ return EXPP_setIValueRange( value, &con->mode, LIMITDIST_INSIDE, LIMITDIST_ONSURFACE, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
static PyObject *followpath_getter( BPy_Constraint * self, int type )
{
bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data);
@@ -1391,11 +1443,40 @@ static PyObject *script_getter( BPy_Constraint * self, int type )
bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
switch( type ) {
- // FIXME!!!
- //case EXPP_CONSTR_TARGET:
- // return Object_CreatePyObject( con->tar );
- //case EXPP_CONSTR_BONE:
- // return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_TARGET:
+ case EXPP_CONSTR_BONE:
+ {
+ bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_PYTHON);
+ bConstraintTarget *ct;
+ PyObject *tlist=NULL, *val;
+
+ if (cti) {
+ /* change space of targets */
+ if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+ int num_tars=0, i=0;
+
+ /* get targets, and create py-list for use temporarily */
+ num_tars= cti->get_constraint_targets(self->con, &targets);
+ if (num_tars) {
+ tlist= PyList_New(num_tars);
+
+ for (ct=targets.first; ct; ct=ct->next, i++) {
+ if (type == EXPP_CONSTR_BONE)
+ val= PyString_FromString(ct->subtarget);
+ else
+ val= Object_CreatePyObject(ct->tar);
+ PyList_SET_ITEM(tlist, i, val);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(self->con, &targets, 1);
+ }
+ }
+
+ return tlist;
+ }
case EXPP_CONSTR_SCRIPT:
return Text_CreatePyObject( con->text );
case EXPP_CONSTR_PROPS:
@@ -1410,25 +1491,73 @@ static int script_setter( BPy_Constraint *self, int type, PyObject *value )
bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
switch( type ) {
- // FIXME!!!
- //case EXPP_CONSTR_TARGET: {
- // Object *obj = (( BPy_Object * )value)->object;
- // if( !BPy_Object_Check( value ) )
- // return EXPP_ReturnIntError( PyExc_TypeError,
- // "expected BPy object argument" );
- // con->tar = obj;
- // return 0;
- // }
- //case EXPP_CONSTR_BONE: {
- // char *name = PyString_AsString( value );
- // if( !name )
- // return EXPP_ReturnIntError( PyExc_TypeError,
- // "expected string arg" );
- //
- // BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
- //
- // return 0;
- // }
+ case EXPP_CONSTR_TARGET:
+ case EXPP_CONSTR_BONE:
+ {
+ bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_PYTHON);
+ bConstraintTarget *ct;
+ int ok= 0;
+
+ if (cti) {
+ /* change space of targets */
+ if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+ int num_tars=0, i=0;
+
+ /* get targets, and extract values from the given list */
+ num_tars= cti->get_constraint_targets(self->con, &targets);
+ if (num_tars) {
+ if ((PySequence_Check(value) == 0) || (PySequence_Size(value) != num_tars)) {
+ char errorstr[64];
+ sprintf(errorstr, "expected sequence of %d integer(s)", num_tars);
+ return EXPP_ReturnIntError(PyExc_TypeError, errorstr);
+ }
+
+ for (ct=targets.first; ct; ct=ct->next, i++) {
+ PyObject *val= PySequence_ITEM(value, i);
+
+ if (type == EXPP_CONSTR_BONE) {
+ char *name = PyString_AsString(val);
+
+ if (name == NULL) {
+ // hrm... should we break here instead?
+ ok = EXPP_ReturnIntError(PyExc_TypeError,
+ "expected string arg as member of list");
+ Py_DECREF(val);
+
+ break;
+ }
+
+ BLI_strncpy(ct->subtarget, name, sizeof(ct->subtarget));
+ }
+ else {
+ Object *obj = (( BPy_Object * )val)->object;
+
+ if ( !BPy_Object_Check(value) ) {
+ // hrm... should we break here instead?
+ ok = EXPP_ReturnIntError(PyExc_TypeError,
+ "expected BPy object argument as member of list");
+ Py_DECREF(val);
+
+ break;
+ }
+
+ ct->tar = obj;
+ }
+
+ Py_DECREF(val);
+ }
+ }
+
+ /* only flush changes to real constraints if all were successful */
+ if ((cti->flush_constraint_targets) && (ok == 0))
+ cti->flush_constraint_targets(self->con, &targets, 0);
+ }
+ }
+
+ return ok;
+ }
+ break;
case EXPP_CONSTR_SCRIPT: {
Text *text = (( BPy_Text * )value)->text;
if( !BPy_Object_Check( value ) )
@@ -1806,6 +1935,8 @@ static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key )
return loclimit_getter( self, setting );
case CONSTRAINT_TYPE_SIZELIMIT:
return sizelimit_getter( self, setting );
+ case CONSTRAINT_TYPE_DISTLIMIT:
+ return distlimit_getter( self, setting );
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
return rigidbody_getter( self, setting );
case CONSTRAINT_TYPE_CLAMPTO:
@@ -1883,6 +2014,9 @@ static int Constraint_setData( BPy_Constraint * self, PyObject * key,
case CONSTRAINT_TYPE_SIZELIMIT:
result = sizelimit_setter( self, key_int, arg);
break;
+ case CONSTRAINT_TYPE_DISTLIMIT:
+ result = distlimit_setter( self, key_int, arg);
+ break;
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
result = rigidbody_setter( self, key_int, arg);
break;
@@ -2370,6 +2504,8 @@ static PyObject *M_Constraint_TypeDict( void )
PyInt_FromLong( CONSTRAINT_TYPE_ROTLIMIT ) );
PyConstant_Insert( d, "LIMITSIZE",
PyInt_FromLong( CONSTRAINT_TYPE_SIZELIMIT ) );
+ PyConstant_Insert( d, "LIMITDIST",
+ PyInt_FromLong( CONSTRAINT_TYPE_DISTLIMIT ) );
PyConstant_Insert( d, "RIGIDBODYJOINT",
PyInt_FromLong( CONSTRAINT_TYPE_RIGIDBODYJOINT ) );
PyConstant_Insert( d, "CLAMPTO",
@@ -2563,6 +2699,15 @@ static PyObject *M_Constraint_SettingsDict( void )
PyConstant_Insert( d, "LOCK",
PyInt_FromLong( EXPP_CONSTR_LOCK ) );
+
+ PyConstant_Insert( d, "LIMITMODE",
+ PyInt_FromLong( EXPP_CONSTR_MODE ) );
+ PyConstant_Insert( d, "LIMIT_INSIDE",
+ PyInt_FromLong( LIMITDIST_INSIDE ) );
+ PyConstant_Insert( d, "LIMIT_OUTSIDE",
+ PyInt_FromLong( LIMITDIST_OUTSIDE ) );
+ PyConstant_Insert( d, "LIMIT_ONSURFACE",
+ PyInt_FromLong( LIMITDIST_ONSURFACE ) );
PyConstant_Insert( d, "COPY",
PyInt_FromLong( EXPP_CONSTR_COPY ) );
diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c
index a4bbeba65ac..76e33a1bcb7 100644
--- a/source/blender/python/api2_2x/Draw.c
+++ b/source/blender/python/api2_2x/Draw.c
@@ -617,7 +617,8 @@ static void exit_pydraw( SpaceScript * sc, short err )
if( err ) {
PyErr_Print( );
script->flags = 0; /* mark script struct for deletion */
- error( "Python script error: check console" );
+ SCRIPT_SET_NULL(script);
+ error_pyscript();
scrarea_queue_redraw( sc->area );
}
@@ -837,7 +838,7 @@ static void exec_but_callback(void *pyobj, void *data)
if (!result) {
Py_DECREF(pyvalue);
PyErr_Print( );
- error( "Python script error: check console" );
+ error_pyscript( );
}
Py_XDECREF( result );
}
@@ -1109,7 +1110,7 @@ static PyObject *Method_UIBlock( PyObject * self, PyObject * args )
if (!result) {
PyErr_Print( );
- error( "Python script error: check console" );
+ error_pyscript( );
} else {
/* copied from do_clever_numbuts in toolbox.c */
diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c
index 1aacaf56786..12e2ce3055b 100644
--- a/source/blender/python/api2_2x/Library.c
+++ b/source/blender/python/api2_2x/Library.c
@@ -175,7 +175,7 @@ static PyObject *M_Library_Open( PyObject * self, PyObject * value )
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" );
@@ -344,6 +344,7 @@ static PyObject *oldM_Library_Load( PyObject * self, PyObject * args )
int blocktype = 0;
int linked = 0;
+
if( !bpy_openlib ) {
return EXPP_ReturnPyObjError( PyExc_IOError,
"no library file: you need to open one, first." );
@@ -359,12 +360,19 @@ static PyObject *oldM_Library_Load( PyObject * self, PyObject * args )
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, G.scene);
+ BLO_script_library_append( &bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK, G.scene);
else
- BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0, G.scene);
-
+ BLO_script_library_append( &bpy_openlib, bpy_openlibname, name, blocktype, 0, G.scene);
+
+ /*
+ NOTE: BLO_script_library_append() can close the library if there is
+ an endian issue. if this happened, reopen for the next call.
+ */
+ if ( !bpy_openlib )
+ bpy_openlib = BLO_blendhandle_from_file( bpy_openlibname );
+
if( update ) {
M_Library_Update( self );
Py_DECREF( Py_None ); /* incref'ed by above function */
@@ -610,7 +618,7 @@ PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
}
/* import from the libary */
- BLO_script_library_append( openlib, longFilename, name, self->type, mode,
+ BLO_script_library_append( &openlib, longFilename, name, self->type, mode,
scene );
/*
diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c
index 803c0b96ef3..f9a23ed37b2 100644
--- a/source/blender/python/api2_2x/Mesh.c
+++ b/source/blender/python/api2_2x/Mesh.c
@@ -75,6 +75,7 @@
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
+#include "BLI_memarena.h"
#include "blendef.h"
#include "mydevice.h"
@@ -7494,6 +7495,179 @@ static PyObject *Mesh_pointInside( BPy_Mesh * self, PyObject * args, PyObject *k
}
+/* This is a bit nasty, Blenders tangents are computed for rendering, and this isnt compatible with a normal Mesh
+ * so we have to rewrite parts of it here, make sure these stay in sync */
+
+static PyObject *Mesh_getTangents( BPy_Mesh * self )
+{
+ /* python stuff */
+ PyObject *py_tanlist;
+ PyObject *py_tuple;
+
+
+ PyObject *py_vector;
+#if 0 /* BI-TANGENT */
+ PyObject *py_bivector;
+ PyObject *py_pair;
+
+ float no[3];
+#endif
+ /* mesh vars */
+ Mesh *mesh = self->mesh;
+ MTFace *tf = mesh->mtface;
+ MFace *mf = mesh->mface;
+ MVert *v1, *v2, *v3, *v4;
+ int mf_vi[4];
+
+ /* See convertblender.c */
+ float *uv1, *uv2, *uv3, *uv4;
+ float fno[3];
+ float tang[3];
+ float uv[4][2];
+ float *vtang;
+
+ float (*orco)[3] = NULL;
+
+ MemArena *arena= NULL;
+ VertexTangent **vtangents= NULL;
+ int i, j, len;
+
+
+ if(!mesh->mtface) {
+ if (!self->object)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "cannot get tangents when there are not UV's, or the mesh has no link to an object");
+
+ orco = (float(*)[3])get_mesh_orco_verts(self->object);
+
+ if (!orco)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "cannot get orco's for this objects tangents");
+ }
+
+ /* vertex normals */
+ arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ BLI_memarena_use_calloc(arena);
+ vtangents= MEM_callocN(sizeof(VertexTangent*)*mesh->totvert, "VertexTangent");
+
+ for( i = 0, tf = mesh->mtface, mf = mesh->mface; i < mesh->totface; mf++, tf++, i++ ) {
+ v1 = &mesh->mvert[mf->v1];
+ v2 = &mesh->mvert[mf->v2];
+ v3 = &mesh->mvert[mf->v3];
+ if (mf->v4) {
+ v4 = &mesh->mvert[mf->v4];
+
+ CalcNormFloat4( v1->co, v2->co, v3->co, v4->co, fno );
+ } else {
+ CalcNormFloat( v1->co, v2->co, v3->co, fno );
+ }
+
+ if(mesh->mtface) {
+ uv1= tf->uv[0];
+ uv2= tf->uv[1];
+ uv3= tf->uv[2];
+ uv4= tf->uv[3];
+ } else {
+ uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
+ spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]);
+ spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]);
+ spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]);
+ if(v4)
+ spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]);
+ }
+
+ tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
+
+ if (mf->v4) {
+ v4 = &mesh->mvert[mf->v4];
+
+ tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
+ sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4);
+ }
+ }
+
+
+ py_tanlist = PyList_New(mesh->totface);
+
+ for( i = 0, tf = mesh->mtface, mf = mesh->mface; i < mesh->totface; mf++, tf++, i++ ) {
+
+ len = mf->v4 ? 4 : 3;
+
+ if(mesh->mtface) {
+ uv1= tf->uv[0];
+ uv2= tf->uv[1];
+ uv3= tf->uv[2];
+ uv4= tf->uv[3];
+ } else {
+ uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
+ spheremap(orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2], &uv[0][0], &uv[0][1]);
+ spheremap(orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2], &uv[1][0], &uv[1][1]);
+ spheremap(orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2], &uv[2][0], &uv[2][1]);
+ if(len==4)
+ spheremap(orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2], &uv[3][0], &uv[3][1]);
+ }
+
+ mf_vi[0] = mf->v1;
+ mf_vi[1] = mf->v2;
+ mf_vi[2] = mf->v3;
+ mf_vi[3] = mf->v4;
+
+#if 0 /* BI-TANGENT */
+ /* now calculate the bitangent */
+ if (mf->flag & ME_SMOOTH) {
+ no[0] = (float)(mesh->mvert[mf_vi[j]]->no[0] / 32767.0);
+ no[1] = (float)(mesh->mvert[mf_vi[j]]->no[1] / 32767.0);
+ no[2] = (float)(mesh->mvert[mf_vi[j]]->no[2] / 32767.0);
+ } else {
+ /* calc face normal */
+ if (len==4) CalcNormFloat4( mesh->mvert[0]->co, mesh->mvert[1]->co, mesh->mvert[2]->co, mesh->mvert[3]->co, no );
+ else CalcNormFloat4( mesh->mvert[0]->co, mesh->mvert[1]->co, mesh->mvert[2]->co, no );
+ }
+#endif
+
+ py_tuple = PyTuple_New( len );
+
+ for (j=0; j<len; j++) {
+ vtang= find_vertex_tangent(vtangents[mf_vi[j]], mesh->mtface ? tf->uv[j] : uv[j]); /* mf_vi[j] == mf->v1, uv[j] == tf->uv[0] */
+
+ py_vector = newVectorObject( vtang, 3, Py_NEW );
+ Normalize(((VectorObject *)py_vector)->vec);
+
+#if 0 /* BI-TANGENT */
+ py_pair = PyTuple_New( 2 );
+ PyTuple_SetItem( py_pair, 0, py_vector );
+ PyTuple_SetItem( py_pair, 1, py_bivector );
+
+ /* qdn: tangent space */
+ /* copied from texture.c */
+ float B[3], tv[3];
+ Crossf(B, shi->vn, shi->nmaptang); /* bitangent */
+ /* transform norvec from tangent space to object surface in camera space */
+ tv[0] = texres.nor[0]*shi->nmaptang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0];
+ tv[1] = texres.nor[0]*shi->nmaptang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1];
+ tv[2] = texres.nor[0]*shi->nmaptang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2];
+ shi->vn[0]= facm*shi->vn[0] + fact*tv[0];
+ shi->vn[1]= facm*shi->vn[1] + fact*tv[1];
+ shi->vn[2]= facm*shi->vn[2] + fact*tv[2];
+ PyTuple_SetItem( py_tuple, j, py_pair );
+#else
+ PyTuple_SetItem( py_tuple, j, py_vector );
+#endif
+ }
+
+ PyList_SetItem( py_tanlist, i, py_tuple );
+ }
+
+ BLI_memarena_free(arena);
+ if (orco) MEM_freeN( orco );
+ MEM_freeN( vtangents );
+
+ return py_tanlist;
+}
+
/*
* "__copy__" return a copy of the mesh
*/
@@ -7571,7 +7745,9 @@ static struct PyMethodDef BPy_Mesh_methods[] = {
"Recalculates inside or outside normals (experimental)"},
{"pointInside", (PyCFunction)Mesh_pointInside, METH_VARARGS|METH_KEYWORDS,
"Recalculates inside or outside normals (experimental)"},
-
+ {"getTangents", (PyCFunction)Mesh_getTangents, METH_VARARGS|METH_KEYWORDS,
+ "Return a list of face tangents"},
+
/* mesh custom data layers */
{"addUVLayer", (PyCFunction)Mesh_addUVLayer, METH_VARARGS,
"adds a UV layer to this mesh"},
diff --git a/source/blender/python/api2_2x/Node.c b/source/blender/python/api2_2x/Node.c
index 0a68509d287..0ceb6b3c2a2 100644
--- a/source/blender/python/api2_2x/Node.c
+++ b/source/blender/python/api2_2x/Node.c
@@ -43,6 +43,7 @@
#include "BLI_blenlib.h"
#include "gen_utils.h"
+#include "vector.h"
static PyObject *Node_repr( BPy_Node * self );
static int Node_compare(BPy_Node *a, BPy_Node *b);
@@ -50,101 +51,369 @@ static PyObject *ShadeInput_repr( BPy_ShadeInput * self );
static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b);
static BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi);
+/* node socket type */
+
+static PyObject *NodeSocket_getName(BPy_NodeSocket *self, void *unused)
+{
+ return PyString_FromString(self->name);
+}
+
+static int NodeSocket_setName(BPy_NodeSocket *self, PyObject *value, void *unused)
+{
+ char *name = NULL;
+
+ if (!PyString_Check(value))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a string" );
+
+ name = PyString_AsString(value);
+
+ if (!name)
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "couldn't convert value to string!");
+
+ BLI_strncpy(self->name, name, NODE_MAXSTR);
+
+ return 0;
+}
+
+static PyObject *NodeSocket_getVal(BPy_NodeSocket *self, void *unused)
+{
+ PyObject *pyret = NULL;
+
+ if (self->type == SOCK_VALUE) {
+ pyret = PyFloat_FromDouble(self->val[0]);
+ }
+ else { /* VECTOR or RGBA */
+ pyret = newVectorObject(self->val, self->type, Py_NEW);
+
+ if (!pyret)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "couldn't create vector object!");
+ }
+
+ return pyret;
+}
+
+static int NodeSocket_setVal(BPy_NodeSocket *self, PyObject *value, void *unused)
+{
+ int error = 0;
+
+ if (PySequence_Check(value)) {
+ PyObject *item, *fpyval;
+ int i, len;
+
+ len = PySequence_Size(value);
+
+ if (len == 3 || len == 4) {
+ for (i = 0; i < len; i++) {
+ item = PySequence_GetItem(value, i);
+ fpyval = PyNumber_Float(item);
+ if (!fpyval) {
+ Py_DECREF(item);
+ error = 1;
+ break;
+ }
+ self->val[i] = (float)PyFloat_AsDouble(fpyval);
+ Py_DECREF(item);
+ Py_DECREF(fpyval);
+ }
+ if (len == 3)
+ self->type = SOCK_VECTOR;
+ else /* len == 4 */
+ self->type = SOCK_RGBA;
+ }
+ else error = 1;
+ }
+ else if (VectorObject_Check(value)) {
+ VectorObject *vecOb = (VectorObject *)value;
+ short vlen = vecOb->size;
+
+ if (vlen == 3 || vlen == 4) {
+ VECCOPY(self->val, vecOb->vec); /* copies 3 values */
+ if (vlen == 3)
+ self->type = SOCK_VECTOR;
+ else {
+ self->val[3] = vecOb->vec[3];
+ self->type = SOCK_RGBA;
+ }
+ }
+ else error = 1;
+ }
+ else if (PyNumber_Check(value)) {
+ self->val[0] = (float)PyFloat_AsDouble(value);
+ self->type = SOCK_VALUE;
+ }
+ else error = 1;
+
+ if (error)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float or a sequence (or vector) of 3 or 4 floats" );
+ return 0;
+}
+
+static PyObject *NodeSocket_getMin(BPy_NodeSocket *self, void *unused)
+{
+ return PyFloat_FromDouble(self->min);
+}
+
+static int NodeSocket_setMin(BPy_NodeSocket *self, PyObject *value, void *unused)
+{
+ PyObject *pyval = PyNumber_Float(value);
+
+ if (!pyval)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float number" );
+
+ self->min = (float)PyFloat_AsDouble(pyval);
+ Py_DECREF(pyval);
+
+ return 0;
+}
+
+static PyObject *NodeSocket_getMax(BPy_NodeSocket *self, void *unused)
+{
+ return PyFloat_FromDouble(self->max);
+}
+
+static int NodeSocket_setMax(BPy_NodeSocket *self, PyObject *value, void *unused)
+{
+ PyObject *pyval = PyNumber_Float(value);
+
+ if (!pyval)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float number" );
+
+ self->max = (float)PyFloat_AsDouble(pyval);
+ Py_DECREF(pyval);
+
+ return 0;
+}
+
+static PyGetSetDef NodeSocket_getseters[] = {
+ {"name", (getter)NodeSocket_getName, (setter)NodeSocket_setName,
+ "This socket's name", NULL},
+ {"val", (getter)NodeSocket_getVal, (setter)NodeSocket_setVal,
+ "This socket's data value(s)", NULL},
+ {"min", (getter)NodeSocket_getMin, (setter)NodeSocket_setMin,
+ "This socket's min possible value (lower range limit)", NULL},
+ {"max", (getter)NodeSocket_getMax, (setter)NodeSocket_setMax,
+ "This socket's max possible value (upper range limit)", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+static void NodeSocket_dealloc(BPy_NodeSocket *self)
+{
+ self->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *NodeSocket_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *pysocket = type->tp_alloc(type, 0);
+
+ if (!pysocket)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError, "couldn't create socket type!");
+
+ return pysocket;
+}
+
+static int NodeSocket_init(BPy_NodeSocket *self, PyObject *args, PyObject *kwargs)
+{
+ char *name = NULL;
+ float min = 0.0f, max = 1.0f;
+ PyObject *val = NULL;
+ static char *kwlist[] = {"name", "val", "min", "max", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Off", kwlist, &name, &val, &min, &max)){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "expected a string and optionally:\n1) a float or a sequence (or vector) of 3 or 4 floats and\n2) two floats");
+ }
+
+ BLI_strncpy(self->name, name, NODE_MAXSTR);
+
+ self->min = min;
+ self->max = max;
+
+ if (val)
+ return NodeSocket_setVal(self, val, NULL);
+ /* else */
+ self->type = SOCK_VALUE;
+ self->val[0] = 0.0f;
+
+ return 0;
+}
+
+static PyObject *NodeSocket_copy(BPy_NodeSocket *self)
+{
+ BPy_NodeSocket *copied;
+
+ copied = (BPy_NodeSocket*)NodeSocket_new(&NodeSocket_Type, NULL, NULL);
+
+ if (!copied) return NULL; /* error already set in NodeSocket_new */
+
+ BLI_strncpy(copied->name, self->name, NODE_MAXSTR);
+ copied->min = self->min;
+ copied->max = self->max;
+ copied->type = self->type;
+ memcpy(copied->val, self->val, 4*sizeof(float));
+
+ return (PyObject *)copied;
+}
+
+static PyMethodDef BPy_NodeSocket_methods[] = {
+ {"__copy__", ( PyCFunction ) NodeSocket_copy, METH_NOARGS,
+ "() - Makes a copy of this node socket."},
+ {"copy", ( PyCFunction ) NodeSocket_copy, METH_NOARGS,
+ "() - Makes a copy of this node socket."},
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject NodeSocket_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.Socket", /* char *tp_name; */
+ sizeof( BPy_NodeSocket ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ (destructor)NodeSocket_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/input buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_NodeSocket_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NodeSocket_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ (initproc)NodeSocket_init, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NodeSocket_new, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
/**
- * Take the descriptions from list and create sockets for those in socks
+ * Take the descriptions from tuple and create sockets for those in socks
* socks is a socketstack from a bNodeTypeInfo
*/
-static int list_socks_to_typeinfo(PyObject *tuple, bNodeSocketType **socks, int stage, int limit) {
+static int pysockets_to_blendersockets(PyObject *tuple, bNodeSocketType **socks, int stage, int limit) {
int len = 0, a = 0, pos = 0, retval = 0;
- //wPyObject *key = NULL, *value = NULL;
- PyObject *item, *arg;
- bNodeSocketType *newsocks = NULL;
- char *s_name = NULL;
- int s_type = SOCK_VALUE;
- float s_val[4], s_min, s_max;
+ short stype;
+ BPy_NodeSocket *pysock;
+ bNodeSocketType *nsocks = NULL;
if (BTST2(stage, NODE_DYNAMIC_READY, NODE_DYNAMIC_ADDEXIST))
return 0; /* already has sockets */
len = PyTuple_Size(tuple);
- newsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType in Node.c");
+ nsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType in Node.c");
for (pos = 0, a = 0; pos< len; pos++, a++) {
- /* default socket values: */
- s_name = NULL;
- s_type = SOCK_VALUE;
- s_min = 0.0f;
- s_max = 1.0f;
- s_val[0] = s_val[1] = s_val[2] = s_val[3] = 1.0f;
-
- item = PyTuple_GetItem(tuple, pos);
+ pysock = (BPy_NodeSocket *)PyTuple_GetItem(tuple, pos);/*borrowed*/
- if (!PySequence_Check(item)) {
- PyErr_SetString(PyExc_AttributeError, "a socket must be a List of Lists or Tuples");
+ if (!BPy_NodeSocket_Check(pysock)) {
+ PyErr_SetString(PyExc_AttributeError, "expected a sequence of node sockets");
retval = -1;
break;
}
- arg = PySequence_Tuple(item);
+ stype = pysock->type;
- if (!PyArg_ParseTuple(arg, "s|iffffff", &s_name, &s_type,
- &s_min, &s_max,
- &s_val[0], &s_val[1], &s_val[2], &s_val[3] )) {
- PyErr_SetString(PyExc_AttributeError, "socket definitions require a string and optionally an int and 6 floats");
- retval = -1;
- Py_DECREF(arg);
- break;
- }
+ nsocks[a].type = stype;
+ nsocks[a].limit = limit;
+
+ nsocks[a].name = BLI_strdupn(pysock->name, NODE_MAXSTR);
+
+ nsocks[a].min = pysock->min;
+ nsocks[a].max = pysock->max;
+
+ if (stype > SOCK_VALUE) {
+ float *vec = pysock->val;
- newsocks[a].name = BLI_strdupn(s_name, NODE_MAXSTR);
- newsocks[a].type = s_type;
- newsocks[a].min = s_min;
- newsocks[a].max = s_max;
- newsocks[a].val1 = s_val[0];
- newsocks[a].val2 = s_val[1];
- newsocks[a].val3 = s_val[2];
- newsocks[a].val4 = s_val[3];
- newsocks[a].limit = limit;
-
- Py_DECREF(arg);
+ nsocks[a].val1 = vec[0];
+ nsocks[a].val2 = vec[1];
+ nsocks[a].val3 = vec[2];
+
+ if (stype == SOCK_RGBA)
+ nsocks[a].val4 = vec[3];
+ }
+ else /* SOCK_VALUE */
+ nsocks[a].val1 = pysock->val[0];
}
- newsocks[a].type = -1;
+ nsocks[a].type = -1;
- *socks = newsocks;
+ *socks = nsocks;
return retval;
}
-/* Get number of complying entries in a list.
- *
- */
-/* unused
-static int num_list_sockets(PyObject *list) {
- int size = 0;
- int i = 0, count = 0;
- PyObject *element = NULL;
-
- size = PyList_Size(list);
- for(i = 0; i < size; i++) {
- element = PyList_GetItem(list, i);
- //wPy_INCREF(element);
- if(PyList_Check(element) && PyList_Size(element) == 8)
- count++;
- //wPy_DECREF(element);
- }
- return count;
-}
-*/
-static void NodeSockets_dealloc(BPy_NodeSockets *self)
+static void NodeSocketLists_dealloc(BPy_NodeSocketLists *self)
{
Py_DECREF(self->input);
Py_DECREF(self->output);
self->ob_type->tp_free((PyObject *)self);
}
-static PyObject *Map_socketdef_getter(BPy_NodeSockets *self, void *closure)
+static PyObject *Map_socketdef_getter(BPy_NodeSocketLists *self, void *closure)
{
PyObject *sockets = NULL;
@@ -167,7 +436,7 @@ static PyObject *Map_socketdef_getter(BPy_NodeSockets *self, void *closure)
return sockets;
}
-static int Map_socketdef(BPy_NodeSockets *self, PyObject *args, void *closure)
+static int Map_socketdef(BPy_NodeSocketLists *self, PyObject *args, void *closure)
{
bNode *node = NULL;
PyObject *tuple = NULL;
@@ -187,7 +456,8 @@ static int Map_socketdef(BPy_NodeSockets *self, PyObject *args, void *closure)
if (args) {
if(PySequence_Check(args)) {
tuple = PySequence_Tuple(args);
- list_socks_to_typeinfo(tuple, &(node->typeinfo->inputs), node->custom1, 1);
+ pysockets_to_blendersockets(tuple,
+ &(node->typeinfo->inputs), node->custom1, 1);
Py_DECREF(self->input);
self->input = tuple;
} else {
@@ -199,7 +469,8 @@ static int Map_socketdef(BPy_NodeSockets *self, PyObject *args, void *closure)
if (args) {
if(PyList_Check(args)) {
tuple = PySequence_Tuple(args);
- list_socks_to_typeinfo(tuple, &(node->typeinfo->outputs), node->custom1, 0);
+ pysockets_to_blendersockets(tuple,
+ &(node->typeinfo->outputs), node->custom1, 0);
Py_DECREF(self->output);
self->output = tuple;
} else {
@@ -214,7 +485,7 @@ static int Map_socketdef(BPy_NodeSockets *self, PyObject *args, void *closure)
return 0;
}
-static PyGetSetDef NodeSockets_getseters[] = {
+static PyGetSetDef NodeSocketLists_getseters[] = {
{"input", (getter)Map_socketdef_getter, (setter)Map_socketdef,
"Set this node's input sockets (list of lists or tuples)",
(void *)'I'},
@@ -230,17 +501,17 @@ static PyGetSetDef NodeSockets_getseters[] = {
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
-PyTypeObject NodeSockets_Type = {
+PyTypeObject NodeSocketLists_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
0, /* ob_size */
/* For printing, in format "<module>.<name>" */
- "Blender.Node.Sockets", /* char *tp_name; */
- sizeof( BPy_NodeSockets ), /* int tp_basicsize; */
+ "Blender.Node.SocketLists", /* char *tp_name; */
+ sizeof( BPy_NodeSocketLists ), /* int tp_basicsize; */
0, /* tp_itemsize; For allocation */
/* Methods to implement standard operations */
- (destructor)NodeSockets_dealloc,/* destructor tp_dealloc; */
+ (destructor)NodeSocketLists_dealloc,/* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
@@ -290,7 +561,7 @@ PyTypeObject NodeSockets_Type = {
/*** Attribute descriptor and subclassing stuff ***/
0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
NULL, /* struct PyMemberDef *tp_members; */
- NodeSockets_getseters, /* struct PyGetSetDef *tp_getset; */
+ NodeSocketLists_getseters, /* struct PyGetSetDef *tp_getset; */
NULL, /* struct _typeobject *tp_base; */
NULL, /* PyObject *tp_dict; */
NULL, /* descrgetfunc tp_descr_get; */
@@ -312,17 +583,17 @@ PyTypeObject NodeSockets_Type = {
NULL
};
-BPy_NodeSockets *Node_CreateSockets(bNode *node) {
- BPy_NodeSockets *sockets = PyObject_NEW(BPy_NodeSockets, &NodeSockets_Type);
- sockets->node = node;
- sockets->input = PyList_New(0);
- sockets->output = PyList_New(0);
- return sockets;
+BPy_NodeSocketLists *Node_CreateSocketLists(bNode *node) {
+ BPy_NodeSocketLists *socklists = PyObject_NEW(BPy_NodeSocketLists, &NodeSocketLists_Type);
+ socklists->node = node;
+ socklists->input = PyList_New(0);
+ socklists->output = PyList_New(0);
+ return socklists;
}
/***************************************/
-static int sockinmap_len ( BPy_SockMap * self) {
+static int Sockinmap_len ( BPy_SockMap * self) {
bNode *node = self->node;
bNodeType *tinfo;
int a = 0;
@@ -340,16 +611,14 @@ static int sockinmap_len ( BPy_SockMap * self) {
return a;
}
-static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) {
+static int sockinmap_has_key( BPy_SockMap *self, char *strkey) {
bNode *node = self->node;
bNodeType *tinfo;
- char *strkey = NULL;
int a = 0;
- if (!node) return -1;
+ if (!node || !strkey) return -1;
tinfo = node->typeinfo;
- strkey = PyString_AsString(key);
if(tinfo && tinfo->inputs){
while(self->node->typeinfo->inputs[a].type!=-1) {
@@ -362,17 +631,17 @@ static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) {
return -1;
}
-PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *pyidx) {
+PyObject *Sockinmap_subscript(BPy_SockMap *self, PyObject *pyidx) {
int idx;
if (!self->node)
return EXPP_ReturnPyObjError(PyExc_RuntimeError, "no access to Blender node data!");
if (PyString_Check(pyidx)) {
- idx = sockinmap_has_key(self, pyidx);
+ idx = sockinmap_has_key(self, PyString_AsString(pyidx));
}
else if(PyInt_Check(pyidx)) {
- int len = sockinmap_len(self);
+ int len = Sockinmap_len(self);
idx = (int)PyInt_AsLong(pyidx);
if (idx < 0 || idx >= len)
return EXPP_ReturnPyObjError(PyExc_IndexError, "index out of range");
@@ -405,10 +674,37 @@ PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *pyidx) {
Py_RETURN_NONE;
}
+static PyObject *Sockinmap_getAttr(BPy_SockMap *self, char *attr)
+{
+ PyObject *pyob = NULL;
+ int idx;
+
+ idx = sockinmap_has_key(self, attr);
+
+ if (idx < 0)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError, "unknown input socket name");
+
+ switch(self->node->typeinfo->inputs[idx].type) {
+ case SOCK_VALUE:
+ pyob = Py_BuildValue("f", self->stack[idx]->vec[0]);
+ break;
+ case SOCK_VECTOR:
+ pyob = Py_BuildValue("(fff)", self->stack[idx]->vec[0], self->stack[idx]->vec[1], self->stack[idx]->vec[2]);
+ break;
+ case SOCK_RGBA:
+ pyob = Py_BuildValue("(ffff)", self->stack[idx]->vec[0], self->stack[idx]->vec[1], self->stack[idx]->vec[2], self->stack[idx]->vec[3]);
+ break;
+ default:
+ break;
+ }
+
+ return pyob;
+}
+
/* read only */
-static PyMappingMethods sockinmap_as_mapping = {
- ( inquiry ) sockinmap_len, /* mp_length */
- ( binaryfunc ) sockinmap_subscript, /* mp_subscript */
+static PyMappingMethods Sockinmap_as_mapping = {
+ ( inquiry ) Sockinmap_len, /* mp_length */
+ ( binaryfunc ) Sockinmap_subscript, /* mp_subscript */
( objobjargproc ) 0 /* mp_ass_subscript */
};
@@ -424,7 +720,7 @@ PyTypeObject SockInMap_Type = {
NULL,/* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
+ (getattrfunc) Sockinmap_getAttr,/* getattrfunc tp_getattr; */
NULL, /* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
NULL, /* reprfunc tp_repr; */
@@ -433,7 +729,7 @@ PyTypeObject SockInMap_Type = {
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
- &sockinmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+ &Sockinmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
@@ -494,7 +790,7 @@ PyTypeObject SockInMap_Type = {
NULL
};
-static int sockoutmap_len ( BPy_SockMap * self) {
+static int Sockoutmap_len ( BPy_SockMap * self) {
bNode *node = self->node;
bNodeType *tinfo;
int a = 0;
@@ -510,16 +806,14 @@ static int sockoutmap_len ( BPy_SockMap * self) {
return a;
}
-static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) {
+static int sockoutmap_has_key(BPy_SockMap *self, char *strkey) {
bNode *node = self->node;
bNodeType *tinfo;
int a = 0;
- char *strkey = NULL;
if (!node) return -1;
tinfo = node->typeinfo;
- strkey = PyString_AsString(key);
if(tinfo && tinfo->outputs){
while(self->node->typeinfo->outputs[a].type!=-1) {
@@ -532,8 +826,8 @@ static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) {
return -1;
}
-static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *pyidx, PyObject *value) {
- int i, idx, len, wanted_len = 0, ret = -1;
+static int Sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *pyidx, PyObject *value) {
+ int i, idx, len, type, wanted_len = 0;
PyObject *val;
PyObject *items[4];
@@ -542,11 +836,11 @@ static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *pyidx, PyObj
if (PyInt_Check(pyidx)) {
idx = (int)PyInt_AsLong(pyidx);
- if (idx < 0 || idx >= sockinmap_len(self))
+ if (idx < 0 || idx >= Sockinmap_len(self))
return EXPP_ReturnIntError(PyExc_IndexError, "index out of range");
}
else if (PyString_Check(pyidx)) {
- idx = sockoutmap_has_key(self, pyidx);
+ idx = sockoutmap_has_key(self, PyString_AsString(pyidx));
}
else if (PySlice_Check(pyidx)) {
return EXPP_ReturnIntError(PyExc_ValueError, "slices not yet implemented");
@@ -557,70 +851,129 @@ static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *pyidx, PyObj
if (idx < 0)
return EXPP_ReturnIntError(PyExc_IndexError, "index must be a positive int or a string");
- val = PySequence_Fast(value, "expected a numeric tuple or list");
- if (!val) return -1;
+ type = self->node->typeinfo->outputs[idx].type;
- len = PySequence_Fast_GET_SIZE(val);
-
- if (len == 0) {
+ if (type == SOCK_VALUE) {
+ val = PyNumber_Float(value);
+ if (!val)
+ return EXPP_ReturnIntError(PyExc_AttributeError, "expected a float value");
+ self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(val);
Py_DECREF(val);
- return EXPP_ReturnIntError(PyExc_AttributeError, "expected a non-empty numeric tuple or list");
}
+ else {
+ val = PySequence_Fast(value, "expected a numeric tuple or list");
+ if (!val) return -1;
+
+ len = PySequence_Fast_GET_SIZE(val);
- for (i = 0; i < len; i++) {
- items[i] = PySequence_Fast_GET_ITEM(val, i); /* borrowed */
- if (!PyNumber_Check(items[i])) {
+ if (type == SOCK_VECTOR) {
+ wanted_len = 3;
+ } else { /* SOCK_RGBA */
+ wanted_len = 4;
+ }
+
+ if (len != wanted_len) {
Py_DECREF(val);
- return EXPP_ReturnIntError(PyExc_AttributeError, "expected a *numeric* tuple or list");
+ PyErr_SetString(PyExc_AttributeError, "wrong number of items in list or tuple");
+ fprintf(stderr, "\nExpected %d numeric values, got %d.", wanted_len, len);
+ return -1;
}
- }
- switch(self->node->typeinfo->outputs[idx].type) {
- case SOCK_VALUE:
- wanted_len = 1;
- if (len == 1) {
- self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
- ret = 0;
+ for (i = 0; i < len; i++) {
+ items[i] = PySequence_Fast_GET_ITEM(val, i); /* borrowed */
+ if (!PyNumber_Check(items[i])) {
+ Py_DECREF(val);
+ return EXPP_ReturnIntError(PyExc_AttributeError, "expected a *numeric* tuple or list");
}
- break;
- case SOCK_VECTOR:
+ }
+
+ self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
+ self->stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
+ self->stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
+
+ if (type == SOCK_RGBA)
+ self->stack[idx]->vec[3] = (float)PyFloat_AsDouble(items[3]);
+
+ Py_DECREF(val);
+ }
+
+ return 0;
+}
+
+static int sockoutmap_set_attr(bNodeStack **stack, short type, short idx, PyObject *value)
+{
+ PyObject *val;
+ PyObject *items[4];
+ int i;
+ short len, wanted_len;
+
+ if (type == SOCK_VALUE) {
+ val = PyNumber_Float(value);
+ if (!val)
+ return EXPP_ReturnIntError(PyExc_AttributeError, "expected a float value");
+ stack[idx]->vec[0] = (float)PyFloat_AsDouble(val);
+ Py_DECREF(val);
+ }
+ else {
+ val = PySequence_Fast(value, "expected a numeric tuple or list");
+ if (!val) return -1;
+
+ len = PySequence_Fast_GET_SIZE(val);
+
+ if (type == SOCK_VECTOR) {
wanted_len = 3;
- if (len == 3) {
- self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
- self->stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
- self->stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
- ret = 0;
- }
- break;
- case SOCK_RGBA:
+ } else { /* SOCK_RGBA */
wanted_len = 4;
- if (len == 4) {
- self->stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
- self->stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
- self->stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
- self->stack[idx]->vec[3] = (float)PyFloat_AsDouble(items[3]);
- ret = 0;
+ }
+
+ if (len != wanted_len) {
+ Py_DECREF(val);
+ PyErr_SetString(PyExc_AttributeError, "wrong number of items in list or tuple");
+ fprintf(stderr, "\nExpected %d numeric values, got %d.", wanted_len, len);
+ return -1;
+ }
+
+ for (i = 0; i < len; i++) {
+ items[i] = PySequence_Fast_GET_ITEM(val, i); /* borrowed */
+ if (!PyNumber_Check(items[i])) {
+ Py_DECREF(val);
+ return EXPP_ReturnIntError(PyExc_AttributeError, "expected a *numeric* tuple or list");
}
- break;
- default:
- break;
- }
+ }
+
+ stack[idx]->vec[0] = (float)PyFloat_AsDouble(items[0]);
+ stack[idx]->vec[1] = (float)PyFloat_AsDouble(items[1]);
+ stack[idx]->vec[2] = (float)PyFloat_AsDouble(items[2]);
- Py_DECREF(val);
+ if (type == SOCK_RGBA)
+ stack[idx]->vec[3] = (float)PyFloat_AsDouble(items[3]);
- if (ret == -1) {
- PyErr_SetString(PyExc_AttributeError, "wrong number of items in list or tuple");
- fprintf(stderr, "\nExpected %d numeric values, got %d.", wanted_len, len);
+ Py_DECREF(val);
}
- return ret;
+ return 0;
}
+static int Sockoutmap_setAttr(BPy_SockMap *self, char *name, PyObject *value) {
+ short idx, type;
+
+ if (!self->node)
+ return EXPP_ReturnIntError(PyExc_RuntimeError, "no access to Blender node data!");
+
+ idx = sockoutmap_has_key(self, name);
+
+ if (idx < 0)
+ return EXPP_ReturnIntError(PyExc_AttributeError, "unknown output socket name");
+
+ type = self->node->typeinfo->outputs[idx].type;
+
+ return sockoutmap_set_attr(self->stack, type, idx, value);
+}
/* write only */
-static PyMappingMethods sockoutmap_as_mapping = {
- ( inquiry ) sockoutmap_len, /* mp_length */
+static PyMappingMethods Sockoutmap_as_mapping = {
+ ( inquiry ) Sockoutmap_len, /* mp_length */
( binaryfunc ) 0, /* mp_subscript */
- ( objobjargproc ) sockoutmap_assign_subscript /* mp_ass_subscript */
+ ( objobjargproc ) Sockoutmap_assign_subscript /* mp_ass_subscript */
};
PyTypeObject SockOutMap_Type = {
@@ -636,7 +989,7 @@ PyTypeObject SockOutMap_Type = {
NULL,/* destructor tp_dealloc; */
NULL, /* printfunc tp_print; */
NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
+ (setattrfunc) Sockoutmap_setAttr,/* setattrfunc tp_setattr; */
NULL, /* cmpfunc tp_compare; */
NULL, /* reprfunc tp_repr; */
@@ -644,7 +997,7 @@ PyTypeObject SockOutMap_Type = {
NULL, /* PyNumberMethods *tp_as_number; */
NULL, /* PySequenceMethods *tp_as_sequence; */
- &sockoutmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+ &Sockoutmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
/* More standard operations (here for binary compatibility) */
@@ -850,7 +1203,6 @@ static PyObject *Node_GetShi(BPy_Node *self) {
static PyObject *node_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *self;
- assert(type!=NULL && type->tp_alloc!=NULL);
self = type->tp_alloc(type, 1);
return self;
}
@@ -1161,7 +1513,9 @@ PyObject *Node_Init(void)
return NULL;
if( PyType_Ready( &ShadeInput_Type ) < 0 )
return NULL;
- if( PyType_Ready( &NodeSockets_Type ) < 0 )
+ if( PyType_Ready( &NodeSocket_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &NodeSocketLists_Type ) < 0 )
return NULL;
if( PyType_Ready( &SockInMap_Type ) < 0 )
return NULL;
@@ -1173,11 +1527,13 @@ PyObject *Node_Init(void)
PyModule_AddIntConstant(submodule, "RGBA", SOCK_RGBA);
PyModule_AddIntConstant(submodule, "VECTOR", SOCK_VECTOR);
+ Py_INCREF(&NodeSocket_Type);
+ PyModule_AddObject(submodule, "Socket", (PyObject *)&NodeSocket_Type);
+
Py_INCREF(&Node_Type);
- PyModule_AddObject(submodule, "node", (PyObject *)&Node_Type);
+ PyModule_AddObject(submodule, "Scripted", (PyObject *)&Node_Type);
return submodule;
-
}
static int Node_compare(BPy_Node *a, BPy_Node *b)
@@ -1189,7 +1545,7 @@ static int Node_compare(BPy_Node *a, BPy_Node *b)
static PyObject *Node_repr(BPy_Node *self)
{
return PyString_FromFormat( "[Node \"%s\"]",
- self->node ? self->node->id->name+2 : "empty node");
+ self->node ? self->node->id->name+2 : "empty node");
}
BPy_Node *Node_CreatePyObject(bNode *node)
diff --git a/source/blender/python/api2_2x/Node.h b/source/blender/python/api2_2x/Node.h
index e229e678fe9..49626599887 100644
--- a/source/blender/python/api2_2x/Node.h
+++ b/source/blender/python/api2_2x/Node.h
@@ -40,11 +40,19 @@
#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */
extern PyTypeObject Node_Type;
+extern PyTypeObject NodeSocket_Type;
+extern PyTypeObject NodeSocketLists_Type;
extern PyTypeObject ShadeInput_Type;
#define BPy_Node_Check(v) \
((v)->ob_type == &Node_Type)
+#define BPy_NodeSocket_Check(v) \
+ ((v)->ob_type == &NodeSocket_Type)
+
+#define BPy_NodeSocketLists_Check(v) \
+ ((v)->ob_type == &NodeSocketLists_Type)
+
#define BPy_ShadeInput_Check(v) \
((v)->ob_type == &ShadeInput_Type)
@@ -64,7 +72,7 @@ typedef struct {
bNode *node;
PyObject *input;
PyObject *output;
-} BPy_NodeSockets;
+} BPy_NodeSocketLists;
typedef struct BPy_Node {
PyObject_HEAD
@@ -74,10 +82,19 @@ typedef struct BPy_Node {
ShadeInput *shi;
} BPy_Node;
+typedef struct BPy_NodeSocket {
+ PyObject_HEAD
+ char name[NODE_MAXSTR];
+ float min;
+ float max;
+ float val[4];
+ short type; /* VALUE, VECTOR or RGBA */
+} BPy_NodeSocket;
+
extern PyObject *Node_Init(void);
extern void InitNode(BPy_Node *self, bNode *node);
extern BPy_Node *Node_CreatePyObject(bNode *node);
-extern BPy_NodeSockets *Node_CreateSockets(bNode *node);
+extern BPy_NodeSocketLists *Node_CreateSocketLists(bNode *node);
extern void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type);
extern void Node_SetShi(BPy_Node *self, ShadeInput *shi);
extern int pytype_is_pynode(PyObject *pyob);
diff --git a/source/blender/python/api2_2x/SurfNurb.c b/source/blender/python/api2_2x/SurfNurb.c
index 3499ec09936..f1c038fc33c 100644
--- a/source/blender/python/api2_2x/SurfNurb.c
+++ b/source/blender/python/api2_2x/SurfNurb.c
@@ -46,6 +46,8 @@ static int SurfNurb_setPoint( BPy_SurfNurb * self, int index, PyObject * ob );
static int SurfNurb_length( PyInstanceObject * inst );
static PyObject *SurfNurb_getIter( BPy_SurfNurb * self );
static PyObject *SurfNurb_iterNext( BPy_SurfNurb * self );
+static PyObject *SurfNurb_getKnotsU( BPy_SurfNurb * self );
+static PyObject *SurfNurb_getKnotsV( BPy_SurfNurb * self );
PyObject *SurfNurb_append( BPy_SurfNurb * self, PyObject * args );
char M_SurfNurb_doc[] = "SurfNurb";
@@ -487,6 +489,58 @@ static int SurfNurb_setCyclicV( BPy_SurfNurb * self, PyObject * value )
return 0;
}
+/*
+ * SurfNurb_getKnotsU
+ *
+ * Returns surface's knotsU in a tuple. Empty tuple is returned if
+ * surface isn't Nurbs or it doesn't have knots in U
+ */
+
+static PyObject *SurfNurb_getKnotsU( BPy_SurfNurb * self )
+{
+ if(self->nurb->knotsu) {
+ int len = KNOTSU(self->nurb);
+ int i;
+ PyObject *knotsu = PyTuple_New(len);
+ if( !knotsu )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get SurfNurb.knotsU attribute" );
+
+ for(i = 0; i < len; ++i)
+ PyTuple_SetItem(knotsu, i,
+ PyFloat_FromDouble(self->nurb->knotsu[i]));
+
+ return knotsu;
+ }
+ return PyTuple_New(0);
+}
+
+/*
+ * SurfNurb_getKnotsV
+ *
+ * Returns surface's knotsV in a tuple. Empty tuple is returned if
+ * curve doesn't have knots in V
+ */
+
+static PyObject *SurfNurb_getKnotsV( BPy_SurfNurb * self )
+{
+ if(self->nurb->knotsv) {
+ int len = KNOTSV(self->nurb);
+ int i;
+ PyObject *knotsv = PyTuple_New(len);
+ if( !knotsv )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get SurfNurb.knotsV index" );
+
+ for(i = 0; i < len; ++i)
+ PyTuple_SetItem(knotsv, i,
+ PyFloat_FromDouble(self->nurb->knotsv[i] ));
+
+ return knotsv;
+ }
+ return PyTuple_New(0);
+}
+
/*
* SurfNurb_getIter
@@ -723,6 +777,15 @@ static PyGetSetDef BPy_SurfNurb_getseters[] = {
{"orderV",
(getter)SurfNurb_getOrderV, (setter)SurfNurb_setOrderV,
"order setting for V direction", NULL},
+ {"knotsU",
+ (getter)SurfNurb_getKnotsU, (setter)NULL,
+ "The The knot vector in the U direction",
+ NULL},
+ {"knotsV",
+ (getter)SurfNurb_getKnotsV, (setter)NULL,
+ "The The knot vector in the V direction",
+ NULL},
+
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c
index 5cfe796add8..b4a14cc6ac8 100644
--- a/source/blender/python/api2_2x/Window.c
+++ b/source/blender/python/api2_2x/Window.c
@@ -47,6 +47,7 @@
#include "BIF_space.h"
#include "BIF_drawtext.h"
#include "BIF_poseobject.h"
+#include "BIF_toolbox.h" /* for error() */
#include "DNA_view3d_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
@@ -513,6 +514,14 @@ static void getSelectedFile( char *name )
script = sc->script;
}
}
+ /* If 'script' is null,
+ * The script must have had an error and closed,
+ * but the fileselector was left open, show an error and exit */
+ if (!script) {
+ error("Python script error: script quit, cannot run callback");
+ return;
+ }
+
pycallback = script->py_browsercallback;
@@ -526,10 +535,17 @@ static void getSelectedFile( char *name )
fprintf(stderr, "BPy error: Callback call failed!\n");
}
else Py_DECREF(result);
-
+
+
+
if (script->py_browsercallback == pycallback) {
- SCRIPT_SET_NULL(script);
+ if (script->flags & SCRIPT_GUI) {
+ script->py_browsercallback = NULL;
+ } else {
+ SCRIPT_SET_NULL(script);
+ }
}
+
/* else another call to selector was made inside pycallback */
Py_DECREF(pycallback);
diff --git a/source/blender/python/api2_2x/doc/Constraint.py b/source/blender/python/api2_2x/doc/Constraint.py
index 61ee3c36700..0f9e4b5e07a 100644
--- a/source/blender/python/api2_2x/doc/Constraint.py
+++ b/source/blender/python/api2_2x/doc/Constraint.py
@@ -31,17 +31,21 @@ Or to print all the constraints attached to each bone in a pose::
@var Type: Constant Constraint dict used by L{Constraints.append()} and
for comparison with L{Constraint.type}. Values are
TRACKTO, IKSOLVER, FOLLOWPATH, COPYROT, COPYLOC, COPYSIZE, ACTION,
- LOCKTRACK, STRETCHTO, FLOOR, LIMITLOC, LIMITROT, LIMITSIZE, CLAMPTO,
- PYTHON, CHILDOF, TRANSFORM, NULL
+ LOCKTRACK, STRETCHTO, FLOOR, LIMITLOC, LIMITROT, LIMITSIZE, LIMITDIST,
+ CLAMPTO, PYTHON, CHILDOF, TRANSFORM, NULL
@type Settings: readonly dictionary
@var Settings: Constant dict used for changing constraint settings.
- - Used for all constraints
- - TARGET (Object) (Note: not used by Limit Location (LIMITLOC),
- Limit Rotation (LIMITROT), Limit Scale (LIMITSIZE))
- - BONE (string): name of Bone sub-target (for armature targets) (Note: not
- used by Stretch To (STRETCHTO), Limit Location (LIMITLOC), Limit Rotation
- (LIMITROT), Limit Scale (LIMITSIZE), Follow Path (FOLLOWPATH), Clamp To (CLAMPTO))
+ - Used for all single-target constraints
+ (TRACKTO, FOLLOWPATH, COPYROT, COPYLOC, COPYSIZE, ACTION, LOCKTRACK, STRETCHTO, FLOOR, CLAMPTO, CHILDOF, TRANSFORM, LIMITDIST)
+ - TARGET (Object): target object
+ - BONE (string): name of Bone sub-target (for Armature targets), or name of Vertex Group sub-target
+ (for Geometry targets)
+ - Used for all multiple-target constraints
+ (PYTHON)
+ - TARGET (list of Objects): list of target objects, with one list slot = one target slot
+ - BONE (list of strings): list of names of Bone sub-target (for Armature targets) or name of Vertex Group
+ sub-targets (for Geometry targets)
- Used by some constraints:
- OWNERSPACE (int): for TRACKTO, COPYLOC, COPYROT, COPYSIZE, LIMITLOC, LIMITROT, LIMITSIZE, PYTHON, TRANSFORM
If the owner is an object, values are SPACE_WORLD, SPACE_LOCAL
@@ -123,6 +127,8 @@ Or to print all the constraints attached to each bone in a pose::
- YMAX (float): clamped to [0.0001,1000.0]
- ZMIN (float): clamped to [0.0001,1000.0]
- ZMAX (float): clamped to [0.0001,1000.0]
+ - Used by Limit Distance (LIMITDIST) constraint:
+ - LIMITMODE (int): any one of LIMIT_INSIDE, LIMIT_OUTSIDE, LIMIT_ONSURFACE
- Used by Python Script (PYTHON) constraint:
- SCRIPT (Text): script to use
- PROPERTIES (IDProperties): ID-Properties of constraint
diff --git a/source/blender/python/api2_2x/doc/Curve.py b/source/blender/python/api2_2x/doc/Curve.py
index c3760bc2c1d..ba8d6d21970 100644
--- a/source/blender/python/api2_2x/doc/Curve.py
+++ b/source/blender/python/api2_2x/doc/Curve.py
@@ -694,6 +694,10 @@ class SurfNurb:
@ivar orderV: The order setting for the V direction. Values are clamped
to the range [2:6] and not greater than the V dimension.
@type orderV: int
+ @ivar knotsU: The The knot vector in the U direction
+ @type knotsU: tuple
+ @ivar knotsV: The The knot vector in the V direction
+ @type knotsV: tuple
"""
def __setitem__( n, point ):
diff --git a/source/blender/python/api2_2x/doc/IpoCurve.py b/source/blender/python/api2_2x/doc/IpoCurve.py
index 873888cffb4..54d9136ec1e 100644
--- a/source/blender/python/api2_2x/doc/IpoCurve.py
+++ b/source/blender/python/api2_2x/doc/IpoCurve.py
@@ -11,6 +11,8 @@ This module provides access to the IpoCurve data in Blender. An Ipo is
composed of several IpoCurves, and an IpoCurve are composed of several
BezTriples.
+@warning: Ipo curves store euler rotations as degrees/10.0 so 180.0 would be 18.0
+
Example::
import Blender
ipo = Blender.Ipo.Get('ObIpo') # retrieves an Ipo object
diff --git a/source/blender/python/api2_2x/doc/Mesh.py b/source/blender/python/api2_2x/doc/Mesh.py
index 0690b94712b..8b49ce29d54 100644
--- a/source/blender/python/api2_2x/doc/Mesh.py
+++ b/source/blender/python/api2_2x/doc/Mesh.py
@@ -844,6 +844,44 @@ class Mesh:
@note: Only returns a valid result for mesh data that has no holes.
@note: Bubbles in the mesh work as expect.
"""
+ def getTangents():
+ """
+ Calculates tangents for this mesh, returning a list of tuples,
+ each with 3 or 4 tangent vectors, these are alligned with the meshes faces.
+
+ Example::
+ # Display the tangents as edges over a the active mesh object
+ from Blender import *
+ sce = Scene.GetCurrent()
+ ob = sce.objects.active
+
+ me = ob.getData(mesh=1)
+ ts = me.getTangents()
+ me_disp = Mesh.New()
+
+ verts = []
+ edges = []
+ for i, f in enumerate(me.faces):
+ ft = ts[i]
+ for j, v in enumerate(f):
+ tan = ft[j]
+ print tan
+ co = v.co
+
+ verts.append(co)
+ verts.append(co+tan)
+
+ i = len(verts)
+ edges.append((i-1, i-2))
+
+ me_disp.verts.extend( verts )
+ me_disp.edges.extend( edges )
+
+ sce.objects.new( me_disp )
+
+ @note: The tangents are computed using the active UV layer, if there are no UV layers, orco coords are used.
+ """
+
def transform(matrix, recalc_normals = False, selected_only=False):
"""
diff --git a/source/blender/python/api2_2x/doc/Render.py b/source/blender/python/api2_2x/doc/Render.py
index 42fd5b564fe..97c7c0ecc44 100644
--- a/source/blender/python/api2_2x/doc/Render.py
+++ b/source/blender/python/api2_2x/doc/Render.py
@@ -440,6 +440,7 @@ class RenderData:
@type filename: string
@since: 2.40
@requires: You must have an image currently rendered before calling this method
+ @warning: This wont work in background mode. use renderAnim instead.
"""
def play():
diff --git a/source/blender/python/api2_2x/sceneRender.c b/source/blender/python/api2_2x/sceneRender.c
index 4bf823bc938..d0440e11b52 100644
--- a/source/blender/python/api2_2x/sceneRender.c
+++ b/source/blender/python/api2_2x/sceneRender.c
@@ -534,7 +534,11 @@ PyObject *RenderData_SaveRenderedImage ( BPy_RenderData * self, PyObject *args )
if( !PyArg_ParseTuple( args, "s|i", &name_str, &zbuff ) )
return EXPP_ReturnPyObjError( PyExc_TypeError,
"expected a filename (string) and optional int" );
-
+
+ if (G.background)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "saveRenderedImage does not work in background mode, use renderAnim() instead" );
+
if( strlen(self->renderContext->pic) + strlen(name_str)
>= sizeof(filepath) )
return EXPP_ReturnPyObjError( PyExc_ValueError,