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:
-rw-r--r--source/blender/python/api2_2x/Mesh.c928
-rw-r--r--source/blender/python/api2_2x/Mesh.h7
-rw-r--r--source/blender/python/api2_2x/Object.c4
-rw-r--r--source/blender/python/api2_2x/doc/Mesh.py268
4 files changed, 1137 insertions, 70 deletions
diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c
index 7303d79fd74..3842de0d674 100644
--- a/source/blender/python/api2_2x/Mesh.c
+++ b/source/blender/python/api2_2x/Mesh.c
@@ -41,6 +41,7 @@
#include "DNA_space_types.h"
#include "DNA_curve_types.h"
#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
#include "BDR_editface.h" /* make_tfaces */
#include "BDR_vpaint.h"
@@ -63,8 +64,9 @@
#include "BKE_mball.h"
#include "BKE_utildefines.h"
#include "BKE_depsgraph.h"
-#include "BSE_edit.h" /* for void countall(); */
-#include "BKE_curve.h" /* copy_curve(); */
+#include "BSE_edit.h" /* for countall(); */
+#include "BKE_curve.h" /* for copy_curve(); */
+#include "BKE_modifier.h" /* for modifier_new(), modifier_copyData(); */
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
@@ -102,6 +104,8 @@
#define MESH_TOOL_REMDOUB 4
#define MESH_TOOL_FILL 5
#define MESH_TOOL_RECALCNORM 6
+#define MESH_TOOL_TRIANGLE 7
+#define MESH_TOOL_QUAD 8
/************************************************************************
*
@@ -1736,11 +1740,50 @@ static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args )
return EXPP_incr_ret( Py_None );
}
+static PyObject *MVertSeq_selected( BPy_MVertSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MVert *tmpvert;
+ PyObject *list;
+
+ /* first count selected edges (quicker than appending to PyList?) */
+ count = 0;
+ tmpvert = mesh->mvert;
+ for( i = 0; i < mesh->totvert; ++i, ++tmpvert )
+ if( tmpvert->flag & SELECT )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected edges into list */
+ count = 0;
+ tmpvert = mesh->mvert;
+ for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) {
+ if( tmpvert->flag & SELECT ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+
static struct PyMethodDef BPy_MVertSeq_methods[] = {
{"extend", (PyCFunction)MVertSeq_extend, METH_VARARGS,
"add vertices to mesh"},
{"delete", (PyCFunction)MVertSeq_delete, METH_VARARGS,
- "delete vertices to mesh"},
+ "delete vertices from mesh"},
+ {"selected", (PyCFunction)MVertSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected vertices"},
{NULL, NULL, 0, NULL}
};
@@ -1756,7 +1799,7 @@ static void MVertSeq_dealloc( BPy_MVertSeq * self )
}
/*****************************************************************************/
-/* Python NMVertSeq_Type structure definition: */
+/* Python MVertSeq_Type structure definition: */
/*****************************************************************************/
PyTypeObject MVertSeq_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
@@ -2430,7 +2473,7 @@ static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args )
int totedge = mesh->totedge+good_edges; /* new edge count */
/* allocate new edge list */
- tmpedge = MEM_callocN(totedge*sizeof(MEdge), "NMesh_addEdges");
+ tmpedge = MEM_callocN(totedge*sizeof(MEdge), "Mesh_addEdges");
/* if we're appending, copy the old edge list and delete it */
if( mesh->medge ) {
@@ -2612,11 +2655,52 @@ static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args )
return EXPP_incr_ret( Py_None );
}
+static PyObject *MEdgeSeq_selected( BPy_MEdgeSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MEdge *tmpedge;
+ PyObject *list;
+
+ /* first count selected edges (quicker than appending to PyList?) */
+ count = 0;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i, ++tmpedge )
+ if( (mesh->mvert[tmpedge->v1].flag & SELECT) &&
+ (mesh->mvert[tmpedge->v2].flag & SELECT) )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected edges into list */
+ count = 0;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) {
+ if( (mesh->mvert[tmpedge->v1].flag & SELECT) &&
+ (mesh->mvert[tmpedge->v2].flag & SELECT) ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+
static struct PyMethodDef BPy_MEdgeSeq_methods[] = {
{"extend", (PyCFunction)MEdgeSeq_extend, METH_VARARGS,
"add edges to mesh"},
{"delete", (PyCFunction)MEdgeSeq_delete, METH_VARARGS,
"delete edges from mesh"},
+ {"selected", (PyCFunction)MEdgeSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected edges"},
{NULL, NULL, 0, NULL}
};
@@ -2632,7 +2716,7 @@ static void MEdgeSeq_dealloc( BPy_MEdgeSeq * self )
}
/*****************************************************************************/
-/* Python NMEdgeSeq_Type structure definition: */
+/* Python MEdgeSeq_Type structure definition: */
/*****************************************************************************/
PyTypeObject MEdgeSeq_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
@@ -3058,7 +3142,7 @@ static int MFace_setTransp( BPy_MFace *self, PyObject *value )
}
/*
- * get a face's texture UV values
+ * get a face's texture UV coord values
*/
static PyObject *MFace_getUV( BPy_MFace * self )
@@ -3090,7 +3174,7 @@ static PyObject *MFace_getUV( BPy_MFace * self )
}
/*
- * set a face's texture UV values
+ * set a face's texture UV coord values
*/
static int MFace_setUV( BPy_MFace * self, PyObject * value )
@@ -3122,6 +3206,82 @@ static int MFace_setUV( BPy_MFace * self, PyObject * value )
}
/*
+ * get a face's texture UV coord select state
+ */
+
+static PyObject *MFace_getUVSel( BPy_MFace * self )
+{
+ TFace *face;
+ PyObject *attr;
+ int length, i, mask;
+
+ if( !self->mesh->tface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ face = &self->mesh->tface[self->index];
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ attr = PyTuple_New( length );
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyTuple_New() failed" );
+
+ /* get coord select state, one bit at a time */
+ mask = TF_SEL1;
+ for( i=0; i<length; ++i, mask <<= 1 ) {
+ PyObject *value = PyInt_FromLong( face->flag & mask ? 1 : 0 );
+ if( !value ) {
+ Py_DECREF( attr );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyTuple_SetItem( attr, i, value );
+ }
+
+ return attr;
+}
+
+/*
+ * set a face's texture UV coord select state
+ */
+
+static int MFace_setUVSel( BPy_MFace * self, PyObject * value )
+{
+ TFace *face;
+ int length, i, mask;
+
+ if( !self->mesh->tface )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !PySequence_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of integers" );
+
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ if( length != PyTuple_Size( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "size of vertex and UV lists differ" );
+
+ /* set coord select state, one bit at a time */
+ face = &self->mesh->tface[self->index];
+ mask = TF_SEL1;
+ for( i=0; i<length; ++i, mask <<= 1 ) {
+ PyObject *tmp = PyTuple_GET_ITEM( value, i );
+ if( !PyInt_CheckExact( tmp ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of integers" );
+ }
+ if( PyInt_AsLong( tmp ) )
+ face->flag |= mask;
+ else
+ face->flag &= ~mask;
+ }
+ return 0;
+}
+
+/*
* get a face's vertex colors. note that if mesh->tfaces is defined, then
* it takes precedent over mesh->mcol
*/
@@ -3227,6 +3387,10 @@ static PyGetSetDef BPy_MFace_getseters[] = {
(getter)MFace_getUV, (setter)MFace_setUV,
"face's UV coordinates",
NULL},
+ {"uvSel",
+ (getter)MFace_getUVSel, (setter)MFace_setUVSel,
+ "face's UV coordinates select status",
+ NULL},
{NULL,NULL,NULL,NULL,NULL} /* Sentinel */
};
@@ -3587,14 +3751,6 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args )
if( nverts == 2 ) /* again, ignore 2-vert tuples */
break;
- /* get copies of vertices */
-#if 0
- for( j = 0; j < nverts; ++j ) {
- BPy_MVert *e = (BPy_MVert *)PyTuple_GET_ITEM( tmp, j );
- vert[j] = e->index;
- }
-#endif
-
/*
* go through some contortions to guarantee the third and fourth
* vertices are not index 0
@@ -3727,7 +3883,7 @@ static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args )
int totface = mesh->totface+good_faces; /* new face count */
/* allocate new face list */
- tmpface = MEM_callocN(totface*sizeof(MFace), "NMesh_addFaces");
+ tmpface = MEM_callocN(totface*sizeof(MFace), "Mesh_addFaces");
/* if we're appending, copy the old face list and delete it */
if( mesh->mface ) {
@@ -3982,11 +4138,50 @@ static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args )
return EXPP_incr_ret( Py_None );
}
+static PyObject *MFaceSeq_selected( BPy_MFaceSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MFace *tmpface;
+ PyObject *list;
+
+ /* first count selected faces (quicker than appending to PyList?) */
+ count = 0;
+ tmpface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i, ++tmpface )
+ if( tmpface->flag & ME_FACE_SEL )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected faces into list */
+ count = 0;
+ tmpface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i, ++tmpface ) {
+ if( tmpface->flag & ME_FACE_SEL ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+
static struct PyMethodDef BPy_MFaceSeq_methods[] = {
{"extend", (PyCFunction)MFaceSeq_extend, METH_VARARGS,
"add faces to mesh"},
{"delete", (PyCFunction)MFaceSeq_delete, METH_VARARGS,
- "delete faces to mesh"},
+ "delete faces from mesh"},
+ {"selected", (PyCFunction)MFaceSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected faces"},
{NULL, NULL, 0, NULL}
};
@@ -4002,7 +4197,7 @@ static void MFaceSeq_dealloc( BPy_MFaceSeq * self )
}
/*****************************************************************************/
-/* Python NMFaceSeq_Type structure definition: */
+/* Python MFaceSeq_Type structure definition: */
/*****************************************************************************/
PyTypeObject MFaceSeq_Type = {
PyObject_HEAD_INIT( NULL ) /* required py macro */
@@ -4345,12 +4540,16 @@ static PyObject *Mesh_findEdges( PyObject * self, PyObject *args )
* replace mesh data with mesh data from another object
*/
+
static PyObject *Mesh_getFromObject( BPy_Mesh * self, PyObject * args )
{
Object *ob;
char *name;
ID tmpid;
Mesh *tmpmesh;
+ Curve *tmpcu;
+ DispListMesh *dlm;
+ DerivedMesh *dm;
Object *tmpobj = NULL;
if( !PyArg_ParseTuple( args, "s", &name ) )
@@ -4367,24 +4566,54 @@ static PyObject *Mesh_getFromObject( BPy_Mesh * self, PyObject * args )
case OB_FONT:
case OB_CURVE:
case OB_SURF:
- tmpobj = alloc_libblock( &( G.main->object ), ID_OB, "i_tmp" );
- tmpobj->id.us = 1;
- tmpobj->flag = 0;
- tmpobj->type = ob->type;
+ /* copies object and modifiers (but not the data) */
+ tmpobj= copy_object( ob );
+ tmpcu = (Curve *)tmpobj->data;
+ tmpcu->id.us--;
+
+ /* copies the data */
tmpobj->data = copy_curve( (Curve *) ob->data );
+
+#if 0
+ /* copy_curve() sets disp.first null, so currently not need */
+ {
+ Curve *cu;
+ cu = (Curve *)tmpobj->data;
+ if( cu->disp.first )
+ MEM_freeN( cu->disp.first );
+ cu->disp.first = NULL;
+ }
+#endif
+
+ /* get updated display list, and convert to a mesh */
makeDispListCurveTypes( tmpobj, 0 );
nurbs_to_mesh( tmpobj );
tmpmesh = tmpobj->data;
free_libblock_us( &G.main->object, tmpobj );
break;
case OB_MBALL:
+ /* metaballs don't have modifiers, so just convert to mesh */
ob = find_basis_mball( ob );
tmpmesh = add_mesh();
mball_to_mesh( &ob->disp, tmpmesh );
break;
case OB_MESH:
- tmpmesh = copy_mesh( (Mesh *) ob->data );
- tmpmesh->id.us = 0;
+ /* copies object and modifiers (but not the data) */
+ tmpobj= copy_object( ob );
+ tmpmesh = tmpobj->data;
+ tmpmesh->id.us--;
+
+ /* copies the data */
+ tmpobj->data = copy_mesh( tmpmesh );
+ G.totmesh++;
+ tmpmesh = tmpobj->data;
+
+ /* get the final derived mesh */
+ dm = mesh_create_derived_render( tmpobj );
+ dlm = dm->convertToDispListMesh( dm, 0 );
+ displistmesh_to_mesh( dlm, tmpmesh );
+ dm->release( dm );
+ free_libblock_us( &G.main->object, tmpobj );
break;
default:
return EXPP_ReturnPyObjError( PyExc_AttributeError,
@@ -4470,11 +4699,388 @@ static PyObject *Mesh_transform( BPy_Mesh *self, PyObject *args )
return EXPP_incr_ret( Py_None );
}
+static PyObject *Mesh_addVertGroup( PyObject * self, PyObject * args )
+{
+ char *groupStr;
+ struct Object *object;
+ PyObject *tempStr;
+
+ if( !PyArg_ParseTuple( args, "s", &groupStr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( ( ( BPy_Mesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh not linked to an object" );
+
+ object = ( ( BPy_Mesh * ) self )->object;
+
+ //get clamped name
+ tempStr = PyString_FromStringAndSize( groupStr, 32 );
+ groupStr = PyString_AsString( tempStr );
+
+ add_defgroup_name( object, groupStr );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Mesh_removeVertGroup( PyObject * self, PyObject * args )
+{
+ char *groupStr;
+ struct Object *object;
+ int nIndex;
+ bDeformGroup *pGroup;
+
+ if( !PyArg_ParseTuple( args, "s", &groupStr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( ( ( BPy_Mesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_Mesh * ) self )->object;
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+ nIndex++;
+ object->actdef = (unsigned short)nIndex;
+
+ del_defgroup( object );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+extern void add_vert_defnr( Object * ob, int def_nr, int vertnum, float weight,
+ int assignmode );
+extern void remove_vert_def_nr (Object *ob, int def_nr, int vertnum);
+
+static PyObject *Mesh_assignVertsToGroup( BPy_Mesh * self, PyObject * args )
+{
+ char *groupStr;
+ int nIndex;
+ bDeformGroup *pGroup;
+ PyObject *listObject;
+ int tempInt;
+ int x;
+ int assignmode = WEIGHT_REPLACE;
+ float weight = 1.0;
+ Object *object = self->object;
+ Mesh *mesh = self->mesh;
+
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple ( args, "sO!fi", &groupStr, &PyList_Type,
+ &listObject, &weight, &assignmode) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string, list, float, string arguments" );
+ }
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+
+ if( assignmode != WEIGHT_REPLACE && assignmode != WEIGHT_ADD &&
+ assignmode != WEIGHT_SUBTRACT )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad assignment mode" );
+
+ /* makes a set of dVerts corresponding to the mVerts */
+ if( !mesh->dvert )
+ create_dverts( mesh );
+
+ /* loop list adding verts to group */
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !PyArg_Parse ( PyList_GetItem( listObject, x ), "i", &tempInt ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( tempInt < 0 || tempInt >= mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ add_vert_defnr( object, nIndex, tempInt, weight, assignmode );
+ }
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Mesh_removeVertsFromGroup( BPy_Mesh * self, PyObject * args )
+{
+ /* not passing a list will remove all verts from group */
+
+ char *groupStr;
+ int nIndex;
+ Object *object;
+ Mesh *mesh;
+ bDeformGroup *pGroup;
+ PyObject *listObject = NULL;
+ int tempInt;
+ int i;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple
+ ( args, "s|O!", &groupStr, &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional list argument" );
+
+ if( !mesh->dvert )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "this mesh contains no deform vertices" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "no deform groups assigned to mesh" );
+
+ /* get out of edit mode */
+ G.obedit = 0;
+ exit_editmode( 1 );
+
+ if( !listObject ) /* no list given */
+ for( i = 0; i < mesh->totvert; i++ )
+ remove_vert_def_nr( object, nIndex, i );
+ else /* loop list removing verts to group */
+ for( i = 0; i < PyList_Size( listObject ); i++ ) {
+ if( !PyArg_Parse( PyList_GetItem( listObject, i ), "i", &tempInt ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( tempInt < 0 || tempInt >= mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ remove_vert_def_nr( object, nIndex, tempInt );
+ }
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Mesh_getVertsFromGroup( BPy_Mesh* self, PyObject * args )
+{
+ /*
+ * not passing a list will return all verts from group
+ * passing indecies not part of the group will not return data in pyList
+ * can be used as a index/group check for a vertex
+ */
+
+ char *groupStr;
+ int nIndex;
+ bDeformGroup *pGroup;
+ MDeformVert *dvert;
+ int i, k, count;
+ PyObject *vertexList;
+ Object *object;
+ Mesh *mesh;
+ PyObject *tempVertexList;
+
+ int num = 0;
+ int weightRet = 0;
+ PyObject *listObject = NULL;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple( args, "s|iO!", &groupStr, &weightRet,
+ &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional int and list arguments" );
+
+ if( weightRet < 0 || weightRet > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "return weights flag must be 0 or 1" );
+
+ if( !mesh->dvert )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "this mesh contains no deform vertices" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( !pGroup )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+ /* temporary list */
+ tempVertexList = PyList_New( mesh->totvert );
+ if( !tempVertexList )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "getVertsFromGroup: can't create pylist!" );
+
+ count = 0;
+
+ if( !listObject ) { /* do entire group */
+ dvert = mesh->dvert;
+ for( num = 0; num < mesh->totvert; num++, ++dvert ) {
+ for( i = 0; i < dvert->totweight; i++ ) {
+ if( dvert->dw[i].def_nr == nIndex ) {
+ PyObject *attr;
+ if( weightRet )
+ attr = Py_BuildValue( "(i,f)", num,
+ dvert->dw[i].weight );
+ else
+ attr = PyInt_FromLong ( num );
+ PyList_SetItem( tempVertexList, count, attr );
+ count++;
+ }
+ }
+ }
+ } else { /* do individual vertices */
+ for( i = 0; i < PyList_Size( listObject ); i++ ) {
+ PyObject *attr = NULL;
+
+ if( !PyArg_Parse( PyList_GetItem( listObject, i ), "i", &num ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( num < 0 || num >= mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ dvert = mesh->dvert + num;
+ for( k = 0; k < dvert->totweight; k++ ) {
+ if( dvert->dw[k].def_nr == nIndex ) {
+ if( weightRet )
+ attr = Py_BuildValue( "(i,f)", num,
+ dvert->dw[k].weight );
+ else
+ attr = PyInt_FromLong ( num );
+ PyList_SetItem( tempVertexList, count, attr );
+ count++;
+ }
+ }
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "specified index not in vertex group" );
+ }
+ }
+ /* only return what we need */
+ vertexList = PyList_GetSlice( tempVertexList, 0, count );
+
+ Py_DECREF( tempVertexList );
+
+ return vertexList;
+}
+
+static PyObject *Mesh_renameVertGroup( BPy_Mesh * self, PyObject * args )
+{
+ char *oldGr = NULL;
+ char *newGr = NULL;
+ bDeformGroup *defGroup;
+ Object *object;
+ Mesh *mesh;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple( args, "ss", &oldGr, &newGr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two string arguments" );
+
+ defGroup = get_named_vertexgroup( object, oldGr );
+ if( !defGroup )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't find the vertex group" );
+
+ PyOS_snprintf( defGroup->name, 32, newGr );
+ unique_vertexgroup_name( defGroup, object );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Mesh_getVertGroupNames( BPy_Mesh * self )
+{
+ bDeformGroup *defGroup;
+ PyObject *list;
+ Object *obj = self->object;
+ Mesh *mesh = self->mesh;
+ int count;
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)obj->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ count = 0;
+ for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next )
+ ++count;
+
+ list = PyList_New( count );
+ count = 0;
+ for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next )
+ PyList_SET_ITEM( list, count++,
+ PyString_FromString( defGroup->name ) );
+
+ return list;
+}
+
#ifdef MESH_TOOLS
static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args )
{
- Base *base;
+ Base *base, *basact;
int result;
Object *object = NULL;
PyObject *attr = NULL;
@@ -4500,9 +5106,11 @@ static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args )
return EXPP_ReturnPyObjError( PyExc_ValueError,
"Object specified is not a mesh." );
- /* enter mesh edit mode, apply subdivide, then exit edit mode */
+ /* save active object for later, make mesh's object active */
+ basact = BASACT;
+ BASACT = base;
- G.obedit = object;
+ /* enter mesh edit mode, apply subdivide, then exit edit mode */
enter_editmode( );
switch( type ) {
case MESH_TOOL_TOSPHERE:
@@ -4532,8 +5140,15 @@ static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args )
case MESH_TOOL_RECALCNORM:
righthandfaces( *((int *)args[0]) );
break;
+ case MESH_TOOL_TRIANGLE:
+ convert_to_triface(0);
+ break;
+ case MESH_TOOL_QUAD:
+ join_triangles();
+ break;
}
exit_editmode( 1 );
+ BASACT = basact;
if( attr )
return attr;
@@ -4633,6 +5248,24 @@ static PyObject *Mesh_fill( BPy_Mesh * self )
return Mesh_Tools( self, MESH_TOOL_FILL, NULL );
}
+/*
+ * "Triangles to Quads" function
+ */
+
+static PyObject *Mesh_tri2quad( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_TRIANGLE, NULL );
+}
+
+/*
+ * "Quads to Triangles" function
+ */
+
+static PyObject *Mesh_quad2tri( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_QUAD, NULL );
+}
+
#endif
static struct PyMethodDef BPy_Mesh_methods[] = {
@@ -4648,6 +5281,23 @@ static struct PyMethodDef BPy_Mesh_methods[] = {
"Update display lists after changes to mesh"},
{"transform", (PyCFunction)Mesh_transform, METH_VARARGS,
"Applies a transformation matrix to mesh's vertices"},
+ {"addVertGroup", (PyCFunction)Mesh_addVertGroup, METH_VARARGS,
+ "Assign vertex group name to the object linked to the mesh"},
+ {"removeVertGroup", (PyCFunction)Mesh_removeVertGroup, METH_VARARGS,
+ "Delete vertex group name from the object linked to the mesh"},
+ {"assignVertsToGroup", (PyCFunction)Mesh_assignVertsToGroup, METH_VARARGS,
+ "Assigns vertices to a vertex group"},
+ {"removeVertsFromGroup", (PyCFunction)Mesh_removeVertsFromGroup, METH_VARARGS,
+ "Removes vertices from a vertex group"},
+ {"getVertsFromGroup", (PyCFunction)Mesh_getVertsFromGroup, METH_VARARGS,
+ "Get index and optional weight for vertices in vertex group"},
+ {"renameVertGroup", (PyCFunction)Mesh_renameVertGroup, METH_VARARGS,
+ "Rename an existing vertex group"},
+ {"getVertGroupNames", (PyCFunction)Mesh_getVertGroupNames, METH_NOARGS,
+ "Get names of vertex groups"},
+
+
+
#ifdef MESH_TOOLS
{"smooth", (PyCFunction)Mesh_smooth, METH_NOARGS,
"Flattens angle of selected faces (experimental)"},
@@ -4657,6 +5307,10 @@ static struct PyMethodDef BPy_Mesh_methods[] = {
"Moves selected vertices outward in a spherical shape (experimental)"},
{"fill", (PyCFunction)Mesh_fill, METH_NOARGS,
"Scan fill a closed edge loop (experimental)"},
+ {"quadToTriangle", (PyCFunction)Mesh_tri2quad, METH_NOARGS,
+ "Convert selected quads to triangles (experimental)"},
+ {"triangleToQuad", (PyCFunction)Mesh_quad2tri, METH_NOARGS,
+ "Convert selected triangles to quads (experimental)"},
{"subdivide", (PyCFunction)Mesh_subdivide, METH_VARARGS,
"Subdivide selected edges in a mesh (experimental)"},
{"remDoubles", (PyCFunction)Mesh_removeDoubles, METH_VARARGS,
@@ -4890,6 +5544,7 @@ static PyObject *Mesh_getUsers( BPy_Mesh * self )
static PyObject *Mesh_getFlag( BPy_Mesh * self, void *type )
{
PyObject *attr;
+
switch( (int)type ) {
case MESH_HASFACEUV:
attr = self->mesh->tface ? EXPP_incr_ret_True() :
@@ -4914,6 +5569,69 @@ static PyObject *Mesh_getFlag( BPy_Mesh * self, void *type )
"couldn't get attribute" );
}
+static int Mesh_setFlag( BPy_Mesh * self, PyObject *value, void *type )
+{
+ int param, i;
+ Mesh *mesh = self->mesh;
+
+ if( !PyInt_CheckExact( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument in range [0,1]" );
+
+ param = PyInt_AsLong( value );
+ if( param != 0 && param != 1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument in range [0,1]" );
+
+ /* sticky is independent of faceUV and vertUV */
+ /* faceUV (tface) has priority over vertUV (mcol) */
+
+ switch( (int)type ) {
+ case MESH_HASFACEUV:
+ if( !param ) {
+ if( mesh->tface ) {
+ MEM_freeN( mesh->tface );
+ mesh->tface = NULL;
+ }
+ } else if( !mesh->tface )
+ make_tfaces( mesh );
+ return 0;
+ case MESH_HASMCOL:
+ if( !param ) {
+ if( mesh->mcol ) {
+ MEM_freeN( mesh->mcol );
+ mesh->mcol = NULL;
+ }
+ } else if( !mesh->mcol ) {
+ /* TODO: mesh_create_shadedColors */
+ mesh->mcol = MEM_callocN( sizeof(unsigned int)*mesh->totface*4,
+ "mcol" );
+ for( i = 0; i < mesh->totface*4; i++ )
+ mesh->mcol[i].a = 255;
+ if( mesh->tface )
+ mcol_to_tface( mesh, 1 );
+ }
+ return 0;
+ case MESH_HASVERTUV:
+ if( !param ) {
+ if( mesh->msticky ) {
+ MEM_freeN( mesh->msticky );
+ mesh->msticky = NULL;
+ }
+ } else {
+ if( !mesh->msticky ) {
+ mesh->msticky= MEM_callocN( mesh->totvert*sizeof( MSticky ),
+ "sticky" );
+ /* TODO: rework RE_make_sticky() so we can calculate */
+ }
+ }
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "couldn't get attribute" );
+ }
+}
+
static PyObject *Mesh_getMode( BPy_Mesh * self )
{
PyObject *attr = PyInt_FromLong( self->mesh->flag );
@@ -5028,7 +5746,7 @@ static PyObject *Mesh_repr( BPy_Mesh * self )
}
/*****************************************************************************/
-/* Python NMesh_Type attributes get/set structure: */
+/* Python Mesh_Type attributes get/set structure: */
/*****************************************************************************/
static PyGetSetDef BPy_Mesh_getseters[] = {
{"verts",
@@ -5070,15 +5788,15 @@ static PyGetSetDef BPy_Mesh_getseters[] = {
{"faceUV",
- (getter)Mesh_getFlag, (setter)NULL,
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
"UV-mapped textured faces enabled",
(void *)MESH_HASFACEUV},
{"vertexColors",
- (getter)Mesh_getFlag, (setter)NULL,
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
"Vertex colors for the mesh enabled",
(void *)MESH_HASMCOL},
{"vertexUV",
- (getter)Mesh_getFlag, (setter)NULL,
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
"'Sticky' flag for per vertex UV coordinates enabled",
(void *)MESH_HASVERTUV},
{"activeFace",
@@ -5203,9 +5921,7 @@ static PyObject *M_Mesh_Get( PyObject * self, PyObject * args )
if( !mesh )
return EXPP_incr_ret( Py_None );
- obj = PyObject_NEW( BPy_Mesh, &Mesh_Type );
- obj->mesh = mesh;
- return (PyObject *)obj;
+ return Mesh_CreatePyObject( mesh, NULL );
} else { /* () - return a list with all meshes in the scene */
PyObject *meshlist;
Link *link;
@@ -5220,9 +5936,7 @@ static PyObject *M_Mesh_Get( PyObject * self, PyObject * args )
link = G.main->mesh.first;
index = 0;
while( link ) {
- obj = ( BPy_Mesh * ) PyObject_NEW( BPy_Object,
- &Mesh_Type );
- obj->mesh = ( Mesh * )link;
+ obj = ( BPy_Mesh * ) Mesh_CreatePyObject( ( Mesh * )link, NULL );
PyList_SetItem( meshlist, index, ( PyObject * ) obj );
index++;
link = link->next;
@@ -5238,7 +5952,6 @@ static PyObject *M_Mesh_Get( PyObject * self, PyObject * args )
static PyObject *M_Mesh_New( PyObject * self, PyObject * args )
{
char *name = "Mesh";
- PyObject *ret = NULL;
Mesh *mesh;
BPy_Mesh *obj;
char buf[21];
@@ -5267,6 +5980,7 @@ static PyObject *M_Mesh_New( PyObject * self, PyObject * args )
rename_id( &mesh->id, buf );
obj->mesh = mesh;
+ obj->object = NULL;
return (PyObject *)obj;
}
@@ -5312,11 +6026,127 @@ static struct PyMethodDef M_Mesh_methods[] = {
{NULL, NULL, 0, NULL},
};
+static PyObject *M_Mesh_Modes( void )
+{
+ PyObject *Modes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *d = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert( d, "NOVNORMALSFLIP",
+ PyInt_FromLong( ME_NOPUNOFLIP ) );
+ PyConstant_Insert( d, "TWOSIDED", PyInt_FromLong( ME_TWOSIDED ) );
+ PyConstant_Insert( d, "AUTOSMOOTH",
+ PyInt_FromLong( ME_AUTOSMOOTH ) );
+ }
+
+ return Modes;
+}
+
+#undef EXPP_ADDCONST
+#define EXPP_ADDCONST(dict, name) \
+ PyConstant_Insert(dict, #name, PyInt_FromLong(TF_##name))
+/* Set constants for face drawing mode -- see drawmesh.c */
+
+static PyObject *M_Mesh_FaceModesDict( void )
+{
+ PyObject *FM = PyConstant_New( );
+
+ if( FM ) {
+ BPy_constant *d = ( BPy_constant * ) FM;
+
+ PyConstant_Insert( d, "BILLBOARD",
+ PyInt_FromLong( TF_BILLBOARD2 ) );
+ PyConstant_Insert( d, "ALL", PyInt_FromLong( 0xffff ) );
+ PyConstant_Insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) );
+ PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( TF_DYNAMIC ) );
+ PyConstant_Insert( d, "INVISIBLE", PyInt_FromLong( TF_INVISIBLE ) );
+ PyConstant_Insert( d, "LIGHT", PyInt_FromLong( TF_LIGHT ) );
+ PyConstant_Insert( d, "OBCOL", PyInt_FromLong( TF_OBCOL ) );
+ PyConstant_Insert( d, "SHADOW", PyInt_FromLong( TF_SHADOW ) );
+ PyConstant_Insert( d, "SHAREDVERT", PyInt_FromLong( TF_SHAREDVERT ) );
+ PyConstant_Insert( d, "SHAREDCOL", PyInt_FromLong( TF_SHAREDCOL ) );
+ PyConstant_Insert( d, "TEX", PyInt_FromLong( TF_TEX ) );
+ PyConstant_Insert( d, "TILES", PyInt_FromLong( TF_TILES ) );
+ PyConstant_Insert( d, "TWOSIDE", PyInt_FromLong( TF_TWOSIDE ) );
+ }
+
+ return FM;
+}
+
+static PyObject *M_Mesh_FaceFlagsDict( void )
+{
+ PyObject *FF = PyConstant_New( );
+
+ if( FF ) {
+ BPy_constant *d = ( BPy_constant * ) FF;
+
+ EXPP_ADDCONST( d, SELECT );
+ EXPP_ADDCONST( d, HIDE );
+ EXPP_ADDCONST( d, ACTIVE );
+ }
+
+ return FF;
+}
+
+static PyObject *M_Mesh_FaceTranspModesDict( void )
+{
+ PyObject *FTM = PyConstant_New( );
+
+ if( FTM ) {
+ BPy_constant *d = ( BPy_constant * ) FTM;
+
+ PyConstant_Insert( d, "TF_SOLID", PyInt_FromLong( TF_SOLID ) );
+ PyConstant_Insert( d, "TF_ADD", PyInt_FromLong( TF_ADD ) );
+ PyConstant_Insert( d, "TF_ALPHA", PyInt_FromLong( TF_ALPHA ) );
+ PyConstant_Insert( d, "TF_SUB", PyInt_FromLong( TF_SUB ) );
+ }
+
+ return FTM;
+}
+
+static PyObject *M_Mesh_EdgeFlagsDict( void )
+{
+ PyObject *EF = PyConstant_New( );
+
+ if( EF ) {
+ BPy_constant *d = ( BPy_constant * ) EF;
+
+ PyConstant_Insert(d, "SELECT", PyInt_FromLong( SELECT ) );
+ PyConstant_Insert(d, "EDGEDRAW", PyInt_FromLong( ME_EDGEDRAW ) );
+ PyConstant_Insert(d, "EDGERENDER", PyInt_FromLong( ME_EDGERENDER ) );
+ PyConstant_Insert(d, "SEAM", PyInt_FromLong( ME_SEAM ) );
+ PyConstant_Insert(d, "FGON", PyInt_FromLong( ME_FGON ) );
+ }
+
+ return EF;
+}
+
+static PyObject *M_Mesh_VertAssignDict( void )
+{
+ PyObject *Vert = PyConstant_New( );
+ if( Vert ) {
+ BPy_constant *d = ( BPy_constant * ) Vert;
+ PyConstant_Insert(d, "ADD", PyInt_FromLong(WEIGHT_ADD));
+ PyConstant_Insert(d, "REPLACE", PyInt_FromLong(WEIGHT_REPLACE));
+ PyConstant_Insert(d, "SUBTRACT", PyInt_FromLong(WEIGHT_SUBTRACT));
+ }
+ return Vert;
+}
+
static char M_Mesh_doc[] = "The Blender.Mesh submodule";
PyObject *Mesh_Init( void )
{
PyObject *submodule;
+ PyObject *dict;
+
+ PyObject *Modes = M_Mesh_Modes( );
+ PyObject *FaceFlags = M_Mesh_FaceFlagsDict( );
+ PyObject *FaceModes = M_Mesh_FaceModesDict( );
+ PyObject *FaceTranspModes = M_Mesh_FaceTranspModesDict( );
+ PyObject *EdgeFlags = M_Mesh_EdgeFlagsDict( );
+ PyObject *AssignModes = M_Mesh_VertAssignDict( );
if( PyType_Ready( &MCol_Type ) < 0 )
return NULL;
@@ -5340,12 +6170,26 @@ PyObject *Mesh_Init( void )
submodule =
Py_InitModule3( "Blender.Mesh", M_Mesh_methods, M_Mesh_doc );
+ if( Modes )
+ PyModule_AddObject( submodule, "Modes", Modes );
+ if( FaceFlags )
+ PyModule_AddObject( submodule, "FaceFlags", FaceFlags );
+ if( FaceModes )
+ PyModule_AddObject( submodule, "FaceModes", FaceModes );
+ if( FaceTranspModes )
+ PyModule_AddObject( submodule, "FaceTranspModes",
+ FaceTranspModes );
+ if( EdgeFlags )
+ PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags );
+ if( AssignModes )
+ PyModule_AddObject( submodule, "AssignModes", dict );
+
return submodule;
}
/* These are needed by Object.c */
-PyObject *Mesh_CreatePyObject( Mesh * me )
+PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj )
{
BPy_Mesh *nmesh = PyObject_NEW( BPy_Mesh, &Mesh_Type );
@@ -5354,6 +6198,7 @@ PyObject *Mesh_CreatePyObject( Mesh * me )
"couldn't create BPy_Mesh object" );
nmesh->mesh = me;
+ nmesh->object = obj;
return ( PyObject * ) nmesh;
}
@@ -5363,11 +6208,12 @@ int Mesh_CheckPyObject( PyObject * pyobj )
return ( pyobj->ob_type == &Mesh_Type );
}
-Mesh *Mesh_FromPyObject( PyObject * pyobj )
+Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj )
{
BPy_Mesh *blen_obj;
blen_obj = ( BPy_Mesh * ) pyobj;
+ blen_obj->object = obj;
return blen_obj->mesh;
}
diff --git a/source/blender/python/api2_2x/Mesh.h b/source/blender/python/api2_2x/Mesh.h
index 31810a57d44..ada47b0927c 100644
--- a/source/blender/python/api2_2x/Mesh.h
+++ b/source/blender/python/api2_2x/Mesh.h
@@ -113,14 +113,15 @@ typedef struct {
typedef struct {
PyObject_HEAD /* required python macro */
- Mesh * mesh;
+ Mesh *mesh;
+ Object *object;
} BPy_Mesh;
/* PROTOS */
PyObject *Mesh_Init( void );
-PyObject *Mesh_CreatePyObject( Mesh * me );
+PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj );
int Mesh_CheckPyObject( PyObject * pyobj );
-Mesh *Mesh_FromPyObject( PyObject * pyobj );
+Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj );
#endif /* EXPP_MESH_H */
diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c
index 5b8fc3024cd..87550e858a9 100644
--- a/source/blender/python/api2_2x/Object.c
+++ b/source/blender/python/api2_2x/Object.c
@@ -1046,7 +1046,7 @@ static PyObject *Object_getData( BPy_Object *self, PyObject *args, PyObject *kwd
if( !mesh ) /* get as NMesh (default) */
data_object = NMesh_CreatePyObject( object->data, object );
else /* else get as Mesh */
- data_object = Mesh_CreatePyObject( object->data );
+ data_object = Mesh_CreatePyObject( object->data, object );
break;
case ID_OB:
data_object = Object_CreatePyObject( object->data );
@@ -1489,7 +1489,7 @@ static PyObject *Object_link( BPy_Object * self, PyObject * args )
else if( NMesh_CheckPyObject( py_data ) )
data = ( void * ) NMesh_FromPyObject( py_data, self->object );
else if( Mesh_CheckPyObject( py_data ) )
- data = ( void * ) Mesh_FromPyObject( py_data );
+ data = ( void * ) Mesh_FromPyObject( py_data, self->object );
else if( Lattice_CheckPyObject( py_data ) )
data = ( void * ) Lattice_FromPyObject( py_data );
else if( Metaball_CheckPyObject( py_data ) )
diff --git a/source/blender/python/api2_2x/doc/Mesh.py b/source/blender/python/api2_2x/doc/Mesh.py
index 41b10179e11..a20cb2ae993 100644
--- a/source/blender/python/api2_2x/doc/Mesh.py
+++ b/source/blender/python/api2_2x/doc/Mesh.py
@@ -12,13 +12,16 @@ B{New}:
- delete methods for L{verts<MVertSeq.delete>}, L{edges<MEdgeSeq.delete>}
and L{faces<MFaceSeq.delete>}
- new experimental mesh tools:
- L{fill()<Mesh.Mesh.fill>},
- L{flipNormals()<Mesh.Mesh.flipNormals>},
- L{recalcNormals()<Mesh.Mesh.recalcNormals>},
- L{remDoubles()<Mesh.Mesh.remDoubles>},
- L{smooth()<Mesh.Mesh.smooth>},
- L{subdivide()<Mesh.Mesh.subdivide>} and
- L{toSphere()<Mesh.Mesh.toSphere>}
+ L{mesh.fill()<Mesh.Mesh.fill>},
+ L{mesh.flipNormals()<Mesh.Mesh.flipNormals>},
+ L{mesh.recalcNormals()<Mesh.Mesh.recalcNormals>},
+ L{mesh.remDoubles()<Mesh.Mesh.remDoubles>},
+ L{mesh.smooth()<Mesh.Mesh.smooth>},
+ L{mesh.subdivide()<Mesh.Mesh.subdivide>},
+ L{mesh.toSphere()<Mesh.Mesh.toSphere>},
+ L{mesh.quadToTriangle()<Mesh.Mesh.quadToTriangle>},
+ L{mesh.triangleToQuad()<Mesh.Mesh.triangleToQuad>}
+ - methods for accessing and modifying vertex groups
- and if you're never used Mesh before, everything!
Mesh Data
@@ -53,8 +56,59 @@ Example::
v.co[2] *= 2.5
if editmode: Window.EditMode(1) # optional, just being nice
+
+@type Modes: readonly dictionary
+@type FaceFlags: readonly dictionary
+@type FaceModes: readonly dictionary
+@type FaceTranspModes: readonly dictionary
+@var Modes: The available mesh modes.
+ - NOVNORMALSFLIP - no flipping of vertex normals during render.
+ - TWOSIDED - double sided mesh.
+ - AUTOSMOOTH - turn auto smoothing of faces "on".
+ - SUBSURF - turn Catmull-Clark subdivision of surfaces "on".
+ - OPTIMAL - optimal drawing of edges when "SubSurf" is "on".
+@var FaceFlags: The available *texture face* (uv face select mode) selection
+ flags. Note: these refer to TexFace faces, available if nmesh.hasFaceUV()
+ returns true.
+ - SELECT - selected.
+ - HIDE - hidden.
+ - ACTIVE - the active face.
+@var FaceModes: The available *texture face* modes. Note: these are only
+ meaningful if nmesh.hasFaceUV() returns true, since in Blender this info is
+ stored at the TexFace (TexFace button in Edit Mesh buttons) structure.
+ - ALL - set all modes at once.
+ - BILLBOARD - always orient after camera.
+ - HALO - halo face, always point to camera.
+ - DYNAMIC - respond to collisions.
+ - INVISIBLE - invisible face.
+ - LIGHT - dynamic lighting.
+ - OBCOL - use object color instead of vertex colors.
+ - SHADOW - shadow type.
+ - SHAREDVERT - apparently unused in Blender.
+ - SHAREDCOL - shared vertex colors (per vertex).
+ - TEX - has texture image.
+ - TILES - uses tiled image.
+ - TWOSIDE - two-sided face.
+@var FaceTranspModes: The available face transparency modes. Note: these are
+ enumerated values (enums), they can't be combined (and'ed, or'ed, etc) like a bit vector.
+ - SOLID - draw solid.
+ - ADD - add to background (halo).
+ - ALPHA - draw with transparency.
+ - SUB - subtract from background.
+@var EdgeFlags: The available edge flags.
+ - SELECT - selected.
+ - EDGEDRAW - edge is drawn out of edition mode.
+ - SEAM - edge is a seam for LSCM UV unwrapping
+ - FGON - edge is part of a F-Gon.
+@type AssignModes: readonly dictionary.
+@var AssignModes: blah blah fix me.
+ - REPLACE - selected.
+ - ADD - edge is drawn out of edition mode.
+ - SUBTRACT - edge is a seam for LSCM UV unwrapping
"""
+AssignModes = {'REPLACE':1}
+
def Get(name=None):
"""
Get the mesh data object called I{name} from Blender.
@@ -220,6 +274,13 @@ class MVertSeq:
the above.
"""
+ def selected():
+ """
+ Get selected vertices.
+ @return: a list of the indices for all vertices selected in edit mode.
+ @rtype: list of ints
+ """
+
class MEdge:
"""
The MEdge object
@@ -231,7 +292,7 @@ class MEdge:
@type v2: MVert
@ivar crease: The crease value of the edge. It is in the range [0,255].
@type crease: int
- @ivar flag: The bitfield describing edge properties. See L{NMesh.EdgeFlags}.
+ @ivar flag: The bitfield describing edge properties. See L{EdgeFlags}.
@type flag: int
@ivar index: The edge's index within the mesh. Read-only.
@type index: int
@@ -289,6 +350,14 @@ class MEdgeSeq:
the above.
"""
+ def selected():
+ """
+ Get selected edges.
+ Selected edges are those for which both vertices are selected.
+ @return: a list of the indices for all edges selected in edit mode.
+ @rtype: list of ints
+ """
+
class MFace:
"""
The MFace object
@@ -316,7 +385,7 @@ class MFace:
## Example for UV textured faces selection:
selected_faces = []
- SEL = NMesh.FaceFlags['SELECT']
+ SEL = Mesh.FaceFlags['SELECT']
# get selected faces:
for f in faces:
if f.flag & SEL:
@@ -361,7 +430,7 @@ class MFace:
Will throw an exception if the mesh does not have UV faces; use
L{Mesh.faceUV} to test.
@type image: Image
- @ivar mode: The texture mode bitfield (see L{NMesh.FaceModes}).
+ @ivar mode: The texture mode bitfield (see L{FaceModes}).
Will throw an exception if the mesh does not have UV faces; use
L{Mesh.faceUV} to test.
@type mode: int
@@ -370,7 +439,7 @@ class MFace:
@ivar flag: The face's B{texture mode} flags; indicates the selection,
active , and visibility states of a textured face (see
- L{NMesh.FaceFlags} for values).
+ L{FaceFlags} for values).
This is not the same as the selection or visibility states of
the faces in edit mode (see L{sel} and L{hide}).
To set the active face, use
@@ -379,7 +448,7 @@ class MFace:
L{Mesh.faceUV} to test.
@ivar transp: Transparency mode. It is one of the values in
- L{NMesh.FaceTranspModes}).
+ L{FaceTranspModes}).
Will throw an exception if the mesh does not have UV faces; use
L{Mesh.faceUV} to test.
@type transp: int
@@ -388,6 +457,12 @@ class MFace:
Will throw an exception if the mesh does not have UV faces; use
L{Mesh.faceUV} to test.
@type uv: list of vectors
+ @ivar uvSel: The face's UV coordinates seletion state; a 1 indicates the
+ vertex is selected. Each vertex has its own UV coordinate select state
+ (this is not the same as the vertex's edit mode selection state).
+ Will throw an exception if the mesh does not have UV faces; use
+ L{Mesh.faceUV} to test.
+ @type uvSel: list of ints
@ivar no: The face's normal vector (x, y, z). Read-only.
@type no: vector
@note: there are regular faces and textured faces in Blender, both currently
@@ -459,6 +534,14 @@ class MFaceSeq:
- a integer, specifying an index into the mesh's face list
"""
+ def selected():
+ """
+ Get selected faces.
+ mode.
+ @return: a list of the indices for all faces selected in edit mode.
+ @rtype: list of ints
+ """
+
class Mesh:
"""
The Mesh Data object
@@ -486,7 +569,7 @@ class Mesh:
@ivar maxSmoothAngle: Same as L{degr}. This attribute is only for
compatibility with NMesh scripts and will probably be deprecated in
the future.
- @ivar mode: The mesh's mode bitfield. See L{NMesh.Modes}.
+ @ivar mode: The mesh's mode bitfield. See L{Modes}.
@type mode: int
@ivar name: The Mesh name. It's common to use this field to store extra
@@ -497,11 +580,17 @@ class Mesh:
@ivar users: The number of Objects using (linked to) this mesh.
@type users: int
- @ivar faceUV: The mesh contains UV-mapped textured faces. Read-only.
+ @ivar faceUV: The mesh contains UV-mapped textured faces. Enabling faceUV
+ does not initialize the face colors like the Blender UI does; this must
+ be done in the script. B{Note}: if faceUV is set, L{vertexColors} cannot
+ be set. Furthermore, if vertexColors is already set when faceUV is set,
+ vertexColors is cleared. This is because the vertex color information
+ is stored with UV faces, so enabling faceUV implies enabling vertexColors.
@type faceUV: bool
- @ivar vertexColors: The mesh contains vertex colors. Read-only.
+ @ivar vertexColors: The mesh contains vertex colors. See L{faceUV} for the
+ use of vertex colors when UV-mapped texture faces are enabled.
@type vertexColors: bool
- @ivar vertexUV: The mesh contains "sticky" per-vertex UV coordinates. Read-only.
+ @ivar vertexUV: The mesh contains "sticky" per-vertex UV coordinates.
@type vertexUV: bool
@ivar activeFace: Index of the mesh's active face in UV Face Select and
Paint modes. Only one face can be active at a time. Note that this is
@@ -514,8 +603,9 @@ class Mesh:
def getFromObject(name):
"""
Replace the mesh's existing data with the raw mesh data from a Blender
- Object. This method support all the geometry based objects (mesh, text,
- curve, surface, and meta).
+ Object. This method supports all the geometry based objects (mesh, text,
+ curve, surface, and meta). If the object has modifiers, they will be
+ applied before to the object before extracting the vertex data.
@note: The mesh coordinates are in i{local space}, not the world space of
its object. For world space vertex coordinates, each vertex location must
be multiplied by the object's 4x4 transform matrix (see L{transform}).
@@ -598,6 +688,124 @@ class Mesh:
returned. If a sequence of edges is passed, a list is returned.
"""
+ def addVertGroup(group):
+ """
+ Add a named and empty vertex (deform) group to the object this nmesh is
+ linked to. The mesh must first be linked to an object (with object.link()
+ or object.getData() ) so the method knows which object to update.
+ This is because vertex groups in Blender are stored in I{the object} --
+ not in the mesh, which may be linked to more than one object.
+ @type group: string
+ @param group: the name for the new group.
+ """
+
+ def removeVertGroup(group):
+ """
+ Remove a named vertex (deform) group from the object linked to this mesh.
+ All vertices assigned to the group will be removed (just from the group,
+ not deleted from the mesh), if any. If this mesh was newly created, it
+ must first be linked to an object (read the comment in L{addVertGroup} for
+ more info).
+ @type group: string
+ @param group: the name of a vertex group.
+ """
+
+
+ def assignVertsToGroup(group, vertList, weight, assignmode = AssignModes['REPLACE']):
+ """
+ Adds an array (a Python list) of vertex points to a named vertex group
+ associated with a mesh. The vertex list is a list of vertex indices from
+ the mesh. You should assign vertex points to groups only when the mesh has
+ all its vertex points added to it and is already linked to an object.
+
+ I{B{Example:}}
+ The example here adds a new set of vertex indices to a sphere primitive::
+ import Blender
+ sphere = Blender.Object.Get('Sphere')
+ replace = Blender.Mesh.AssignModes.REPLACE
+ mesh = sphere.getData(mesh=True)
+ mesh.addVertGroup('firstGroup')
+ vertList = []
+ for x in range(300):
+ if x % 3 == 0:
+ vertList.append(x)
+ mesh.assignVertsToGroup('firstGroup', vertList, 0.5, replace)
+
+ @type group: string
+ @param group: the name of the group.
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices.
+ @type weight: float
+ @param weight: the deform weight for (which means: the amount of influence
+ the group has over) the given vertices. It should be in the range
+ [0.0, 1.0]. If weight <= 0, the given vertices are removed from the
+ group. If weight > 1, it is clamped.
+ @type assignmode: module constant
+ @param assignmode: Three choices:
+ - ADD: if the vertex in the list is not assigned to the group
+ already, this creates a new association between this vertex and the
+ group with the weight specified, otherwise the weight given is added to
+ the current weight of an existing association between the vertex and
+ group.
+ - SUBTRACT: will attempt to subtract the weight passed from a vertex
+ already associated with a group, else it does nothing.\n
+ - REPLACE: attempts to replace a weight with the new weight value
+ for an already associated vertex/group, else it does nothing.
+ """
+
+ def removeVertsFromGroup(group, vertList = None):
+ """
+ Remove a list of vertices from the given group. If this nmesh was newly
+ created, it must first be linked to an object (check L{addVertGroup}).
+ @type group: string
+ @param group: the name of a vertex group
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices to be removed from I{group}.
+ If None, all vertices are removed -- the group is emptied.
+ """
+
+ def getVertsFromGroup(group, weightsFlag = 0, vertList = None):
+ """
+ Return a list of vertex indices associated with the passed group. This
+ method can be used to test whether a vertex index is part of a group and
+ if so, what its weight is.
+
+ I{B{Example:}}
+ Append this to the example from L{assignVertsToGroup}::
+ # ...
+ print "Vertex indices from group %s :" % groupName
+ print mesh.getVertsFromGroup('firstGroup')
+ print "Again, with weights:"
+ print mesh.getVertsFromGroup('firstGroup',1)
+ print "Again, with weights and restricted to the given indices:"
+ print mesh.getVertsFromGroup('firstGroup',1,[1,2,3,4,5,6])
+
+ @type group: string
+ @param group: the group name.
+ @type weightsFlag: bool
+ @param weightsFlag: if 1, the weight is returned along with the index.
+ @type vertList: list of ints
+ @param vertList: if given, only those vertex points that are both in the
+ list and group passed in are returned.
+ """
+
+ def renameVertGroup(groupName, newName):
+ """
+ Renames a vertex group.
+ @type groupName: string
+ @param groupName: the vertex group name to be renamed.
+ @type newName: string
+ @param newName: the name to replace the old name.
+ """
+
+ def getVertGroupNames():
+ """
+ Return a list of all vertex group names.
+ @rtype: list of strings
+ @return: returns a list of strings representing all vertex group
+ associated with the mesh's object
+ """
+
def smooth():
"""
Flattens angle of selected faces. Experimental mesh tool.
@@ -617,6 +825,24 @@ class Mesh:
An exception is thrown if called while in EditMode.
"""
+ def fill():
+ """
+ Scan fill a closed selected edge loop. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def triangleToQuad():
+ """
+ Convert selected triangles to quads. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def quadToTriangle():
+ """
+ Convert selected quads to triangles. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
def subdivide(beauty=0):
"""
Subdivide selected edges in a mesh. Experimental mesh tool.
@@ -637,12 +863,6 @@ class Mesh:
@return: the number of vertices deleted
"""
- def fill():
- """
- Scan fill a closed selected edge loop. Experimental mesh tool.
- An exception is thrown if called while in EditMode.
- """
-
def recalcNormals(direction=0):
"""
Recalculates inside or outside normals for selected faces. Experimental