diff options
author | Jean-Luc Peurière <jlp@nerim.net> | 2008-03-21 20:00:40 +0300 |
---|---|---|
committer | Jean-Luc Peurière <jlp@nerim.net> | 2008-03-21 20:00:40 +0300 |
commit | 32b5138e6459df5298ca50865dafab4d22a4aeed (patch) | |
tree | 8ba947a61d91fe051e9c3a864f5e0ca61968bca1 /source/blender/python | |
parent | 473ba6ac718bc32b4fc6c6aee4d03673cf62936c (diff) | |
parent | df1ba7da75f9b82f81693d5e0adfec29b2f4a424 (diff) |
update to trunk r14199ndof
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/BPY_extern.h | 4 | ||||
-rw-r--r-- | source/blender/python/BPY_interface.c | 53 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Blender.c | 11 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Constraint.c | 193 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Draw.c | 7 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Library.c | 20 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Mesh.c | 178 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Node.c | 658 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Node.h | 21 | ||||
-rw-r--r-- | source/blender/python/api2_2x/SurfNurb.c | 63 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Window.c | 20 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Constraint.py | 22 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Curve.py | 4 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/IpoCurve.py | 2 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Mesh.py | 38 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Render.py | 1 | ||||
-rw-r--r-- | source/blender/python/api2_2x/sceneRender.c | 6 |
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, |